1/*
2 * Copyright 2014, Pawe�� Dziepak, pdziepak@quarnos.org.
3 * Copyright 2008-2016, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Copyright 2002-2010, Axel D��rfler, axeld@pinc-software.de.
5 * Distributed under the terms of the MIT License.
6 *
7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
8 * Distributed under the terms of the NewOS License.
9 */
10
11
12/*!	Team functions */
13
14
15#include <team.h>
16
17#include <errno.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/wait.h>
22
23#include <OS.h>
24
25#include <AutoDeleter.h>
26#include <FindDirectory.h>
27
28#include <extended_system_info_defs.h>
29
30#include <commpage.h>
31#include <boot_device.h>
32#include <elf.h>
33#include <file_cache.h>
34#include <find_directory_private.h>
35#include <fs/KPath.h>
36#include <heap.h>
37#include <int.h>
38#include <kernel.h>
39#include <kimage.h>
40#include <kscheduler.h>
41#include <ksignal.h>
42#include <Notifications.h>
43#include <port.h>
44#include <posix/realtime_sem.h>
45#include <posix/xsi_semaphore.h>
46#include <safemode.h>
47#include <sem.h>
48#include <syscall_process_info.h>
49#include <syscall_load_image.h>
50#include <syscall_restart.h>
51#include <syscalls.h>
52#include <tls.h>
53#include <tracing.h>
54#include <user_runtime.h>
55#include <user_thread.h>
56#include <usergroup.h>
57#include <vfs.h>
58#include <vm/vm.h>
59#include <vm/VMAddressSpace.h>
60#include <util/AutoLock.h>
61
62#include "TeamThreadTables.h"
63
64
65//#define TRACE_TEAM
66#ifdef TRACE_TEAM
67#	define TRACE(x) dprintf x
68#else
69#	define TRACE(x) ;
70#endif
71
72
73struct team_key {
74	team_id id;
75};
76
77struct team_arg {
78	char	*path;
79	char	**flat_args;
80	size_t	flat_args_size;
81	uint32	arg_count;
82	uint32	env_count;
83	mode_t	umask;
84	uint32	flags;
85	port_id	error_port;
86	uint32	error_token;
87};
88
89#define TEAM_ARGS_FLAG_NO_ASLR	0x01
90
91
92namespace {
93
94
95class TeamNotificationService : public DefaultNotificationService {
96public:
97							TeamNotificationService();
98
99			void			Notify(uint32 eventCode, Team* team);
100};
101
102
103// #pragma mark - TeamTable
104
105
106typedef BKernel::TeamThreadTable<Team> TeamTable;
107
108
109// #pragma mark - ProcessGroupHashDefinition
110
111
112struct ProcessGroupHashDefinition {
113	typedef pid_t			KeyType;
114	typedef	ProcessGroup	ValueType;
115
116	size_t HashKey(pid_t key) const
117	{
118		return key;
119	}
120
121	size_t Hash(ProcessGroup* value) const
122	{
123		return HashKey(value->id);
124	}
125
126	bool Compare(pid_t key, ProcessGroup* value) const
127	{
128		return value->id == key;
129	}
130
131	ProcessGroup*& GetLink(ProcessGroup* value) const
132	{
133		return value->next;
134	}
135};
136
137typedef BOpenHashTable<ProcessGroupHashDefinition> ProcessGroupHashTable;
138
139
140}	// unnamed namespace
141
142
143// #pragma mark -
144
145
146// the team_id -> Team hash table and the lock protecting it
147static TeamTable sTeamHash;
148static rw_spinlock sTeamHashLock = B_RW_SPINLOCK_INITIALIZER;
149
150// the pid_t -> ProcessGroup hash table and the lock protecting it
151static ProcessGroupHashTable sGroupHash;
152static spinlock sGroupHashLock = B_SPINLOCK_INITIALIZER;
153
154static Team* sKernelTeam = NULL;
155static bool sDisableUserAddOns = false;
156
157// A list of process groups of children of dying session leaders that need to
158// be signalled, if they have become orphaned and contain stopped processes.
159static ProcessGroupList sOrphanedCheckProcessGroups;
160static mutex sOrphanedCheckLock
161	= MUTEX_INITIALIZER("orphaned process group check");
162
163// some arbitrarily chosen limits -- should probably depend on the available
164// memory (the limit is not yet enforced)
165static int32 sMaxTeams = 2048;
166static int32 sUsedTeams = 1;
167
168static TeamNotificationService sNotificationService;
169
170static const size_t kTeamUserDataReservedSize	= 128 * B_PAGE_SIZE;
171static const size_t kTeamUserDataInitialSize	= 4 * B_PAGE_SIZE;
172
173
174// #pragma mark - TeamListIterator
175
176
177TeamListIterator::TeamListIterator()
178{
179	// queue the entry
180	InterruptsWriteSpinLocker locker(sTeamHashLock);
181	sTeamHash.InsertIteratorEntry(&fEntry);
182}
183
184
185TeamListIterator::~TeamListIterator()
186{
187	// remove the entry
188	InterruptsWriteSpinLocker locker(sTeamHashLock);
189	sTeamHash.RemoveIteratorEntry(&fEntry);
190}
191
192
193Team*
194TeamListIterator::Next()
195{
196	// get the next team -- if there is one, get reference for it
197	InterruptsWriteSpinLocker locker(sTeamHashLock);
198	Team* team = sTeamHash.NextElement(&fEntry);
199	if (team != NULL)
200		team->AcquireReference();
201
202	return team;
203}
204
205
206// #pragma mark - Tracing
207
208
209#if TEAM_TRACING
210namespace TeamTracing {
211
212class TeamForked : public AbstractTraceEntry {
213public:
214	TeamForked(thread_id forkedThread)
215		:
216		fForkedThread(forkedThread)
217	{
218		Initialized();
219	}
220
221	virtual void AddDump(TraceOutput& out)
222	{
223		out.Print("team forked, new thread %" B_PRId32, fForkedThread);
224	}
225
226private:
227	thread_id			fForkedThread;
228};
229
230
231class ExecTeam : public AbstractTraceEntry {
232public:
233	ExecTeam(const char* path, int32 argCount, const char* const* args,
234			int32 envCount, const char* const* env)
235		:
236		fArgCount(argCount),
237		fArgs(NULL)
238	{
239		fPath = alloc_tracing_buffer_strcpy(path, B_PATH_NAME_LENGTH,
240			false);
241
242		// determine the buffer size we need for the args
243		size_t argBufferSize = 0;
244		for (int32 i = 0; i < argCount; i++)
245			argBufferSize += strlen(args[i]) + 1;
246
247		// allocate a buffer
248		fArgs = (char*)alloc_tracing_buffer(argBufferSize);
249		if (fArgs) {
250			char* buffer = fArgs;
251			for (int32 i = 0; i < argCount; i++) {
252				size_t argSize = strlen(args[i]) + 1;
253				memcpy(buffer, args[i], argSize);
254				buffer += argSize;
255			}
256		}
257
258		// ignore env for the time being
259		(void)envCount;
260		(void)env;
261
262		Initialized();
263	}
264
265	virtual void AddDump(TraceOutput& out)
266	{
267		out.Print("team exec, \"%p\", args:", fPath);
268
269		if (fArgs != NULL) {
270			char* args = fArgs;
271			for (int32 i = 0; !out.IsFull() && i < fArgCount; i++) {
272				out.Print(" \"%s\"", args);
273				args += strlen(args) + 1;
274			}
275		} else
276			out.Print(" <too long>");
277	}
278
279private:
280	char*	fPath;
281	int32	fArgCount;
282	char*	fArgs;
283};
284
285
286static const char*
287job_control_state_name(job_control_state state)
288{
289	switch (state) {
290		case JOB_CONTROL_STATE_NONE:
291			return "none";
292		case JOB_CONTROL_STATE_STOPPED:
293			return "stopped";
294		case JOB_CONTROL_STATE_CONTINUED:
295			return "continued";
296		case JOB_CONTROL_STATE_DEAD:
297			return "dead";
298		default:
299			return "invalid";
300	}
301}
302
303
304class SetJobControlState : public AbstractTraceEntry {
305public:
306	SetJobControlState(team_id team, job_control_state newState, Signal* signal)
307		:
308		fTeam(team),
309		fNewState(newState),
310		fSignal(signal != NULL ? signal->Number() : 0)
311	{
312		Initialized();
313	}
314
315	virtual void AddDump(TraceOutput& out)
316	{
317		out.Print("team set job control state, team %" B_PRId32 ", "
318			"new state: %s, signal: %d",
319			fTeam, job_control_state_name(fNewState), fSignal);
320	}
321
322private:
323	team_id				fTeam;
324	job_control_state	fNewState;
325	int					fSignal;
326};
327
328
329class WaitForChild : public AbstractTraceEntry {
330public:
331	WaitForChild(pid_t child, uint32 flags)
332		:
333		fChild(child),
334		fFlags(flags)
335	{
336		Initialized();
337	}
338
339	virtual void AddDump(TraceOutput& out)
340	{
341		out.Print("team wait for child, child: %" B_PRId32 ", "
342			"flags: %#" B_PRIx32, fChild, fFlags);
343	}
344
345private:
346	pid_t	fChild;
347	uint32	fFlags;
348};
349
350
351class WaitForChildDone : public AbstractTraceEntry {
352public:
353	WaitForChildDone(const job_control_entry& entry)
354		:
355		fState(entry.state),
356		fTeam(entry.thread),
357		fStatus(entry.status),
358		fReason(entry.reason),
359		fSignal(entry.signal)
360	{
361		Initialized();
362	}
363
364	WaitForChildDone(status_t error)
365		:
366		fTeam(error)
367	{
368		Initialized();
369	}
370
371	virtual void AddDump(TraceOutput& out)
372	{
373		if (fTeam >= 0) {
374			out.Print("team wait for child done, team: %" B_PRId32 ", "
375				"state: %s, status: %#" B_PRIx32 ", reason: %#x, signal: %d\n",
376				fTeam, job_control_state_name(fState), fStatus, fReason,
377				fSignal);
378		} else {
379			out.Print("team wait for child failed, error: "
380				"%#" B_PRIx32 ", ", fTeam);
381		}
382	}
383
384private:
385	job_control_state	fState;
386	team_id				fTeam;
387	status_t			fStatus;
388	uint16				fReason;
389	uint16				fSignal;
390};
391
392}	// namespace TeamTracing
393
394#	define T(x) new(std::nothrow) TeamTracing::x;
395#else
396#	define T(x) ;
397#endif
398
399
400//	#pragma mark - TeamNotificationService
401
402
403TeamNotificationService::TeamNotificationService()
404	: DefaultNotificationService("teams")
405{
406}
407
408
409void
410TeamNotificationService::Notify(uint32 eventCode, Team* team)
411{
412	char eventBuffer[128];
413	KMessage event;
414	event.SetTo(eventBuffer, sizeof(eventBuffer), TEAM_MONITOR);
415	event.AddInt32("event", eventCode);
416	event.AddInt32("team", team->id);
417	event.AddPointer("teamStruct", team);
418
419	DefaultNotificationService::Notify(event, eventCode);
420}
421
422
423//	#pragma mark - Team
424
425
426Team::Team(team_id id, bool kernel)
427{
428	// allocate an ID
429	this->id = id;
430	visible = true;
431	serial_number = -1;
432
433	// init mutex
434	if (kernel) {
435		mutex_init(&fLock, "Team:kernel");
436	} else {
437		char lockName[16];
438		snprintf(lockName, sizeof(lockName), "Team:%" B_PRId32, id);
439		mutex_init_etc(&fLock, lockName, MUTEX_FLAG_CLONE_NAME);
440	}
441
442	hash_next = siblings_next = children = parent = NULL;
443	fName[0] = '\0';
444	fArgs[0] = '\0';
445	num_threads = 0;
446	io_context = NULL;
447	address_space = NULL;
448	realtime_sem_context = NULL;
449	xsi_sem_context = NULL;
450	thread_list = NULL;
451	main_thread = NULL;
452	loading_info = NULL;
453	state = TEAM_STATE_BIRTH;
454	flags = 0;
455	death_entry = NULL;
456	user_data_area = -1;
457	user_data = 0;
458	used_user_data = 0;
459	user_data_size = 0;
460	free_user_threads = NULL;
461
462	commpage_address = NULL;
463
464	supplementary_groups = NULL;
465	supplementary_group_count = 0;
466
467	dead_threads_kernel_time = 0;
468	dead_threads_user_time = 0;
469	cpu_clock_offset = 0;
470
471	// dead threads
472	list_init(&dead_threads);
473	dead_threads_count = 0;
474
475	// dead children
476	dead_children.count = 0;
477	dead_children.kernel_time = 0;
478	dead_children.user_time = 0;
479
480	// job control entry
481	job_control_entry = new(nothrow) ::job_control_entry;
482	if (job_control_entry != NULL) {
483		job_control_entry->state = JOB_CONTROL_STATE_NONE;
484		job_control_entry->thread = id;
485		job_control_entry->team = this;
486	}
487
488	// exit status -- setting initialized to false suffices
489	exit.initialized = false;
490
491	list_init(&sem_list);
492	list_init_etc(&port_list, port_team_link_offset());
493	list_init(&image_list);
494	list_init(&watcher_list);
495
496	clear_team_debug_info(&debug_info, true);
497
498	// init dead/stopped/continued children condition vars
499	dead_children.condition_variable.Init(&dead_children, "team children");
500
501	B_INITIALIZE_SPINLOCK(&time_lock);
502	B_INITIALIZE_SPINLOCK(&signal_lock);
503
504	fQueuedSignalsCounter = new(std::nothrow) BKernel::QueuedSignalsCounter(
505		kernel ? -1 : MAX_QUEUED_SIGNALS);
506	memset(fSignalActions, 0, sizeof(fSignalActions));
507
508	fUserDefinedTimerCount = 0;
509
510	fCoreDumpCondition = NULL;
511}
512
513
514Team::~Team()
515{
516	// get rid of all associated data
517	PrepareForDeletion();
518
519	if (io_context != NULL)
520		vfs_put_io_context(io_context);
521	delete_owned_ports(this);
522	sem_delete_owned_sems(this);
523
524	DeleteUserTimers(false);
525
526	fPendingSignals.Clear();
527
528	if (fQueuedSignalsCounter != NULL)
529		fQueuedSignalsCounter->ReleaseReference();
530
531	while (thread_death_entry* threadDeathEntry
532			= (thread_death_entry*)list_remove_head_item(&dead_threads)) {
533		free(threadDeathEntry);
534	}
535
536	while (::job_control_entry* entry = dead_children.entries.RemoveHead())
537		delete entry;
538
539	while (free_user_thread* entry = free_user_threads) {
540		free_user_threads = entry->next;
541		free(entry);
542	}
543
544	malloc_referenced_release(supplementary_groups);
545
546	delete job_control_entry;
547		// usually already NULL and transferred to the parent
548
549	mutex_destroy(&fLock);
550}
551
552
553/*static*/ Team*
554Team::Create(team_id id, const char* name, bool kernel)
555{
556	// create the team object
557	Team* team = new(std::nothrow) Team(id, kernel);
558	if (team == NULL)
559		return NULL;
560	ObjectDeleter<Team> teamDeleter(team);
561
562	if (name != NULL)
563		team->SetName(name);
564
565	// check initialization
566	if (team->job_control_entry == NULL || team->fQueuedSignalsCounter == NULL)
567		return NULL;
568
569	// finish initialization (arch specifics)
570	if (arch_team_init_team_struct(team, kernel) != B_OK)
571		return NULL;
572
573	if (!kernel) {
574		status_t error = user_timer_create_team_timers(team);
575		if (error != B_OK)
576			return NULL;
577	}
578
579	// everything went fine
580	return teamDeleter.Detach();
581}
582
583
584/*!	\brief Returns the team with the given ID.
585	Returns a reference to the team.
586	Team and thread spinlock must not be held.
587*/
588/*static*/ Team*
589Team::Get(team_id id)
590{
591	if (id == B_CURRENT_TEAM) {
592		Team* team = thread_get_current_thread()->team;
593		team->AcquireReference();
594		return team;
595	}
596
597	InterruptsReadSpinLocker locker(sTeamHashLock);
598	Team* team = sTeamHash.Lookup(id);
599	if (team != NULL)
600		team->AcquireReference();
601	return team;
602}
603
604
605/*!	\brief Returns the team with the given ID in a locked state.
606	Returns a reference to the team.
607	Team and thread spinlock must not be held.
608*/
609/*static*/ Team*
610Team::GetAndLock(team_id id)
611{
612	// get the team
613	Team* team = Get(id);
614	if (team == NULL)
615		return NULL;
616
617	// lock it
618	team->Lock();
619
620	// only return the team, when it isn't already dying
621	if (team->state >= TEAM_STATE_SHUTDOWN) {
622		team->Unlock();
623		team->ReleaseReference();
624		return NULL;
625	}
626
627	return team;
628}
629
630
631/*!	Locks the team and its parent team (if any).
632	The caller must hold a reference to the team or otherwise make sure that
633	it won't be deleted.
634	If the team doesn't have a parent, only the team itself is locked. If the
635	team's parent is the kernel team and \a dontLockParentIfKernel is \c true,
636	only the team itself is locked.
637
638	\param dontLockParentIfKernel If \c true, the team's parent team is only
639		locked, if it is not the kernel team.
640*/
641void
642Team::LockTeamAndParent(bool dontLockParentIfKernel)
643{
644	// The locking order is parent -> child. Since the parent can change as long
645	// as we don't lock the team, we need to do a trial and error loop.
646	Lock();
647
648	while (true) {
649		// If the team doesn't have a parent, we're done. Otherwise try to lock
650		// the parent.This will succeed in most cases, simplifying things.
651		Team* parent = this->parent;
652		if (parent == NULL || (dontLockParentIfKernel && parent == sKernelTeam)
653			|| parent->TryLock()) {
654			return;
655		}
656
657		// get a temporary reference to the parent, unlock this team, lock the
658		// parent, and re-lock this team
659		BReference<Team> parentReference(parent);
660
661		Unlock();
662		parent->Lock();
663		Lock();
664
665		// If the parent hasn't changed in the meantime, we're done.
666		if (this->parent == parent)
667			return;
668
669		// The parent has changed -- unlock and retry.
670		parent->Unlock();
671	}
672}
673
674
675/*!	Unlocks the team and its parent team (if any).
676*/
677void
678Team::UnlockTeamAndParent()
679{
680	if (parent != NULL)
681		parent->Unlock();
682
683	Unlock();
684}
685
686
687/*!	Locks the team, its parent team (if any), and the team's process group.
688	The caller must hold a reference to the team or otherwise make sure that
689	it won't be deleted.
690	If the team doesn't have a parent, only the team itself is locked.
691*/
692void
693Team::LockTeamParentAndProcessGroup()
694{
695	LockTeamAndProcessGroup();
696
697	// We hold the group's and the team's lock, but not the parent team's lock.
698	// If we have a parent, try to lock it.
699	if (this->parent == NULL || this->parent->TryLock())
700		return;
701
702	// No success -- unlock the team and let LockTeamAndParent() do the rest of
703	// the job.
704	Unlock();
705	LockTeamAndParent(false);
706}
707
708
709/*!	Unlocks the team, its parent team (if any), and the team's process group.
710*/
711void
712Team::UnlockTeamParentAndProcessGroup()
713{
714	group->Unlock();
715
716	if (parent != NULL)
717		parent->Unlock();
718
719	Unlock();
720}
721
722
723void
724Team::LockTeamAndProcessGroup()
725{
726	// The locking order is process group -> child. Since the process group can
727	// change as long as we don't lock the team, we need to do a trial and error
728	// loop.
729	Lock();
730
731	while (true) {
732		// Try to lock the group. This will succeed in most cases, simplifying
733		// things.
734		ProcessGroup* group = this->group;
735		if (group->TryLock())
736			return;
737
738		// get a temporary reference to the group, unlock this team, lock the
739		// group, and re-lock this team
740		BReference<ProcessGroup> groupReference(group);
741
742		Unlock();
743		group->Lock();
744		Lock();
745
746		// If the group hasn't changed in the meantime, we're done.
747		if (this->group == group)
748			return;
749
750		// The group has changed -- unlock and retry.
751		group->Unlock();
752	}
753}
754
755
756void
757Team::UnlockTeamAndProcessGroup()
758{
759	group->Unlock();
760	Unlock();
761}
762
763
764void
765Team::SetName(const char* name)
766{
767	if (const char* lastSlash = strrchr(name, '/'))
768		name = lastSlash + 1;
769
770	strlcpy(fName, name, B_OS_NAME_LENGTH);
771}
772
773
774void
775Team::SetArgs(const char* args)
776{
777	strlcpy(fArgs, args, sizeof(fArgs));
778}
779
780
781void
782Team::SetArgs(const char* path, const char* const* otherArgs, int otherArgCount)
783{
784	fArgs[0] = '\0';
785	strlcpy(fArgs, path, sizeof(fArgs));
786	for (int i = 0; i < otherArgCount; i++) {
787		strlcat(fArgs, " ", sizeof(fArgs));
788		strlcat(fArgs, otherArgs[i], sizeof(fArgs));
789	}
790}
791
792
793void
794Team::ResetSignalsOnExec()
795{
796	// We are supposed to keep pending signals. Signal actions shall be reset
797	// partially: SIG_IGN and SIG_DFL dispositions shall be kept as they are
798	// (for SIGCHLD it's implementation-defined). Others shall be reset to
799	// SIG_DFL. SA_ONSTACK shall be cleared. There's no mention of the other
800	// flags, but since there aren't any handlers, they make little sense, so
801	// we clear them.
802
803	for (uint32 i = 1; i <= MAX_SIGNAL_NUMBER; i++) {
804		struct sigaction& action = SignalActionFor(i);
805		if (action.sa_handler != SIG_IGN && action.sa_handler != SIG_DFL)
806			action.sa_handler = SIG_DFL;
807
808		action.sa_mask = 0;
809		action.sa_flags = 0;
810		action.sa_userdata = NULL;
811	}
812}
813
814
815void
816Team::InheritSignalActions(Team* parent)
817{
818	memcpy(fSignalActions, parent->fSignalActions, sizeof(fSignalActions));
819}
820
821
822/*!	Adds the given user timer to the team and, if user-defined, assigns it an
823	ID.
824
825	The caller must hold the team's lock.
826
827	\param timer The timer to be added. If it doesn't have an ID yet, it is
828		considered user-defined and will be assigned an ID.
829	\return \c B_OK, if the timer was added successfully, another error code
830		otherwise.
831*/
832status_t
833Team::AddUserTimer(UserTimer* timer)
834{
835	// don't allow addition of timers when already shutting the team down
836	if (state >= TEAM_STATE_SHUTDOWN)
837		return B_BAD_TEAM_ID;
838
839	// If the timer is user-defined, check timer limit and increment
840	// user-defined count.
841	if (timer->ID() < 0 && !CheckAddUserDefinedTimer())
842		return EAGAIN;
843
844	fUserTimers.AddTimer(timer);
845
846	return B_OK;
847}
848
849
850/*!	Removes the given user timer from the team.
851
852	The caller must hold the team's lock.
853
854	\param timer The timer to be removed.
855
856*/
857void
858Team::RemoveUserTimer(UserTimer* timer)
859{
860	fUserTimers.RemoveTimer(timer);
861
862	if (timer->ID() >= USER_TIMER_FIRST_USER_DEFINED_ID)
863		UserDefinedTimersRemoved(1);
864}
865
866
867/*!	Deletes all (or all user-defined) user timers of the team.
868
869	Timer's belonging to the team's threads are not affected.
870	The caller must hold the team's lock.
871
872	\param userDefinedOnly If \c true, only the user-defined timers are deleted,
873		otherwise all timers are deleted.
874*/
875void
876Team::DeleteUserTimers(bool userDefinedOnly)
877{
878	int32 count = fUserTimers.DeleteTimers(userDefinedOnly);
879	UserDefinedTimersRemoved(count);
880}
881
882
883/*!	If not at the limit yet, increments the team's user-defined timer count.
884	\return \c true, if the limit wasn't reached yet, \c false otherwise.
885*/
886bool
887Team::CheckAddUserDefinedTimer()
888{
889	int32 oldCount = atomic_add(&fUserDefinedTimerCount, 1);
890	if (oldCount >= MAX_USER_TIMERS_PER_TEAM) {
891		atomic_add(&fUserDefinedTimerCount, -1);
892		return false;
893	}
894
895	return true;
896}
897
898
899/*!	Subtracts the given count for the team's user-defined timer count.
900	\param count The count to subtract.
901*/
902void
903Team::UserDefinedTimersRemoved(int32 count)
904{
905	atomic_add(&fUserDefinedTimerCount, -count);
906}
907
908
909void
910Team::DeactivateCPUTimeUserTimers()
911{
912	while (TeamTimeUserTimer* timer = fCPUTimeUserTimers.Head())
913		timer->Deactivate();
914
915	while (TeamUserTimeUserTimer* timer = fUserTimeUserTimers.Head())
916		timer->Deactivate();
917}
918
919
920/*!	Returns the team's current total CPU time (kernel + user + offset).
921
922	The caller must hold \c time_lock.
923
924	\param ignoreCurrentRun If \c true and the current thread is one team's
925		threads, don't add the time since the last time \c last_time was
926		updated. Should be used in "thread unscheduled" scheduler callbacks,
927		since although the thread is still running at that time, its time has
928		already been stopped.
929	\return The team's current total CPU time.
930*/
931bigtime_t
932Team::CPUTime(bool ignoreCurrentRun, Thread* lockedThread) const
933{
934	bigtime_t time = cpu_clock_offset + dead_threads_kernel_time
935		+ dead_threads_user_time;
936
937	Thread* currentThread = thread_get_current_thread();
938	bigtime_t now = system_time();
939
940	for (Thread* thread = thread_list; thread != NULL;
941			thread = thread->team_next) {
942		bool alreadyLocked = thread == lockedThread;
943		SpinLocker threadTimeLocker(thread->time_lock, alreadyLocked);
944		time += thread->kernel_time + thread->user_time;
945
946		if (thread->last_time != 0) {
947			if (!ignoreCurrentRun || thread != currentThread)
948				time += now - thread->last_time;
949		}
950
951		if (alreadyLocked)
952			threadTimeLocker.Detach();
953	}
954
955	return time;
956}
957
958
959/*!	Returns the team's current user CPU time.
960
961	The caller must hold \c time_lock.
962
963	\return The team's current user CPU time.
964*/
965bigtime_t
966Team::UserCPUTime() const
967{
968	bigtime_t time = dead_threads_user_time;
969
970	bigtime_t now = system_time();
971
972	for (Thread* thread = thread_list; thread != NULL;
973			thread = thread->team_next) {
974		SpinLocker threadTimeLocker(thread->time_lock);
975		time += thread->user_time;
976
977		if (thread->last_time != 0 && !thread->in_kernel)
978			time += now - thread->last_time;
979	}
980
981	return time;
982}
983
984
985//	#pragma mark - ProcessGroup
986
987
988ProcessGroup::ProcessGroup(pid_t id)
989	:
990	id(id),
991	teams(NULL),
992	fSession(NULL),
993	fInOrphanedCheckList(false)
994{
995	char lockName[32];
996	snprintf(lockName, sizeof(lockName), "Group:%" B_PRId32, id);
997	mutex_init_etc(&fLock, lockName, MUTEX_FLAG_CLONE_NAME);
998}
999
1000
1001ProcessGroup::~ProcessGroup()
1002{
1003	TRACE(("ProcessGroup::~ProcessGroup(): id = %" B_PRId32 "\n", id));
1004
1005	// If the group is in the orphaned check list, remove it.
1006	MutexLocker orphanedCheckLocker(sOrphanedCheckLock);
1007
1008	if (fInOrphanedCheckList)
1009		sOrphanedCheckProcessGroups.Remove(this);
1010
1011	orphanedCheckLocker.Unlock();
1012
1013	// remove group from the hash table and from the session
1014	if (fSession != NULL) {
1015		InterruptsSpinLocker groupHashLocker(sGroupHashLock);
1016		sGroupHash.RemoveUnchecked(this);
1017		groupHashLocker.Unlock();
1018
1019		fSession->ReleaseReference();
1020	}
1021
1022	mutex_destroy(&fLock);
1023}
1024
1025
1026/*static*/ ProcessGroup*
1027ProcessGroup::Get(pid_t id)
1028{
1029	InterruptsSpinLocker groupHashLocker(sGroupHashLock);
1030	ProcessGroup* group = sGroupHash.Lookup(id);
1031	if (group != NULL)
1032		group->AcquireReference();
1033	return group;
1034}
1035
1036
1037/*!	Adds the group the given session and makes it publicly accessible.
1038	The caller must not hold the process group hash lock.
1039*/
1040void
1041ProcessGroup::Publish(ProcessSession* session)
1042{
1043	InterruptsSpinLocker groupHashLocker(sGroupHashLock);
1044	PublishLocked(session);
1045}
1046
1047
1048/*!	Adds the group to the given session and makes it publicly accessible.
1049	The caller must hold the process group hash lock.
1050*/
1051void
1052ProcessGroup::PublishLocked(ProcessSession* session)
1053{
1054	ASSERT(sGroupHash.Lookup(this->id) == NULL);
1055
1056	fSession = session;
1057	fSession->AcquireReference();
1058
1059	sGroupHash.InsertUnchecked(this);
1060}
1061
1062
1063/*!	Checks whether the process group is orphaned.
1064	The caller must hold the group's lock.
1065	\return \c true, if the group is orphaned, \c false otherwise.
1066*/
1067bool
1068ProcessGroup::IsOrphaned() const
1069{
1070	// Orphaned Process Group: "A process group in which the parent of every
1071	// member is either itself a member of the group or is not a member of the
1072	// group's session." (Open Group Base Specs Issue 7)
1073	bool orphaned = true;
1074
1075	Team* team = teams;
1076	while (orphaned && team != NULL) {
1077		team->LockTeamAndParent(false);
1078
1079		Team* parent = team->parent;
1080		if (parent != NULL && parent->group_id != id
1081			&& parent->session_id == fSession->id) {
1082			orphaned = false;
1083		}
1084
1085		team->UnlockTeamAndParent();
1086
1087		team = team->group_next;
1088	}
1089
1090	return orphaned;
1091}
1092
1093
1094void
1095ProcessGroup::ScheduleOrphanedCheck()
1096{
1097	MutexLocker orphanedCheckLocker(sOrphanedCheckLock);
1098
1099	if (!fInOrphanedCheckList) {
1100		sOrphanedCheckProcessGroups.Add(this);
1101		fInOrphanedCheckList = true;
1102	}
1103}
1104
1105
1106void
1107ProcessGroup::UnsetOrphanedCheck()
1108{
1109	fInOrphanedCheckList = false;
1110}
1111
1112
1113//	#pragma mark - ProcessSession
1114
1115
1116ProcessSession::ProcessSession(pid_t id)
1117	:
1118	id(id),
1119	controlling_tty(-1),
1120	foreground_group(-1)
1121{
1122	char lockName[32];
1123	snprintf(lockName, sizeof(lockName), "Session:%" B_PRId32, id);
1124	mutex_init_etc(&fLock, lockName, MUTEX_FLAG_CLONE_NAME);
1125}
1126
1127
1128ProcessSession::~ProcessSession()
1129{
1130	mutex_destroy(&fLock);
1131}
1132
1133
1134//	#pragma mark - KDL functions
1135
1136
1137static void
1138_dump_team_info(Team* team)
1139{
1140	kprintf("TEAM: %p\n", team);
1141	kprintf("id:               %" B_PRId32 " (%#" B_PRIx32 ")\n", team->id,
1142		team->id);
1143	kprintf("serial_number:    %" B_PRId64 "\n", team->serial_number);
1144	kprintf("name:             '%s'\n", team->Name());
1145	kprintf("args:             '%s'\n", team->Args());
1146	kprintf("hash_next:        %p\n", team->hash_next);
1147	kprintf("parent:           %p", team->parent);
1148	if (team->parent != NULL) {
1149		kprintf(" (id = %" B_PRId32 ")\n", team->parent->id);
1150	} else
1151		kprintf("\n");
1152
1153	kprintf("children:         %p\n", team->children);
1154	kprintf("num_threads:      %d\n", team->num_threads);
1155	kprintf("state:            %d\n", team->state);
1156	kprintf("flags:            0x%" B_PRIx32 "\n", team->flags);
1157	kprintf("io_context:       %p\n", team->io_context);
1158	if (team->address_space)
1159		kprintf("address_space:    %p\n", team->address_space);
1160	kprintf("user data:        %p (area %" B_PRId32 ")\n",
1161		(void*)team->user_data, team->user_data_area);
1162	kprintf("free user thread: %p\n", team->free_user_threads);
1163	kprintf("main_thread:      %p\n", team->main_thread);
1164	kprintf("thread_list:      %p\n", team->thread_list);
1165	kprintf("group_id:         %" B_PRId32 "\n", team->group_id);
1166	kprintf("session_id:       %" B_PRId32 "\n", team->session_id);
1167}
1168
1169
1170static int
1171dump_team_info(int argc, char** argv)
1172{
1173	ulong arg;
1174	bool found = false;
1175
1176	if (argc < 2) {
1177		Thread* thread = thread_get_current_thread();
1178		if (thread != NULL && thread->team != NULL)
1179			_dump_team_info(thread->team);
1180		else
1181			kprintf("No current team!\n");
1182		return 0;
1183	}
1184
1185	arg = strtoul(argv[1], NULL, 0);
1186	if (IS_KERNEL_ADDRESS(arg)) {
1187		// semi-hack
1188		_dump_team_info((Team*)arg);
1189		return 0;
1190	}
1191
1192	// walk through the thread list, trying to match name or id
1193	for (TeamTable::Iterator it = sTeamHash.GetIterator();
1194		Team* team = it.Next();) {
1195		if ((team->Name() && strcmp(argv[1], team->Name()) == 0)
1196			|| team->id == (team_id)arg) {
1197			_dump_team_info(team);
1198			found = true;
1199			break;
1200		}
1201	}
1202
1203	if (!found)
1204		kprintf("team \"%s\" (%" B_PRId32 ") doesn't exist!\n", argv[1], (team_id)arg);
1205	return 0;
1206}
1207
1208
1209static int
1210dump_teams(int argc, char** argv)
1211{
1212	kprintf("%-*s       id  %-*s    name\n", B_PRINTF_POINTER_WIDTH, "team",
1213		B_PRINTF_POINTER_WIDTH, "parent");
1214
1215	for (TeamTable::Iterator it = sTeamHash.GetIterator();
1216		Team* team = it.Next();) {
1217		kprintf("%p%7" B_PRId32 "  %p  %s\n", team, team->id, team->parent, team->Name());
1218	}
1219
1220	return 0;
1221}
1222
1223
1224//	#pragma mark - Private functions
1225
1226
1227/*!	Inserts team \a team into the child list of team \a parent.
1228
1229	The caller must hold the lock of both \a parent and \a team.
1230
1231	\param parent The parent team.
1232	\param team The team to be inserted into \a parent's child list.
1233*/
1234static void
1235insert_team_into_parent(Team* parent, Team* team)
1236{
1237	ASSERT(parent != NULL);
1238
1239	team->siblings_next = parent->children;
1240	parent->children = team;
1241	team->parent = parent;
1242}
1243
1244
1245/*!	Removes team \a team from the child list of team \a parent.
1246
1247	The caller must hold the lock of both \a parent and \a team.
1248
1249	\param parent The parent team.
1250	\param team The team to be removed from \a parent's child list.
1251*/
1252static void
1253remove_team_from_parent(Team* parent, Team* team)
1254{
1255	Team* child;
1256	Team* last = NULL;
1257
1258	for (child = parent->children; child != NULL;
1259			child = child->siblings_next) {
1260		if (child == team) {
1261			if (last == NULL)
1262				parent->children = child->siblings_next;
1263			else
1264				last->siblings_next = child->siblings_next;
1265
1266			team->parent = NULL;
1267			break;
1268		}
1269		last = child;
1270	}
1271}
1272
1273
1274/*!	Returns whether the given team is a session leader.
1275	The caller must hold the team's lock or its process group's lock.
1276*/
1277static bool
1278is_session_leader(Team* team)
1279{
1280	return team->session_id == team->id;
1281}
1282
1283
1284/*!	Returns whether the given team is a process group leader.
1285	The caller must hold the team's lock or its process group's lock.
1286*/
1287static bool
1288is_process_group_leader(Team* team)
1289{
1290	return team->group_id == team->id;
1291}
1292
1293
1294/*!	Inserts the given team into the given process group.
1295	The caller must hold the process group's lock, the team's lock, and the
1296	team's parent's lock.
1297*/
1298static void
1299insert_team_into_group(ProcessGroup* group, Team* team)
1300{
1301	team->group = group;
1302	team->group_id = group->id;
1303	team->session_id = group->Session()->id;
1304
1305	team->group_next = group->teams;
1306	group->teams = team;
1307	group->AcquireReference();
1308}
1309
1310
1311/*!	Removes the given team from its process group.
1312
1313	The caller must hold the process group's lock, the team's lock, and the
1314	team's parent's lock. Interrupts must be enabled.
1315
1316	\param team The team that'll be removed from its process group.
1317*/
1318static void
1319remove_team_from_group(Team* team)
1320{
1321	ProcessGroup* group = team->group;
1322	Team* current;
1323	Team* last = NULL;
1324
1325	// the team must be in a process group to let this function have any effect
1326	if  (group == NULL)
1327		return;
1328
1329	for (current = group->teams; current != NULL;
1330			current = current->group_next) {
1331		if (current == team) {
1332			if (last == NULL)
1333				group->teams = current->group_next;
1334			else
1335				last->group_next = current->group_next;
1336
1337			team->group = NULL;
1338			break;
1339		}
1340		last = current;
1341	}
1342
1343	team->group = NULL;
1344	team->group_next = NULL;
1345
1346	group->ReleaseReference();
1347}
1348
1349
1350static status_t
1351create_team_user_data(Team* team, void* exactAddress = NULL)
1352{
1353	void* address;
1354	uint32 addressSpec;
1355
1356	if (exactAddress != NULL) {
1357		address = exactAddress;
1358		addressSpec = B_EXACT_ADDRESS;
1359	} else {
1360		address = (void*)KERNEL_USER_DATA_BASE;
1361		addressSpec = B_RANDOMIZED_BASE_ADDRESS;
1362	}
1363
1364	status_t result = vm_reserve_address_range(team->id, &address, addressSpec,
1365		kTeamUserDataReservedSize, RESERVED_AVOID_BASE);
1366
1367	virtual_address_restrictions virtualRestrictions = {};
1368	if (result == B_OK || exactAddress != NULL) {
1369		if (exactAddress != NULL)
1370			virtualRestrictions.address = exactAddress;
1371		else
1372			virtualRestrictions.address = address;
1373		virtualRestrictions.address_specification = B_EXACT_ADDRESS;
1374	} else {
1375		virtualRestrictions.address = (void*)KERNEL_USER_DATA_BASE;
1376		virtualRestrictions.address_specification = B_RANDOMIZED_BASE_ADDRESS;
1377	}
1378
1379	physical_address_restrictions physicalRestrictions = {};
1380	team->user_data_area = create_area_etc(team->id, "user area",
1381		kTeamUserDataInitialSize, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA, 0, 0,
1382		&virtualRestrictions, &physicalRestrictions, &address);
1383	if (team->user_data_area < 0)
1384		return team->user_data_area;
1385
1386	team->user_data = (addr_t)address;
1387	team->used_user_data = 0;
1388	team->user_data_size = kTeamUserDataInitialSize;
1389	team->free_user_threads = NULL;
1390
1391	return B_OK;
1392}
1393
1394
1395static void
1396delete_team_user_data(Team* team)
1397{
1398	if (team->user_data_area >= 0) {
1399		vm_delete_area(team->id, team->user_data_area, true);
1400		vm_unreserve_address_range(team->id, (void*)team->user_data,
1401			kTeamUserDataReservedSize);
1402
1403		team->user_data = 0;
1404		team->used_user_data = 0;
1405		team->user_data_size = 0;
1406		team->user_data_area = -1;
1407		while (free_user_thread* entry = team->free_user_threads) {
1408			team->free_user_threads = entry->next;
1409			free(entry);
1410		}
1411	}
1412}
1413
1414
1415static status_t
1416copy_user_process_args(const char* const* userFlatArgs, size_t flatArgsSize,
1417	int32 argCount, int32 envCount, char**& _flatArgs)
1418{
1419	if (argCount < 0 || envCount < 0)
1420		return B_BAD_VALUE;
1421
1422	if (flatArgsSize > MAX_PROCESS_ARGS_SIZE)
1423		return B_TOO_MANY_ARGS;
1424	if ((argCount + envCount + 2) * sizeof(char*) > flatArgsSize)
1425		return B_BAD_VALUE;
1426
1427	if (!IS_USER_ADDRESS(userFlatArgs))
1428		return B_BAD_ADDRESS;
1429
1430	// allocate kernel memory
1431	char** flatArgs = (char**)malloc(_ALIGN(flatArgsSize));
1432	if (flatArgs == NULL)
1433		return B_NO_MEMORY;
1434
1435	if (user_memcpy(flatArgs, userFlatArgs, flatArgsSize) != B_OK) {
1436		free(flatArgs);
1437		return B_BAD_ADDRESS;
1438	}
1439
1440	// check and relocate the array
1441	status_t error = B_OK;
1442	const char* stringBase = (char*)flatArgs + argCount + envCount + 2;
1443	const char* stringEnd = (char*)flatArgs + flatArgsSize;
1444	for (int32 i = 0; i < argCount + envCount + 2; i++) {
1445		if (i == argCount || i == argCount + envCount + 1) {
1446			// check array null termination
1447			if (flatArgs[i] != NULL) {
1448				error = B_BAD_VALUE;
1449				break;
1450			}
1451		} else {
1452			// check string
1453			char* arg = (char*)flatArgs + (flatArgs[i] - (char*)userFlatArgs);
1454			size_t maxLen = stringEnd - arg;
1455			if (arg < stringBase || arg >= stringEnd
1456					|| strnlen(arg, maxLen) == maxLen) {
1457				error = B_BAD_VALUE;
1458				break;
1459			}
1460
1461			flatArgs[i] = arg;
1462		}
1463	}
1464
1465	if (error == B_OK)
1466		_flatArgs = flatArgs;
1467	else
1468		free(flatArgs);
1469
1470	return error;
1471}
1472
1473
1474static void
1475free_team_arg(struct team_arg* teamArg)
1476{
1477	if (teamArg != NULL) {
1478		free(teamArg->flat_args);
1479		free(teamArg->path);
1480		free(teamArg);
1481	}
1482}
1483
1484
1485static status_t
1486create_team_arg(struct team_arg** _teamArg, const char* path, char** flatArgs,
1487	size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask,
1488	port_id port, uint32 token)
1489{
1490	struct team_arg* teamArg = (struct team_arg*)malloc(sizeof(team_arg));
1491	if (teamArg == NULL)
1492		return B_NO_MEMORY;
1493
1494	teamArg->path = strdup(path);
1495	if (teamArg->path == NULL) {
1496		free(teamArg);
1497		return B_NO_MEMORY;
1498	}
1499
1500	// copy the args over
1501	teamArg->flat_args = flatArgs;
1502	teamArg->flat_args_size = flatArgsSize;
1503	teamArg->arg_count = argCount;
1504	teamArg->env_count = envCount;
1505	teamArg->flags = 0;
1506	teamArg->umask = umask;
1507	teamArg->error_port = port;
1508	teamArg->error_token = token;
1509
1510	// determine the flags from the environment
1511	const char* const* env = flatArgs + argCount + 1;
1512	for (int32 i = 0; i < envCount; i++) {
1513		if (strcmp(env[i], "DISABLE_ASLR=1") == 0) {
1514			teamArg->flags |= TEAM_ARGS_FLAG_NO_ASLR;
1515			break;
1516		}
1517	}
1518
1519	*_teamArg = teamArg;
1520	return B_OK;
1521}
1522
1523
1524static status_t
1525team_create_thread_start_internal(void* args)
1526{
1527	status_t err;
1528	Thread* thread;
1529	Team* team;
1530	struct team_arg* teamArgs = (struct team_arg*)args;
1531	const char* path;
1532	addr_t entry;
1533	char** userArgs;
1534	char** userEnv;
1535	struct user_space_program_args* programArgs;
1536	uint32 argCount, envCount;
1537
1538	thread = thread_get_current_thread();
1539	team = thread->team;
1540	cache_node_launched(teamArgs->arg_count, teamArgs->flat_args);
1541
1542	TRACE(("team_create_thread_start: entry thread %" B_PRId32 "\n",
1543		thread->id));
1544
1545	// Main stack area layout is currently as follows (starting from 0):
1546	//
1547	// size								| usage
1548	// ---------------------------------+--------------------------------
1549	// USER_MAIN_THREAD_STACK_SIZE		| actual stack
1550	// TLS_SIZE							| TLS data
1551	// sizeof(user_space_program_args)	| argument structure for the runtime
1552	//									| loader
1553	// flat arguments size				| flat process arguments and environment
1554
1555	// TODO: ENV_SIZE is a) limited, and b) not used after libroot copied it to
1556	// the heap
1557	// TODO: we could reserve the whole USER_STACK_REGION upfront...
1558
1559	argCount = teamArgs->arg_count;
1560	envCount = teamArgs->env_count;
1561
1562	programArgs = (struct user_space_program_args*)(thread->user_stack_base
1563		+ thread->user_stack_size + TLS_SIZE);
1564
1565	userArgs = (char**)(programArgs + 1);
1566	userEnv = userArgs + argCount + 1;
1567	path = teamArgs->path;
1568
1569	if (user_strlcpy(programArgs->program_path, path,
1570				sizeof(programArgs->program_path)) < B_OK
1571		|| user_memcpy(&programArgs->arg_count, &argCount, sizeof(int32)) < B_OK
1572		|| user_memcpy(&programArgs->args, &userArgs, sizeof(char**)) < B_OK
1573		|| user_memcpy(&programArgs->env_count, &envCount, sizeof(int32)) < B_OK
1574		|| user_memcpy(&programArgs->env, &userEnv, sizeof(char**)) < B_OK
1575		|| user_memcpy(&programArgs->error_port, &teamArgs->error_port,
1576				sizeof(port_id)) < B_OK
1577		|| user_memcpy(&programArgs->error_token, &teamArgs->error_token,
1578				sizeof(uint32)) < B_OK
1579		|| user_memcpy(&programArgs->umask, &teamArgs->umask, sizeof(mode_t)) < B_OK
1580		|| user_memcpy(&programArgs->disable_user_addons,
1581			&sDisableUserAddOns, sizeof(bool)) < B_OK
1582		|| user_memcpy(userArgs, teamArgs->flat_args,
1583				teamArgs->flat_args_size) < B_OK) {
1584		// the team deletion process will clean this mess
1585		free_team_arg(teamArgs);
1586		return B_BAD_ADDRESS;
1587	}
1588
1589	TRACE(("team_create_thread_start: loading elf binary '%s'\n", path));
1590
1591	// set team args and update state
1592	team->Lock();
1593	team->SetArgs(path, teamArgs->flat_args + 1, argCount - 1);
1594	team->state = TEAM_STATE_NORMAL;
1595	team->Unlock();
1596
1597	free_team_arg(teamArgs);
1598		// the arguments are already on the user stack, we no longer need
1599		// them in this form
1600
1601	// Clone commpage area
1602	area_id commPageArea = clone_commpage_area(team->id,
1603		&team->commpage_address);
1604	if (commPageArea  < B_OK) {
1605		TRACE(("team_create_thread_start: clone_commpage_area() failed: %s\n",
1606			strerror(commPageArea)));
1607		return commPageArea;
1608	}
1609
1610	// Register commpage image
1611	image_id commPageImage = get_commpage_image();
1612	extended_image_info imageInfo;
1613	err = get_image_info(commPageImage, &imageInfo.basic_info);
1614	if (err != B_OK) {
1615		TRACE(("team_create_thread_start: get_image_info() failed: %s\n",
1616			strerror(err)));
1617		return err;
1618	}
1619	imageInfo.basic_info.text = team->commpage_address;
1620	imageInfo.text_delta = (ssize_t)(addr_t)team->commpage_address;
1621	imageInfo.symbol_table = NULL;
1622	imageInfo.symbol_hash = NULL;
1623	imageInfo.string_table = NULL;
1624	image_id image = register_image(team, &imageInfo, sizeof(imageInfo));
1625	if (image < 0) {
1626		TRACE(("team_create_thread_start: register_image() failed: %s\n",
1627			strerror(image)));
1628		return image;
1629	}
1630
1631	// NOTE: Normally arch_thread_enter_userspace() never returns, that is
1632	// automatic variables with function scope will never be destroyed.
1633	{
1634		// find runtime_loader path
1635		KPath runtimeLoaderPath;
1636		err = __find_directory(B_SYSTEM_DIRECTORY, gBootDevice, false,
1637			runtimeLoaderPath.LockBuffer(), runtimeLoaderPath.BufferSize());
1638		if (err < B_OK) {
1639			TRACE(("team_create_thread_start: find_directory() failed: %s\n",
1640				strerror(err)));
1641			return err;
1642		}
1643		runtimeLoaderPath.UnlockBuffer();
1644		err = runtimeLoaderPath.Append("runtime_loader");
1645
1646		if (err == B_OK) {
1647			err = elf_load_user_image(runtimeLoaderPath.Path(), team, 0,
1648				&entry);
1649		}
1650	}
1651
1652	if (err < B_OK) {
1653		// Luckily, we don't have to clean up the mess we created - that's
1654		// done for us by the normal team deletion process
1655		TRACE(("team_create_thread_start: elf_load_user_image() failed: "
1656			"%s\n", strerror(err)));
1657		return err;
1658	}
1659
1660	TRACE(("team_create_thread_start: loaded elf. entry = %#lx\n", entry));
1661
1662	// enter userspace -- returns only in case of error
1663	return thread_enter_userspace_new_team(thread, (addr_t)entry,
1664		programArgs, team->commpage_address);
1665}
1666
1667
1668static status_t
1669team_create_thread_start(void* args)
1670{
1671	team_create_thread_start_internal(args);
1672	team_init_exit_info_on_error(thread_get_current_thread()->team);
1673	thread_exit();
1674		// does not return
1675	return B_OK;
1676}
1677
1678
1679static thread_id
1680load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount,
1681	int32 envCount, int32 priority, team_id parentID, uint32 flags,
1682	port_id errorPort, uint32 errorToken)
1683{
1684	char** flatArgs = _flatArgs;
1685	thread_id thread;
1686	status_t status;
1687	struct team_arg* teamArgs;
1688	struct team_loading_info loadingInfo;
1689	ConditionVariableEntry loadingWaitEntry;
1690	io_context* parentIOContext = NULL;
1691	team_id teamID;
1692	bool teamLimitReached = false;
1693
1694	if (flatArgs == NULL || argCount == 0)
1695		return B_BAD_VALUE;
1696
1697	const char* path = flatArgs[0];
1698
1699	TRACE(("load_image_internal: name '%s', args = %p, argCount = %" B_PRId32
1700		"\n", path, flatArgs, argCount));
1701
1702	// cut the path from the main thread name
1703	const char* threadName = strrchr(path, '/');
1704	if (threadName != NULL)
1705		threadName++;
1706	else
1707		threadName = path;
1708
1709	// create the main thread object
1710	Thread* mainThread;
1711	status = Thread::Create(threadName, mainThread);
1712	if (status != B_OK)
1713		return status;
1714	BReference<Thread> mainThreadReference(mainThread, true);
1715
1716	// create team object
1717	Team* team = Team::Create(mainThread->id, path, false);
1718	if (team == NULL)
1719		return B_NO_MEMORY;
1720	BReference<Team> teamReference(team, true);
1721
1722	if ((flags & B_WAIT_TILL_LOADED) != 0) {
1723		loadingInfo.condition.Init(team, "image load");
1724		loadingInfo.condition.Add(&loadingWaitEntry);
1725		loadingInfo.result = B_ERROR;
1726		team->loading_info = &loadingInfo;
1727	}
1728
1729	// get the parent team
1730	Team* parent = Team::Get(parentID);
1731	if (parent == NULL)
1732		return B_BAD_TEAM_ID;
1733	BReference<Team> parentReference(parent, true);
1734
1735	parent->LockTeamAndProcessGroup();
1736	team->Lock();
1737
1738	// inherit the parent's user/group
1739	inherit_parent_user_and_group(team, parent);
1740
1741	// get a reference to the parent's I/O context -- we need it to create ours
1742	parentIOContext = parent->io_context;
1743	vfs_get_io_context(parentIOContext);
1744
1745	team->Unlock();
1746	parent->UnlockTeamAndProcessGroup();
1747
1748	// check the executable's set-user/group-id permission
1749	update_set_id_user_and_group(team, path);
1750
1751	status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize, argCount,
1752		envCount, (mode_t)-1, errorPort, errorToken);
1753	if (status != B_OK)
1754		goto err1;
1755
1756	_flatArgs = NULL;
1757		// args are owned by the team_arg structure now
1758
1759	// create a new io_context for this team
1760	team->io_context = vfs_new_io_context(parentIOContext, true);
1761	if (!team->io_context) {
1762		status = B_NO_MEMORY;
1763		goto err2;
1764	}
1765
1766	// We don't need the parent's I/O context any longer.
1767	vfs_put_io_context(parentIOContext);
1768	parentIOContext = NULL;
1769
1770	// remove any fds that have the CLOEXEC flag set (emulating BeOS behaviour)
1771	vfs_exec_io_context(team->io_context);
1772
1773	// create an address space for this team
1774	status = VMAddressSpace::Create(team->id, USER_BASE, USER_SIZE, false,
1775		&team->address_space);
1776	if (status != B_OK)
1777		goto err2;
1778
1779	team->address_space->SetRandomizingEnabled(
1780		(teamArgs->flags & TEAM_ARGS_FLAG_NO_ASLR) == 0);
1781
1782	// create the user data area
1783	status = create_team_user_data(team);
1784	if (status != B_OK)
1785		goto err4;
1786
1787	// insert the team into its parent and the teams hash
1788	parent->LockTeamAndProcessGroup();
1789	team->Lock();
1790
1791	{
1792		InterruptsWriteSpinLocker teamsLocker(sTeamHashLock);
1793
1794		sTeamHash.Insert(team);
1795		teamLimitReached = sUsedTeams >= sMaxTeams;
1796		if (!teamLimitReached)
1797			sUsedTeams++;
1798	}
1799
1800	insert_team_into_parent(parent, team);
1801	insert_team_into_group(parent->group, team);
1802
1803	team->Unlock();
1804	parent->UnlockTeamAndProcessGroup();
1805
1806	// notify team listeners
1807	sNotificationService.Notify(TEAM_ADDED, team);
1808
1809	if (teamLimitReached) {
1810		status = B_NO_MORE_TEAMS;
1811		goto err6;
1812	}
1813
1814	// In case we start the main thread, we shouldn't access the team object
1815	// afterwards, so cache the team's ID.
1816	teamID = team->id;
1817
1818	// Create a kernel thread, but under the context of the new team
1819	// The new thread will take over ownership of teamArgs.
1820	{
1821		ThreadCreationAttributes threadAttributes(team_create_thread_start,
1822			threadName, B_NORMAL_PRIORITY, teamArgs, teamID, mainThread);
1823		threadAttributes.additional_stack_size = sizeof(user_space_program_args)
1824			+ teamArgs->flat_args_size;
1825		thread = thread_create_thread(threadAttributes, false);
1826		if (thread < 0) {
1827			status = thread;
1828			goto err6;
1829		}
1830	}
1831
1832	// The team has been created successfully, so we keep the reference. Or
1833	// more precisely: It's owned by the team's main thread, now.
1834	teamReference.Detach();
1835
1836	// wait for the loader of the new team to finish its work
1837	if ((flags & B_WAIT_TILL_LOADED) != 0) {
1838		if (mainThread != NULL) {
1839			// resume the team's main thread
1840			thread_continue(mainThread);
1841		}
1842
1843		// Now wait until loading is finished. We will be woken either by the
1844		// thread, when it finished or aborted loading, or when the team is
1845		// going to die (e.g. is killed). In either case the one notifying is
1846		// responsible for unsetting `loading_info` in the team structure.
1847		loadingWaitEntry.Wait();
1848
1849		if (loadingInfo.result < B_OK)
1850			return loadingInfo.result;
1851	}
1852
1853	// notify the debugger
1854	user_debug_team_created(teamID);
1855
1856	return thread;
1857
1858err6:
1859	// Remove the team structure from the process group, the parent team, and
1860	// the team hash table and delete the team structure.
1861	parent->LockTeamAndProcessGroup();
1862	team->Lock();
1863
1864	remove_team_from_group(team);
1865	remove_team_from_parent(team->parent, team);
1866
1867	team->Unlock();
1868	parent->UnlockTeamAndProcessGroup();
1869
1870	{
1871		InterruptsWriteSpinLocker teamsLocker(sTeamHashLock);
1872		sTeamHash.Remove(team);
1873		if (!teamLimitReached)
1874			sUsedTeams--;
1875	}
1876
1877	sNotificationService.Notify(TEAM_REMOVED, team);
1878
1879	delete_team_user_data(team);
1880err4:
1881	team->address_space->Put();
1882err2:
1883	free_team_arg(teamArgs);
1884err1:
1885	if (parentIOContext != NULL)
1886		vfs_put_io_context(parentIOContext);
1887
1888	return status;
1889}
1890
1891
1892/*!	Almost shuts down the current team and loads a new image into it.
1893	If successful, this function does not return and will takeover ownership of
1894	the arguments provided.
1895	This function may only be called in a userland team (caused by one of the
1896	exec*() syscalls).
1897*/
1898static status_t
1899exec_team(const char* path, char**& _flatArgs, size_t flatArgsSize,
1900	int32 argCount, int32 envCount, mode_t umask)
1901{
1902	// NOTE: Since this function normally doesn't return, don't use automatic
1903	// variables that need destruction in the function scope.
1904	char** flatArgs = _flatArgs;
1905	Team* team = thread_get_current_thread()->team;
1906	struct team_arg* teamArgs;
1907	const char* threadName;
1908	thread_id nubThreadID = -1;
1909
1910	TRACE(("exec_team(path = \"%s\", argc = %" B_PRId32 ", envCount = %"
1911		B_PRId32 "): team %" B_PRId32 "\n", path, argCount, envCount,
1912		team->id));
1913
1914	T(ExecTeam(path, argCount, flatArgs, envCount, flatArgs + argCount + 1));
1915
1916	// switching the kernel at run time is probably not a good idea :)
1917	if (team == team_get_kernel_team())
1918		return B_NOT_ALLOWED;
1919
1920	// we currently need to be single threaded here
1921	// TODO: maybe we should just kill all other threads and
1922	//	make the current thread the team's main thread?
1923	Thread* currentThread = thread_get_current_thread();
1924	if (currentThread != team->main_thread)
1925		return B_NOT_ALLOWED;
1926
1927	// The debug nub thread, a pure kernel thread, is allowed to survive.
1928	// We iterate through the thread list to make sure that there's no other
1929	// thread.
1930	TeamLocker teamLocker(team);
1931	InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
1932
1933	if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED)
1934		nubThreadID = team->debug_info.nub_thread;
1935
1936	debugInfoLocker.Unlock();
1937
1938	for (Thread* thread = team->thread_list; thread != NULL;
1939			thread = thread->team_next) {
1940		if (thread != team->main_thread && thread->id != nubThreadID)
1941			return B_NOT_ALLOWED;
1942	}
1943
1944	team->DeleteUserTimers(true);
1945	team->ResetSignalsOnExec();
1946
1947	teamLocker.Unlock();
1948
1949	status_t status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize,
1950		argCount, envCount, umask, -1, 0);
1951	if (status != B_OK)
1952		return status;
1953
1954	_flatArgs = NULL;
1955		// args are owned by the team_arg structure now
1956
1957	// TODO: remove team resources if there are any left
1958	// thread_atkernel_exit() might not be called at all
1959
1960	thread_reset_for_exec();
1961
1962	user_debug_prepare_for_exec();
1963
1964	delete_team_user_data(team);
1965	vm_delete_areas(team->address_space, false);
1966	xsi_sem_undo(team);
1967	delete_owned_ports(team);
1968	sem_delete_owned_sems(team);
1969	remove_images(team);
1970	vfs_exec_io_context(team->io_context);
1971	delete_realtime_sem_context(team->realtime_sem_context);
1972	team->realtime_sem_context = NULL;
1973
1974	// update ASLR
1975	team->address_space->SetRandomizingEnabled(
1976		(teamArgs->flags & TEAM_ARGS_FLAG_NO_ASLR) == 0);
1977
1978	status = create_team_user_data(team);
1979	if (status != B_OK) {
1980		// creating the user data failed -- we're toast
1981		free_team_arg(teamArgs);
1982		exit_thread(status);
1983		return status;
1984	}
1985
1986	user_debug_finish_after_exec();
1987
1988	// rename the team
1989
1990	team->Lock();
1991	team->SetName(path);
1992	team->Unlock();
1993
1994	// cut the path from the team name and rename the main thread, too
1995	threadName = strrchr(path, '/');
1996	if (threadName != NULL)
1997		threadName++;
1998	else
1999		threadName = path;
2000	rename_thread(thread_get_current_thread_id(), threadName);
2001
2002	atomic_or(&team->flags, TEAM_FLAG_EXEC_DONE);
2003
2004	// Update user/group according to the executable's set-user/group-id
2005	// permission.
2006	update_set_id_user_and_group(team, path);
2007
2008	user_debug_team_exec();
2009
2010	// notify team listeners
2011	sNotificationService.Notify(TEAM_EXEC, team);
2012
2013	// get a user thread for the thread
2014	user_thread* userThread = team_allocate_user_thread(team);
2015		// cannot fail (the allocation for the team would have failed already)
2016	ThreadLocker currentThreadLocker(currentThread);
2017	currentThread->user_thread = userThread;
2018	currentThreadLocker.Unlock();
2019
2020	// create the user stack for the thread
2021	status = thread_create_user_stack(currentThread->team, currentThread, NULL,
2022		0, sizeof(user_space_program_args) + teamArgs->flat_args_size);
2023	if (status == B_OK) {
2024		// prepare the stack, load the runtime loader, and enter userspace
2025		team_create_thread_start(teamArgs);
2026			// does never return
2027	} else
2028		free_team_arg(teamArgs);
2029
2030	// Sorry, we have to kill ourselves, there is no way out anymore
2031	// (without any areas left and all that).
2032	exit_thread(status);
2033
2034	// We return a status here since the signal that is sent by the
2035	// call above is not immediately handled.
2036	return B_ERROR;
2037}
2038
2039
2040static thread_id
2041fork_team(void)
2042{
2043	Thread* parentThread = thread_get_current_thread();
2044	Team* parentTeam = parentThread->team;
2045	Team* team;
2046	arch_fork_arg* forkArgs;
2047	struct area_info info;
2048	thread_id threadID;
2049	status_t status;
2050	ssize_t areaCookie;
2051	bool teamLimitReached = false;
2052
2053	TRACE(("fork_team(): team %" B_PRId32 "\n", parentTeam->id));
2054
2055	if (parentTeam == team_get_kernel_team())
2056		return B_NOT_ALLOWED;
2057
2058	// create a new team
2059	// TODO: this is very similar to load_image_internal() - maybe we can do
2060	// something about it :)
2061
2062	// create the main thread object
2063	Thread* thread;
2064	status = Thread::Create(parentThread->name, thread);
2065	if (status != B_OK)
2066		return status;
2067	BReference<Thread> threadReference(thread, true);
2068
2069	// create the team object
2070	team = Team::Create(thread->id, NULL, false);
2071	if (team == NULL)
2072		return B_NO_MEMORY;
2073
2074	parentTeam->LockTeamAndProcessGroup();
2075	team->Lock();
2076
2077	team->SetName(parentTeam->Name());
2078	team->SetArgs(parentTeam->Args());
2079
2080	team->commpage_address = parentTeam->commpage_address;
2081
2082	// Inherit the parent's user/group.
2083	inherit_parent_user_and_group(team, parentTeam);
2084
2085	// inherit signal handlers
2086	team->InheritSignalActions(parentTeam);
2087
2088	team->Unlock();
2089	parentTeam->UnlockTeamAndProcessGroup();
2090
2091	// inherit some team debug flags
2092	team->debug_info.flags |= atomic_get(&parentTeam->debug_info.flags)
2093		& B_TEAM_DEBUG_INHERITED_FLAGS;
2094
2095	forkArgs = (arch_fork_arg*)malloc(sizeof(arch_fork_arg));
2096	if (forkArgs == NULL) {
2097		status = B_NO_MEMORY;
2098		goto err1;
2099	}
2100
2101	// create a new io_context for this team
2102	team->io_context = vfs_new_io_context(parentTeam->io_context, false);
2103	if (!team->io_context) {
2104		status = B_NO_MEMORY;
2105		goto err2;
2106	}
2107
2108	// duplicate the realtime sem context
2109	if (parentTeam->realtime_sem_context) {
2110		team->realtime_sem_context = clone_realtime_sem_context(
2111			parentTeam->realtime_sem_context);
2112		if (team->realtime_sem_context == NULL) {
2113			status = B_NO_MEMORY;
2114			goto err2;
2115		}
2116	}
2117
2118	// create an address space for this team
2119	status = VMAddressSpace::Create(team->id, USER_BASE, USER_SIZE, false,
2120		&team->address_space);
2121	if (status < B_OK)
2122		goto err3;
2123
2124	// copy all areas of the team
2125	// TODO: should be able to handle stack areas differently (ie. don't have
2126	// them copy-on-write)
2127
2128	areaCookie = 0;
2129	while (get_next_area_info(B_CURRENT_TEAM, &areaCookie, &info) == B_OK) {
2130		if (info.area == parentTeam->user_data_area) {
2131			// don't clone the user area; just create a new one
2132			status = create_team_user_data(team, info.address);
2133			if (status != B_OK)
2134				break;
2135
2136			thread->user_thread = team_allocate_user_thread(team);
2137		} else {
2138			void* address;
2139			area_id area = vm_copy_area(team->address_space->ID(), info.name,
2140				&address, B_CLONE_ADDRESS, info.protection, info.area);
2141			if (area < B_OK) {
2142				status = area;
2143				break;
2144			}
2145
2146			if (info.area == parentThread->user_stack_area)
2147				thread->user_stack_area = area;
2148		}
2149	}
2150
2151	if (status < B_OK)
2152		goto err4;
2153
2154	if (thread->user_thread == NULL) {
2155#if KDEBUG
2156		panic("user data area not found, parent area is %" B_PRId32,
2157			parentTeam->user_data_area);
2158#endif
2159		status = B_ERROR;
2160		goto err4;
2161	}
2162
2163	thread->user_stack_base = parentThread->user_stack_base;
2164	thread->user_stack_size = parentThread->user_stack_size;
2165	thread->user_local_storage = parentThread->user_local_storage;
2166	thread->sig_block_mask = parentThread->sig_block_mask;
2167	thread->signal_stack_base = parentThread->signal_stack_base;
2168	thread->signal_stack_size = parentThread->signal_stack_size;
2169	thread->signal_stack_enabled = parentThread->signal_stack_enabled;
2170
2171	arch_store_fork_frame(forkArgs);
2172
2173	// copy image list
2174	if (copy_images(parentTeam->id, team) != B_OK)
2175		goto err5;
2176
2177	// insert the team into its parent and the teams hash
2178	parentTeam->LockTeamAndProcessGroup();
2179	team->Lock();
2180
2181	{
2182		InterruptsWriteSpinLocker teamsLocker(sTeamHashLock);
2183
2184		sTeamHash.Insert(team);
2185		teamLimitReached = sUsedTeams >= sMaxTeams;
2186		if (!teamLimitReached)
2187			sUsedTeams++;
2188	}
2189
2190	insert_team_into_parent(parentTeam, team);
2191	insert_team_into_group(parentTeam->group, team);
2192
2193	team->Unlock();
2194	parentTeam->UnlockTeamAndProcessGroup();
2195
2196	// notify team listeners
2197	sNotificationService.Notify(TEAM_ADDED, team);
2198
2199	if (teamLimitReached) {
2200		status = B_NO_MORE_TEAMS;
2201		goto err6;
2202	}
2203
2204	// create the main thread
2205	{
2206		ThreadCreationAttributes threadCreationAttributes(NULL,
2207			parentThread->name, parentThread->priority, NULL, team->id, thread);
2208		threadCreationAttributes.forkArgs = forkArgs;
2209		threadCreationAttributes.flags |= THREAD_CREATION_FLAG_DEFER_SIGNALS;
2210		threadID = thread_create_thread(threadCreationAttributes, false);
2211		if (threadID < 0) {
2212			status = threadID;
2213			goto err6;
2214		}
2215	}
2216
2217	// notify the debugger
2218	user_debug_team_created(team->id);
2219
2220	T(TeamForked(threadID));
2221
2222	resume_thread(threadID);
2223	return threadID;
2224
2225err6:
2226	// Remove the team structure from the process group, the parent team, and
2227	// the team hash table and delete the team structure.
2228	parentTeam->LockTeamAndProcessGroup();
2229	team->Lock();
2230
2231	remove_team_from_group(team);
2232	remove_team_from_parent(team->parent, team);
2233
2234	team->Unlock();
2235	parentTeam->UnlockTeamAndProcessGroup();
2236
2237	{
2238		InterruptsWriteSpinLocker teamsLocker(sTeamHashLock);
2239		sTeamHash.Remove(team);
2240		if (!teamLimitReached)
2241			sUsedTeams--;
2242	}
2243
2244	sNotificationService.Notify(TEAM_REMOVED, team);
2245err5:
2246	remove_images(team);
2247err4:
2248	team->address_space->RemoveAndPut();
2249err3:
2250	delete_realtime_sem_context(team->realtime_sem_context);
2251err2:
2252	free(forkArgs);
2253err1:
2254	team->ReleaseReference();
2255
2256	return status;
2257}
2258
2259
2260/*!	Returns if the specified team \a parent has any children belonging to the
2261	process group with the specified ID \a groupID.
2262	The caller must hold \a parent's lock.
2263*/
2264static bool
2265has_children_in_group(Team* parent, pid_t groupID)
2266{
2267	for (Team* child = parent->children; child != NULL;
2268			child = child->siblings_next) {
2269		TeamLocker childLocker(child);
2270		if (child->group_id == groupID)
2271			return true;
2272	}
2273
2274	return false;
2275}
2276
2277
2278/*!	Returns the first job control entry from \a children, which matches \a id.
2279	\a id can be:
2280	- \code > 0 \endcode: Matching an entry with that team ID.
2281	- \code == -1 \endcode: Matching any entry.
2282	- \code < -1 \endcode: Matching any entry with a process group ID of \c -id.
2283	\c 0 is an invalid value for \a id.
2284
2285	The caller must hold the lock of the team that \a children belongs to.
2286
2287	\param children The job control entry list to check.
2288	\param id The match criterion.
2289	\return The first matching entry or \c NULL, if none matches.
2290*/
2291static job_control_entry*
2292get_job_control_entry(team_job_control_children& children, pid_t id)
2293{
2294	for (JobControlEntryList::Iterator it = children.entries.GetIterator();
2295		 job_control_entry* entry = it.Next();) {
2296
2297		if (id > 0) {
2298			if (entry->thread == id)
2299				return entry;
2300		} else if (id == -1) {
2301			return entry;
2302		} else {
2303			pid_t processGroup
2304				= (entry->team ? entry->team->group_id : entry->group_id);
2305			if (processGroup == -id)
2306				return entry;
2307		}
2308	}
2309
2310	return NULL;
2311}
2312
2313
2314/*!	Returns the first job control entry from one of team's dead, continued, or
2315	stopped children which matches \a id.
2316	\a id can be:
2317	- \code > 0 \endcode: Matching an entry with that team ID.
2318	- \code == -1 \endcode: Matching any entry.
2319	- \code < -1 \endcode: Matching any entry with a process group ID of \c -id.
2320	\c 0 is an invalid value for \a id.
2321
2322	The caller must hold \a team's lock.
2323
2324	\param team The team whose dead, stopped, and continued child lists shall be
2325		checked.
2326	\param id The match criterion.
2327	\param flags Specifies which children shall be considered. Dead children
2328		are considered when \a flags is ORed bitwise with \c WEXITED, stopped
2329		children are considered when \a flags is ORed bitwise with \c WUNTRACED
2330		or \c WSTOPPED, continued children when \a flags is ORed bitwise with
2331		\c WCONTINUED.
2332	\return The first matching entry or \c NULL, if none matches.
2333*/
2334static job_control_entry*
2335get_job_control_entry(Team* team, pid_t id, uint32 flags)
2336{
2337	job_control_entry* entry = NULL;
2338
2339	if ((flags & WEXITED) != 0)
2340		entry = get_job_control_entry(team->dead_children, id);
2341
2342	if (entry == NULL && (flags & WCONTINUED) != 0)
2343		entry = get_job_control_entry(team->continued_children, id);
2344
2345	if (entry == NULL && (flags & (WUNTRACED | WSTOPPED)) != 0)
2346		entry = get_job_control_entry(team->stopped_children, id);
2347
2348	return entry;
2349}
2350
2351
2352job_control_entry::job_control_entry()
2353	:
2354	has_group_ref(false)
2355{
2356}
2357
2358
2359job_control_entry::~job_control_entry()
2360{
2361	if (has_group_ref) {
2362		InterruptsSpinLocker groupHashLocker(sGroupHashLock);
2363
2364		ProcessGroup* group = sGroupHash.Lookup(group_id);
2365		if (group == NULL) {
2366			panic("job_control_entry::~job_control_entry(): unknown group "
2367				"ID: %" B_PRId32, group_id);
2368			return;
2369		}
2370
2371		groupHashLocker.Unlock();
2372
2373		group->ReleaseReference();
2374	}
2375}
2376
2377
2378/*!	Invoked when the owning team is dying, initializing the entry according to
2379	the dead state.
2380
2381	The caller must hold the owning team's lock and the scheduler lock.
2382*/
2383void
2384job_control_entry::InitDeadState()
2385{
2386	if (team != NULL) {
2387		ASSERT(team->exit.initialized);
2388
2389		group_id = team->group_id;
2390		team->group->AcquireReference();
2391		has_group_ref = true;
2392
2393		thread = team->id;
2394		status = team->exit.status;
2395		reason = team->exit.reason;
2396		signal = team->exit.signal;
2397		signaling_user = team->exit.signaling_user;
2398		user_time = team->dead_threads_user_time
2399			+ team->dead_children.user_time;
2400		kernel_time = team->dead_threads_kernel_time
2401			+ team->dead_children.kernel_time;
2402
2403		team = NULL;
2404	}
2405}
2406
2407
2408job_control_entry&
2409job_control_entry::operator=(const job_control_entry& other)
2410{
2411	state = other.state;
2412	thread = other.thread;
2413	signal = other.signal;
2414	has_group_ref = false;
2415	signaling_user = other.signaling_user;
2416	team = other.team;
2417	group_id = other.group_id;
2418	status = other.status;
2419	reason = other.reason;
2420	user_time = other.user_time;
2421	kernel_time = other.kernel_time;
2422
2423	return *this;
2424}
2425
2426
2427/*! This is the kernel backend for waitid().
2428*/
2429static thread_id
2430wait_for_child(pid_t child, uint32 flags, siginfo_t& _info,
2431	team_usage_info& _usage_info)
2432{
2433	Thread* thread = thread_get_current_thread();
2434	Team* team = thread->team;
2435	struct job_control_entry foundEntry;
2436	struct job_control_entry* freeDeathEntry = NULL;
2437	status_t status = B_OK;
2438
2439	TRACE(("wait_for_child(child = %" B_PRId32 ", flags = %" B_PRId32 ")\n",
2440		child, flags));
2441
2442	T(WaitForChild(child, flags));
2443
2444	if ((flags & (WEXITED | WUNTRACED | WSTOPPED | WCONTINUED)) == 0) {
2445		T(WaitForChildDone(B_BAD_VALUE));
2446		return B_BAD_VALUE;
2447	}
2448
2449	pid_t originalChild = child;
2450
2451	bool ignoreFoundEntries = false;
2452	bool ignoreFoundEntriesChecked = false;
2453
2454	while (true) {
2455		// lock the team
2456		TeamLocker teamLocker(team);
2457
2458		// A 0 child argument means to wait for all children in the process
2459		// group of the calling team.
2460		child = originalChild == 0 ? -team->group_id : originalChild;
2461
2462		// check whether any condition holds
2463		job_control_entry* entry = get_job_control_entry(team, child, flags);
2464
2465		// If we don't have an entry yet, check whether there are any children
2466		// complying to the process group specification at all.
2467		if (entry == NULL) {
2468			// No success yet -- check whether there are any children complying
2469			// to the process group specification at all.
2470			bool childrenExist = false;
2471			if (child == -1) {
2472				childrenExist = team->children != NULL;
2473			} else if (child < -1) {
2474				childrenExist = has_children_in_group(team, -child);
2475			} else if (child != team->id) {
2476				if (Team* childTeam = Team::Get(child)) {
2477					BReference<Team> childTeamReference(childTeam, true);
2478					TeamLocker childTeamLocker(childTeam);
2479					childrenExist = childTeam->parent == team;
2480				}
2481			}
2482
2483			if (!childrenExist) {
2484				// there is no child we could wait for
2485				status = ECHILD;
2486			} else {
2487				// the children we're waiting for are still running
2488				status = B_WOULD_BLOCK;
2489			}
2490		} else {
2491			// got something
2492			foundEntry = *entry;
2493
2494			// unless WNOWAIT has been specified, "consume" the wait state
2495			if ((flags & WNOWAIT) == 0 || ignoreFoundEntries) {
2496				if (entry->state == JOB_CONTROL_STATE_DEAD) {
2497					// The child is dead. Reap its death entry.
2498					freeDeathEntry = entry;
2499					team->dead_children.entries.Remove(entry);
2500					team->dead_children.count--;
2501				} else {
2502					// The child is well. Reset its job control state.
2503					team_set_job_control_state(entry->team,
2504						JOB_CONTROL_STATE_NONE, NULL);
2505				}
2506			}
2507		}
2508
2509		// If we haven't got anything yet, prepare for waiting for the
2510		// condition variable.
2511		ConditionVariableEntry deadWaitEntry;
2512
2513		if (status == B_WOULD_BLOCK && (flags & WNOHANG) == 0)
2514			team->dead_children.condition_variable.Add(&deadWaitEntry);
2515
2516		teamLocker.Unlock();
2517
2518		// we got our entry and can return to our caller
2519		if (status == B_OK) {
2520			if (ignoreFoundEntries) {
2521				// ... unless we shall ignore found entries
2522				delete freeDeathEntry;
2523				freeDeathEntry = NULL;
2524				continue;
2525			}
2526
2527			break;
2528		}
2529
2530		if (status != B_WOULD_BLOCK || (flags & WNOHANG) != 0) {
2531			T(WaitForChildDone(status));
2532			return status;
2533		}
2534
2535		status = deadWaitEntry.Wait(B_CAN_INTERRUPT);
2536		if (status == B_INTERRUPTED) {
2537			T(WaitForChildDone(status));
2538			return status;
2539		}
2540
2541		// If SA_NOCLDWAIT is set or SIGCHLD is ignored, we shall wait until
2542		// all our children are dead and fail with ECHILD. We check the
2543		// condition at this point.
2544		if (!ignoreFoundEntriesChecked) {
2545			teamLocker.Lock();
2546
2547			struct sigaction& handler = team->SignalActionFor(SIGCHLD);
2548			if ((handler.sa_flags & SA_NOCLDWAIT) != 0
2549				|| handler.sa_handler == SIG_IGN) {
2550				ignoreFoundEntries = true;
2551			}
2552
2553			teamLocker.Unlock();
2554
2555			ignoreFoundEntriesChecked = true;
2556		}
2557	}
2558
2559	delete freeDeathEntry;
2560
2561	// When we got here, we have a valid death entry, and already got
2562	// unregistered from the team or group. Fill in the returned info.
2563	memset(&_info, 0, sizeof(_info));
2564	_info.si_signo = SIGCHLD;
2565	_info.si_pid = foundEntry.thread;
2566	_info.si_uid = foundEntry.signaling_user;
2567	// TODO: Fill in si_errno?
2568
2569	switch (foundEntry.state) {
2570		case JOB_CONTROL_STATE_DEAD:
2571			_info.si_code = foundEntry.reason;
2572			_info.si_status = foundEntry.reason == CLD_EXITED
2573				? foundEntry.status : foundEntry.signal;
2574			_usage_info.user_time = foundEntry.user_time;
2575			_usage_info.kernel_time = foundEntry.kernel_time;
2576			break;
2577		case JOB_CONTROL_STATE_STOPPED:
2578			_info.si_code = CLD_STOPPED;
2579			_info.si_status = foundEntry.signal;
2580			break;
2581		case JOB_CONTROL_STATE_CONTINUED:
2582			_info.si_code = CLD_CONTINUED;
2583			_info.si_status = 0;
2584			break;
2585		case JOB_CONTROL_STATE_NONE:
2586			// can't happen
2587			break;
2588	}
2589
2590	// If SIGCHLD is blocked, we shall clear pending SIGCHLDs, if no other child
2591	// status is available.
2592	TeamLocker teamLocker(team);
2593	InterruptsSpinLocker signalLocker(team->signal_lock);
2594	SpinLocker threadCreationLocker(gThreadCreationLock);
2595
2596	if (is_team_signal_blocked(team, SIGCHLD)) {
2597		if (get_job_control_entry(team, child, flags) == NULL)
2598			team->RemovePendingSignals(SIGNAL_TO_MASK(SIGCHLD));
2599	}
2600
2601	threadCreationLocker.Unlock();
2602	signalLocker.Unlock();
2603	teamLocker.Unlock();
2604
2605	// When the team is dead, the main thread continues to live in the kernel
2606	// team for a very short time. To avoid surprises for the caller we rather
2607	// wait until the thread is really gone.
2608	if (foundEntry.state == JOB_CONTROL_STATE_DEAD)
2609		wait_for_thread(foundEntry.thread, NULL);
2610
2611	T(WaitForChildDone(foundEntry));
2612
2613	return foundEntry.thread;
2614}
2615
2616
2617/*! Fills the team_info structure with information from the specified team.
2618	Interrupts must be enabled. The team must not be locked.
2619*/
2620static status_t
2621fill_team_info(Team* team, team_info* info, size_t size)
2622{
2623	if (size != sizeof(team_info))
2624		return B_BAD_VALUE;
2625
2626	// TODO: Set more informations for team_info
2627	memset(info, 0, size);
2628
2629	info->team = team->id;
2630		// immutable
2631	info->image_count = count_images(team);
2632		// protected by sImageMutex
2633
2634	TeamLocker teamLocker(team);
2635	InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
2636
2637	info->thread_count = team->num_threads;
2638	//info->area_count =
2639	info->debugger_nub_thread = team->debug_info.nub_thread;
2640	info->debugger_nub_port = team->debug_info.nub_port;
2641	info->uid = team->effective_uid;
2642	info->gid = team->effective_gid;
2643
2644	strlcpy(info->args, team->Args(), sizeof(info->args));
2645	info->argc = 1;
2646
2647	return B_OK;
2648}
2649
2650
2651/*!	Returns whether the process group contains stopped processes.
2652	The caller must hold the process group's lock.
2653*/
2654static bool
2655process_group_has_stopped_processes(ProcessGroup* group)
2656{
2657	Team* team = group->teams;
2658	while (team != NULL) {
2659		// the parent team's lock guards the job control entry -- acquire it
2660		team->LockTeamAndParent(false);
2661
2662		if (team->job_control_entry != NULL
2663			&& team->job_control_entry->state == JOB_CONTROL_STATE_STOPPED) {
2664			team->UnlockTeamAndParent();
2665			return true;
2666		}
2667
2668		team->UnlockTeamAndParent();
2669
2670		team = team->group_next;
2671	}
2672
2673	return false;
2674}
2675
2676
2677/*!	Iterates through all process groups queued in team_remove_team() and signals
2678	those that are orphaned and have stopped processes.
2679	The caller must not hold any team or process group locks.
2680*/
2681static void
2682orphaned_process_group_check()
2683{
2684	// process as long as there are groups in the list
2685	while (true) {
2686		// remove the head from the list
2687		MutexLocker orphanedCheckLocker(sOrphanedCheckLock);
2688
2689		ProcessGroup* group = sOrphanedCheckProcessGroups.RemoveHead();
2690		if (group == NULL)
2691			return;
2692
2693		group->UnsetOrphanedCheck();
2694		BReference<ProcessGroup> groupReference(group);
2695
2696		orphanedCheckLocker.Unlock();
2697
2698		AutoLocker<ProcessGroup> groupLocker(group);
2699
2700		// If the group is orphaned and contains stopped processes, we're
2701		// supposed to send SIGHUP + SIGCONT.
2702		if (group->IsOrphaned() && process_group_has_stopped_processes(group)) {
2703			Thread* currentThread = thread_get_current_thread();
2704
2705			Signal signal(SIGHUP, SI_USER, B_OK, currentThread->team->id);
2706			send_signal_to_process_group_locked(group, signal, 0);
2707
2708			signal.SetNumber(SIGCONT);
2709			send_signal_to_process_group_locked(group, signal, 0);
2710		}
2711	}
2712}
2713
2714
2715static status_t
2716common_get_team_usage_info(team_id id, int32 who, team_usage_info* info,
2717	uint32 flags)
2718{
2719	if (who != B_TEAM_USAGE_SELF && who != B_TEAM_USAGE_CHILDREN)
2720		return B_BAD_VALUE;
2721
2722	// get the team
2723	Team* team = Team::GetAndLock(id);
2724	if (team == NULL)
2725		return B_BAD_TEAM_ID;
2726	BReference<Team> teamReference(team, true);
2727	TeamLocker teamLocker(team, true);
2728
2729	if ((flags & B_CHECK_PERMISSION) != 0) {
2730		uid_t uid = geteuid();
2731		if (uid != 0 && uid != team->effective_uid)
2732			return B_NOT_ALLOWED;
2733	}
2734
2735	bigtime_t kernelTime = 0;
2736	bigtime_t userTime = 0;
2737
2738	switch (who) {
2739		case B_TEAM_USAGE_SELF:
2740		{
2741			Thread* thread = team->thread_list;
2742
2743			for (; thread != NULL; thread = thread->team_next) {
2744				InterruptsSpinLocker threadTimeLocker(thread->time_lock);
2745				kernelTime += thread->kernel_time;
2746				userTime += thread->user_time;
2747			}
2748
2749			kernelTime += team->dead_threads_kernel_time;
2750			userTime += team->dead_threads_user_time;
2751			break;
2752		}
2753
2754		case B_TEAM_USAGE_CHILDREN:
2755		{
2756			Team* child = team->children;
2757			for (; child != NULL; child = child->siblings_next) {
2758				TeamLocker childLocker(child);
2759
2760				Thread* thread = team->thread_list;
2761
2762				for (; thread != NULL; thread = thread->team_next) {
2763					InterruptsSpinLocker threadTimeLocker(thread->time_lock);
2764					kernelTime += thread->kernel_time;
2765					userTime += thread->user_time;
2766				}
2767
2768				kernelTime += child->dead_threads_kernel_time;
2769				userTime += child->dead_threads_user_time;
2770			}
2771
2772			kernelTime += team->dead_children.kernel_time;
2773			userTime += team->dead_children.user_time;
2774			break;
2775		}
2776	}
2777
2778	info->kernel_time = kernelTime;
2779	info->user_time = userTime;
2780
2781	return B_OK;
2782}
2783
2784
2785//	#pragma mark - Private kernel API
2786
2787
2788status_t
2789team_init(kernel_args* args)
2790{
2791	// create the team hash table
2792	new(&sTeamHash) TeamTable;
2793	if (sTeamHash.Init(64) != B_OK)
2794		panic("Failed to init team hash table!");
2795
2796	new(&sGroupHash) ProcessGroupHashTable;
2797	if (sGroupHash.Init() != B_OK)
2798		panic("Failed to init process group hash table!");
2799
2800	// create initial session and process groups
2801
2802	ProcessSession* session = new(std::nothrow) ProcessSession(1);
2803	if (session == NULL)
2804		panic("Could not create initial session.\n");
2805	BReference<ProcessSession> sessionReference(session, true);
2806
2807	ProcessGroup* group = new(std::nothrow) ProcessGroup(1);
2808	if (group == NULL)
2809		panic("Could not create initial process group.\n");
2810	BReference<ProcessGroup> groupReference(group, true);
2811
2812	group->Publish(session);
2813
2814	// create the kernel team
2815	sKernelTeam = Team::Create(1, "kernel_team", true);
2816	if (sKernelTeam == NULL)
2817		panic("could not create kernel team!\n");
2818	sKernelTeam->SetArgs(sKernelTeam->Name());
2819	sKernelTeam->state = TEAM_STATE_NORMAL;
2820
2821	sKernelTeam->saved_set_uid = 0;
2822	sKernelTeam->real_uid = 0;
2823	sKernelTeam->effective_uid = 0;
2824	sKernelTeam->saved_set_gid = 0;
2825	sKernelTeam->real_gid = 0;
2826	sKernelTeam->effective_gid = 0;
2827	sKernelTeam->supplementary_groups = NULL;
2828	sKernelTeam->supplementary_group_count = 0;
2829
2830	insert_team_into_group(group, sKernelTeam);
2831
2832	sKernelTeam->io_context = vfs_new_io_context(NULL, false);
2833	if (sKernelTeam->io_context == NULL)
2834		panic("could not create io_context for kernel team!\n");
2835
2836	if (vfs_resize_fd_table(sKernelTeam->io_context, 4096) != B_OK)
2837		dprintf("Failed to resize FD table for kernel team!\n");
2838
2839	// stick it in the team hash
2840	sTeamHash.Insert(sKernelTeam);
2841
2842	// check safe mode settings
2843	sDisableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS,
2844		false);
2845
2846	add_debugger_command_etc("team", &dump_team_info,
2847		"Dump info about a particular team",
2848		"[ <id> | <address> | <name> ]\n"
2849		"Prints information about the specified team. If no argument is given\n"
2850		"the current team is selected.\n"
2851		"  <id>       - The ID of the team.\n"
2852		"  <address>  - The address of the team structure.\n"
2853		"  <name>     - The team's name.\n", 0);
2854	add_debugger_command_etc("teams", &dump_teams, "List all teams",
2855		"\n"
2856		"Prints a list of all existing teams.\n", 0);
2857
2858	new(&sNotificationService) TeamNotificationService();
2859
2860	sNotificationService.Register();
2861
2862	return B_OK;
2863}
2864
2865
2866int32
2867team_max_teams(void)
2868{
2869	return sMaxTeams;
2870}
2871
2872
2873int32
2874team_used_teams(void)
2875{
2876	InterruptsReadSpinLocker teamsLocker(sTeamHashLock);
2877	return sUsedTeams;
2878}
2879
2880
2881/*! Returns a death entry of a child team specified by ID (if any).
2882	The caller must hold the team's lock.
2883
2884	\param team The team whose dead children list to check.
2885	\param child The ID of the child for whose death entry to lock. Must be > 0.
2886	\param _deleteEntry Return variable, indicating whether the caller needs to
2887		delete the returned entry.
2888	\return The death entry of the matching team, or \c NULL, if no death entry
2889		for the team was found.
2890*/
2891job_control_entry*
2892team_get_death_entry(Team* team, thread_id child, bool* _deleteEntry)
2893{
2894	if (child <= 0)
2895		return NULL;
2896
2897	job_control_entry* entry = get_job_control_entry(team->dead_children,
2898		child);
2899	if (entry) {
2900		// remove the entry only, if the caller is the parent of the found team
2901		if (team_get_current_team_id() == entry->thread) {
2902			team->dead_children.entries.Remove(entry);
2903			team->dead_children.count--;
2904			*_deleteEntry = true;
2905		} else {
2906			*_deleteEntry = false;
2907		}
2908	}
2909
2910	return entry;
2911}
2912
2913
2914/*! Quick check to see if we have a valid team ID. */
2915bool
2916team_is_valid(team_id id)
2917{
2918	if (id <= 0)
2919		return false;
2920
2921	InterruptsReadSpinLocker teamsLocker(sTeamHashLock);
2922	return team_get_team_struct_locked(id) != NULL;
2923}
2924
2925
2926Team*
2927team_get_team_struct_locked(team_id id)
2928{
2929	return sTeamHash.Lookup(id);
2930}
2931
2932
2933void
2934team_set_controlling_tty(int32 ttyIndex)
2935{
2936	// lock the team, so its session won't change while we're playing with it
2937	Team* team = thread_get_current_thread()->team;
2938	TeamLocker teamLocker(team);
2939
2940	// get and lock the session
2941	ProcessSession* session = team->group->Session();
2942	AutoLocker<ProcessSession> sessionLocker(session);
2943
2944	// set the session's fields
2945	session->controlling_tty = ttyIndex;
2946	session->foreground_group = -1;
2947}
2948
2949
2950int32
2951team_get_controlling_tty()
2952{
2953	// lock the team, so its session won't change while we're playing with it
2954	Team* team = thread_get_current_thread()->team;
2955	TeamLocker teamLocker(team);
2956
2957	// get and lock the session
2958	ProcessSession* session = team->group->Session();
2959	AutoLocker<ProcessSession> sessionLocker(session);
2960
2961	// get the session's field
2962	return session->controlling_tty;
2963}
2964
2965
2966status_t
2967team_set_foreground_process_group(int32 ttyIndex, pid_t processGroupID)
2968{
2969	// lock the team, so its session won't change while we're playing with it
2970	Thread* thread = thread_get_current_thread();
2971	Team* team = thread->team;
2972	TeamLocker teamLocker(team);
2973
2974	// get and lock the session
2975	ProcessSession* session = team->group->Session();
2976	AutoLocker<ProcessSession> sessionLocker(session);
2977
2978	// check given TTY -- must be the controlling tty of the calling process
2979	if (session->controlling_tty != ttyIndex)
2980		return ENOTTY;
2981
2982	// check given process group -- must belong to our session
2983	{
2984		InterruptsSpinLocker groupHashLocker(sGroupHashLock);
2985		ProcessGroup* group = sGroupHash.Lookup(processGroupID);
2986		if (group == NULL || group->Session() != session)
2987			return B_BAD_VALUE;
2988	}
2989
2990	// If we are a background group, we can do that unharmed only when we
2991	// ignore or block SIGTTOU. Otherwise the group gets a SIGTTOU.
2992	if (session->foreground_group != -1
2993		&& session->foreground_group != team->group_id
2994		&& team->SignalActionFor(SIGTTOU).sa_handler != SIG_IGN
2995		&& (thread->sig_block_mask & SIGNAL_TO_MASK(SIGTTOU)) == 0) {
2996		InterruptsSpinLocker signalLocker(team->signal_lock);
2997
2998		if (!is_team_signal_blocked(team, SIGTTOU)) {
2999			pid_t groupID = team->group_id;
3000
3001			signalLocker.Unlock();
3002			sessionLocker.Unlock();
3003			teamLocker.Unlock();
3004
3005			Signal signal(SIGTTOU, SI_USER, B_OK, team->id);
3006			send_signal_to_process_group(groupID, signal, 0);
3007			return B_INTERRUPTED;
3008		}
3009	}
3010
3011	session->foreground_group = processGroupID;
3012
3013	return B_OK;
3014}
3015
3016
3017uid_t
3018team_geteuid(team_id id)
3019{
3020	InterruptsReadSpinLocker teamsLocker(sTeamHashLock);
3021	Team* team = team_get_team_struct_locked(id);
3022	if (team == NULL)
3023		return (uid_t)-1;
3024	return team->effective_uid;
3025}
3026
3027
3028/*!	Removes the specified team from the global team hash, from its process
3029	group, and from its parent.
3030	It also moves all of its children to the kernel team.
3031
3032	The caller must hold the following locks:
3033	- \a team's process group's lock,
3034	- the kernel team's lock,
3035	- \a team's parent team's lock (might be the kernel team), and
3036	- \a team's lock.
3037*/
3038void
3039team_remove_team(Team* team, pid_t& _signalGroup)
3040{
3041	Team* parent = team->parent;
3042
3043	// remember how long this team lasted
3044	parent->dead_children.kernel_time += team->dead_threads_kernel_time
3045		+ team->dead_children.kernel_time;
3046	parent->dead_children.user_time += team->dead_threads_user_time
3047		+ team->dead_children.user_time;
3048
3049	// remove the team from the hash table
3050	InterruptsWriteSpinLocker teamsLocker(sTeamHashLock);
3051	sTeamHash.Remove(team);
3052	sUsedTeams--;
3053	teamsLocker.Unlock();
3054
3055	// The team can no longer be accessed by ID. Navigation to it is still
3056	// possible from its process group and its parent and children, but that
3057	// will be rectified shortly.
3058	team->state = TEAM_STATE_DEATH;
3059
3060	// If we're a controlling process (i.e. a session leader with controlling
3061	// terminal), there's a bit of signalling we have to do. We can't do any of
3062	// the signaling here due to the bunch of locks we're holding, but we need
3063	// to determine, whom to signal.
3064	_signalGroup = -1;
3065	bool isSessionLeader = false;
3066	if (team->session_id == team->id
3067		&& team->group->Session()->controlling_tty >= 0) {
3068		isSessionLeader = true;
3069
3070		ProcessSession* session = team->group->Session();
3071
3072		AutoLocker<ProcessSession> sessionLocker(session);
3073
3074		session->controlling_tty = -1;
3075		_signalGroup = session->foreground_group;
3076	}
3077
3078	// remove us from our process group
3079	remove_team_from_group(team);
3080
3081	// move the team's children to the kernel team
3082	while (Team* child = team->children) {
3083		// remove the child from the current team and add it to the kernel team
3084		TeamLocker childLocker(child);
3085
3086		remove_team_from_parent(team, child);
3087		insert_team_into_parent(sKernelTeam, child);
3088
3089		// move job control entries too
3090		sKernelTeam->stopped_children.entries.MoveFrom(
3091			&team->stopped_children.entries);
3092		sKernelTeam->continued_children.entries.MoveFrom(
3093			&team->continued_children.entries);
3094
3095		// If the team was a session leader with controlling terminal,
3096		// we need to send SIGHUP + SIGCONT to all newly-orphaned process
3097		// groups with stopped processes. Due to locking complications we can't
3098		// do that here, so we only check whether we were a reason for the
3099		// child's process group not being an orphan and, if so, schedule a
3100		// later check (cf. orphaned_process_group_check()).
3101		if (isSessionLeader) {
3102			ProcessGroup* childGroup = child->group;
3103			if (childGroup->Session()->id == team->session_id
3104				&& childGroup->id != team->group_id) {
3105				childGroup->ScheduleOrphanedCheck();
3106			}
3107		}
3108
3109		// Note, we don't move the dead children entries. Those will be deleted
3110		// when the team structure is deleted.
3111	}
3112
3113	// remove us from our parent
3114	remove_team_from_parent(parent, team);
3115}
3116
3117
3118/*!	Kills all threads but the main thread of the team and shuts down user
3119	debugging for it.
3120	To be called on exit of the team's main thread. No locks must be held.
3121
3122	\param team The team in question.
3123	\return The port of the debugger for the team, -1 if none. To be passed to
3124		team_delete_team().
3125*/
3126port_id
3127team_shutdown_team(Team* team)
3128{
3129	ASSERT(thread_get_current_thread() == team->main_thread);
3130
3131	TeamLocker teamLocker(team);
3132
3133	// Make sure debugging changes won't happen anymore.
3134	port_id debuggerPort = -1;
3135	while (true) {
3136		// If a debugger change is in progress for the team, we'll have to
3137		// wait until it is done.
3138		ConditionVariableEntry waitForDebuggerEntry;
3139		bool waitForDebugger = false;
3140
3141		InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
3142
3143		if (team->debug_info.debugger_changed_condition != NULL) {
3144			team->debug_info.debugger_changed_condition->Add(
3145				&waitForDebuggerEntry);
3146			waitForDebugger = true;
3147		} else if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
3148			// The team is being debugged. That will stop with the termination
3149			// of the nub thread. Since we set the team state to death, no one
3150			// can install a debugger anymore. We fetch the debugger's port to
3151			// send it a message at the bitter end.
3152			debuggerPort = team->debug_info.debugger_port;
3153		}
3154
3155		debugInfoLocker.Unlock();
3156
3157		if (!waitForDebugger)
3158			break;
3159
3160		// wait for the debugger change to be finished
3161		teamLocker.Unlock();
3162
3163		waitForDebuggerEntry.Wait();
3164
3165		teamLocker.Lock();
3166	}
3167
3168	// Mark the team as shutting down. That will prevent new threads from being
3169	// created and debugger changes from taking place.
3170	team->state = TEAM_STATE_SHUTDOWN;
3171
3172	// delete all timers
3173	team->DeleteUserTimers(false);
3174
3175	// deactivate CPU time user timers for the team
3176	InterruptsSpinLocker timeLocker(team->time_lock);
3177
3178	if (team->HasActiveCPUTimeUserTimers())
3179		team->DeactivateCPUTimeUserTimers();
3180
3181	timeLocker.Unlock();
3182
3183	// kill all threads but the main thread
3184	team_death_entry deathEntry;
3185	deathEntry.condition.Init(team, "team death");
3186
3187	while (true) {
3188		team->death_entry = &deathEntry;
3189		deathEntry.remaining_threads = 0;
3190
3191		Thread* thread = team->thread_list;
3192		while (thread != NULL) {
3193			if (thread != team->main_thread) {
3194				Signal signal(SIGKILLTHR, SI_USER, B_OK, team->id);
3195				send_signal_to_thread(thread, signal, B_DO_NOT_RESCHEDULE);
3196				deathEntry.remaining_threads++;
3197			}
3198
3199			thread = thread->team_next;
3200		}
3201
3202		if (deathEntry.remaining_threads == 0)
3203			break;
3204
3205		// there are threads to wait for
3206		ConditionVariableEntry entry;
3207		deathEntry.condition.Add(&entry);
3208
3209		teamLocker.Unlock();
3210
3211		entry.Wait();
3212
3213		teamLocker.Lock();
3214	}
3215
3216	team->death_entry = NULL;
3217
3218	return debuggerPort;
3219}
3220
3221
3222/*!	Called on team exit to notify threads waiting on the team and free most
3223	resources associated with it.
3224	The caller shouldn't hold any locks.
3225*/
3226void
3227team_delete_team(Team* team, port_id debuggerPort)
3228{
3229	// Not quite in our job description, but work that has been left by
3230	// team_remove_team() and that can be done now that we're not holding any
3231	// locks.
3232	orphaned_process_group_check();
3233
3234	team_id teamID = team->id;
3235
3236	ASSERT(team->num_threads == 0);
3237
3238	// If someone is waiting for this team to be loaded, but it dies
3239	// unexpectedly before being done, we need to notify the waiting
3240	// thread now.
3241
3242	TeamLocker teamLocker(team);
3243
3244	if (team->loading_info) {
3245		// there's indeed someone waiting
3246		struct team_loading_info* loadingInfo = team->loading_info;
3247		team->loading_info = NULL;
3248
3249		loadingInfo->result = B_ERROR;
3250
3251		// wake up the waiting thread
3252		loadingInfo->condition.NotifyAll();
3253	}
3254
3255	// notify team watchers
3256
3257	{
3258		// we're not reachable from anyone anymore at this point, so we
3259		// can safely access the list without any locking
3260		struct team_watcher* watcher;
3261		while ((watcher = (struct team_watcher*)list_remove_head_item(
3262				&team->watcher_list)) != NULL) {
3263			watcher->hook(teamID, watcher->data);
3264			free(watcher);
3265		}
3266	}
3267
3268	teamLocker.Unlock();
3269
3270	sNotificationService.Notify(TEAM_REMOVED, team);
3271
3272	// free team resources
3273
3274	delete_realtime_sem_context(team->realtime_sem_context);
3275	xsi_sem_undo(team);
3276	remove_images(team);
3277	team->address_space->RemoveAndPut();
3278
3279	team->ReleaseReference();
3280
3281	// notify the debugger, that the team is gone
3282	user_debug_team_deleted(teamID, debuggerPort);
3283}
3284
3285
3286Team*
3287team_get_kernel_team(void)
3288{
3289	return sKernelTeam;
3290}
3291
3292
3293team_id
3294team_get_kernel_team_id(void)
3295{
3296	if (!sKernelTeam)
3297		return 0;
3298
3299	return sKernelTeam->id;
3300}
3301
3302
3303team_id
3304team_get_current_team_id(void)
3305{
3306	return thread_get_current_thread()->team->id;
3307}
3308
3309
3310status_t
3311team_get_address_space(team_id id, VMAddressSpace** _addressSpace)
3312{
3313	if (id == sKernelTeam->id) {
3314		// we're the kernel team, so we don't have to go through all
3315		// the hassle (locking and hash lookup)
3316		*_addressSpace = VMAddressSpace::GetKernel();
3317		return B_OK;
3318	}
3319
3320	InterruptsReadSpinLocker teamsLocker(sTeamHashLock);
3321
3322	Team* team = team_get_team_struct_locked(id);
3323	if (team == NULL)
3324		return B_BAD_VALUE;
3325
3326	team->address_space->Get();
3327	*_addressSpace = team->address_space;
3328	return B_OK;
3329}
3330
3331
3332/*!	Sets the team's job control state.
3333	The caller must hold the parent team's lock. Interrupts are allowed to be
3334	enabled or disabled.
3335	\a team The team whose job control state shall be set.
3336	\a newState The new state to be set.
3337	\a signal The signal the new state was caused by. Can \c NULL, if none. Then
3338		the caller is responsible for filling in the following fields of the
3339		entry before releasing the parent team's lock, unless the new state is
3340		\c JOB_CONTROL_STATE_NONE:
3341		- \c signal: The number of the signal causing the state change.
3342		- \c signaling_user: The real UID of the user sending the signal.
3343*/
3344void
3345team_set_job_control_state(Team* team, job_control_state newState,
3346	Signal* signal)
3347{
3348	if (team == NULL || team->job_control_entry == NULL)
3349		return;
3350
3351	// don't touch anything, if the state stays the same or the team is already
3352	// dead
3353	job_control_entry* entry = team->job_control_entry;
3354	if (entry->state == newState || entry->state == JOB_CONTROL_STATE_DEAD)
3355		return;
3356
3357	T(SetJobControlState(team->id, newState, signal));
3358
3359	// remove from the old list
3360	switch (entry->state) {
3361		case JOB_CONTROL_STATE_NONE:
3362			// entry is in no list ATM
3363			break;
3364		case JOB_CONTROL_STATE_DEAD:
3365			// can't get here
3366			break;
3367		case JOB_CONTROL_STATE_STOPPED:
3368			team->parent->stopped_children.entries.Remove(entry);
3369			break;
3370		case JOB_CONTROL_STATE_CONTINUED:
3371			team->parent->continued_children.entries.Remove(entry);
3372			break;
3373	}
3374
3375	entry->state = newState;
3376
3377	if (signal != NULL) {
3378		entry->signal = signal->Number();
3379		entry->signaling_user = signal->SendingUser();
3380	}
3381
3382	// add to new list
3383	team_job_control_children* childList = NULL;
3384	switch (entry->state) {
3385		case JOB_CONTROL_STATE_NONE:
3386			// entry doesn't get into any list
3387			break;
3388		case JOB_CONTROL_STATE_DEAD:
3389			childList = &team->parent->dead_children;
3390			team->parent->dead_children.count++;
3391			break;
3392		case JOB_CONTROL_STATE_STOPPED:
3393			childList = &team->parent->stopped_children;
3394			break;
3395		case JOB_CONTROL_STATE_CONTINUED:
3396			childList = &team->parent->continued_children;
3397			break;
3398	}
3399
3400	if (childList != NULL) {
3401		childList->entries.Add(entry);
3402		team->parent->dead_children.condition_variable.NotifyAll();
3403	}
3404}
3405
3406
3407/*!	Inits the given team's exit information, if not yet initialized, to some
3408	generic "killed" status.
3409	The caller must not hold the team's lock. Interrupts must be enabled.
3410
3411	\param team The team whose exit info shall be initialized.
3412*/
3413void
3414team_init_exit_info_on_error(Team* team)
3415{
3416	TeamLocker teamLocker(team);
3417
3418	if (!team->exit.initialized) {
3419		team->exit.reason = CLD_KILLED;
3420		team->exit.signal = SIGKILL;
3421		team->exit.signaling_user = geteuid();
3422		team->exit.status = 0;
3423		team->exit.initialized = true;
3424	}
3425}
3426
3427
3428/*! Adds a hook to the team that is called as soon as this team goes away.
3429	This call might get public in the future.
3430*/
3431status_t
3432start_watching_team(team_id teamID, void (*hook)(team_id, void*), void* data)
3433{
3434	if (hook == NULL || teamID < B_OK)
3435		return B_BAD_VALUE;
3436
3437	// create the watcher object
3438	team_watcher* watcher = (team_watcher*)malloc(sizeof(team_watcher));
3439	if (watcher == NULL)
3440		return B_NO_MEMORY;
3441
3442	watcher->hook = hook;
3443	watcher->data = data;
3444
3445	// add watcher, if the team isn't already dying
3446	// get the team
3447	Team* team = Team::GetAndLock(teamID);
3448	if (team == NULL) {
3449		free(watcher);
3450		return B_BAD_TEAM_ID;
3451	}
3452
3453	list_add_item(&team->watcher_list, watcher);
3454
3455	team->UnlockAndReleaseReference();
3456
3457	return B_OK;
3458}
3459
3460
3461status_t
3462stop_watching_team(team_id teamID, void (*hook)(team_id, void*), void* data)
3463{
3464	if (hook == NULL || teamID < 0)
3465		return B_BAD_VALUE;
3466
3467	// get team and remove watcher (if present)
3468	Team* team = Team::GetAndLock(teamID);
3469	if (team == NULL)
3470		return B_BAD_TEAM_ID;
3471
3472	// search for watcher
3473	team_watcher* watcher = NULL;
3474	while ((watcher = (team_watcher*)list_get_next_item(
3475			&team->watcher_list, watcher)) != NULL) {
3476		if (watcher->hook == hook && watcher->data == data) {
3477			// got it!
3478			list_remove_item(&team->watcher_list, watcher);
3479			break;
3480		}
3481	}
3482
3483	team->UnlockAndReleaseReference();
3484
3485	if (watcher == NULL)
3486		return B_ENTRY_NOT_FOUND;
3487
3488	free(watcher);
3489	return B_OK;
3490}
3491
3492
3493/*!	Allocates a user_thread structure from the team.
3494	The team lock must be held, unless the function is called for the team's
3495	main thread. Interrupts must be enabled.
3496*/
3497struct user_thread*
3498team_allocate_user_thread(Team* team)
3499{
3500	if (team->user_data == 0)
3501		return NULL;
3502
3503	// take an entry from the free list, if any
3504	if (struct free_user_thread* entry = team->free_user_threads) {
3505		user_thread* thread = entry->thread;
3506		team->free_user_threads = entry->next;
3507		free(entry);
3508		return thread;
3509	}
3510
3511	while (true) {
3512		// enough space left?
3513		size_t needed = ROUNDUP(sizeof(user_thread), CACHE_LINE_SIZE);
3514		if (team->user_data_size - team->used_user_data < needed) {
3515			// try to resize the area
3516			if (resize_area(team->user_data_area,
3517					team->user_data_size + B_PAGE_SIZE) != B_OK) {
3518				return NULL;
3519			}
3520
3521			// resized user area successfully -- try to allocate the user_thread
3522			// again
3523			team->user_data_size += B_PAGE_SIZE;
3524			continue;
3525		}
3526
3527		// allocate the user_thread
3528		user_thread* thread
3529			= (user_thread*)(team->user_data + team->used_user_data);
3530		team->used_user_data += needed;
3531
3532		return thread;
3533	}
3534}
3535
3536
3537/*!	Frees the given user_thread structure.
3538	The team's lock must not be held. Interrupts must be enabled.
3539	\param team The team the user thread was allocated from.
3540	\param userThread The user thread to free.
3541*/
3542void
3543team_free_user_thread(Team* team, struct user_thread* userThread)
3544{
3545	if (userThread == NULL)
3546		return;
3547
3548	// create a free list entry
3549	free_user_thread* entry
3550		= (free_user_thread*)malloc(sizeof(free_user_thread));
3551	if (entry == NULL) {
3552		// we have to leak the user thread :-/
3553		return;
3554	}
3555
3556	// add to free list
3557	TeamLocker teamLocker(team);
3558
3559	entry->thread = userThread;
3560	entry->next = team->free_user_threads;
3561	team->free_user_threads = entry;
3562}
3563
3564
3565//	#pragma mark - Associated data interface
3566
3567
3568AssociatedData::AssociatedData()
3569	:
3570	fOwner(NULL)
3571{
3572}
3573
3574
3575AssociatedData::~AssociatedData()
3576{
3577}
3578
3579
3580void
3581AssociatedData::OwnerDeleted(AssociatedDataOwner* owner)
3582{
3583}
3584
3585
3586AssociatedDataOwner::AssociatedDataOwner()
3587{
3588	mutex_init(&fLock, "associated data owner");
3589}
3590
3591
3592AssociatedDataOwner::~AssociatedDataOwner()
3593{
3594	mutex_destroy(&fLock);
3595}
3596
3597
3598bool
3599AssociatedDataOwner::AddData(AssociatedData* data)
3600{
3601	MutexLocker locker(fLock);
3602
3603	if (data->Owner() != NULL)
3604		return false;
3605
3606	data->AcquireReference();
3607	fList.Add(data);
3608	data->SetOwner(this);
3609
3610	return true;
3611}
3612
3613
3614bool
3615AssociatedDataOwner::RemoveData(AssociatedData* data)
3616{
3617	MutexLocker locker(fLock);
3618
3619	if (data->Owner() != this)
3620		return false;
3621
3622	data->SetOwner(NULL);
3623	fList.Remove(data);
3624
3625	locker.Unlock();
3626
3627	data->ReleaseReference();
3628
3629	return true;
3630}
3631
3632
3633void
3634AssociatedDataOwner::PrepareForDeletion()
3635{
3636	MutexLocker locker(fLock);
3637
3638	// move all data to a temporary list and unset the owner
3639	DataList list;
3640	list.MoveFrom(&fList);
3641
3642	for (DataList::Iterator it = list.GetIterator();
3643		AssociatedData* data = it.Next();) {
3644		data->SetOwner(NULL);
3645	}
3646
3647	locker.Unlock();
3648
3649	// call the notification hooks and release our references
3650	while (AssociatedData* data = list.RemoveHead()) {
3651		data->OwnerDeleted(this);
3652		data->ReleaseReference();
3653	}
3654}
3655
3656
3657/*!	Associates data with the current team.
3658	When the team is deleted, the data object is notified.
3659	The team acquires a reference to the object.
3660
3661	\param data The data object.
3662	\return \c true on success, \c false otherwise. Fails only when the supplied
3663		data object is already associated with another owner.
3664*/
3665bool
3666team_associate_data(AssociatedData* data)
3667{
3668	return thread_get_current_thread()->team->AddData(data);
3669}
3670
3671
3672/*!	Dissociates data from the current team.
3673	Balances an earlier call to team_associate_data().
3674
3675	\param data The data object.
3676	\return \c true on success, \c false otherwise. Fails only when the data
3677		object is not associated with the current team.
3678*/
3679bool
3680team_dissociate_data(AssociatedData* data)
3681{
3682	return thread_get_current_thread()->team->RemoveData(data);
3683}
3684
3685
3686//	#pragma mark - Public kernel API
3687
3688
3689thread_id
3690load_image(int32 argCount, const char** args, const char** env)
3691{
3692	return load_image_etc(argCount, args, env, B_NORMAL_PRIORITY,
3693		B_CURRENT_TEAM, B_WAIT_TILL_LOADED);
3694}
3695
3696
3697thread_id
3698load_image_etc(int32 argCount, const char* const* args,
3699	const char* const* env, int32 priority, team_id parentID, uint32 flags)
3700{
3701	// we need to flatten the args and environment
3702
3703	if (args == NULL)
3704		return B_BAD_VALUE;
3705
3706	// determine total needed size
3707	int32 argSize = 0;
3708	for (int32 i = 0; i < argCount; i++)
3709		argSize += strlen(args[i]) + 1;
3710
3711	int32 envCount = 0;
3712	int32 envSize = 0;
3713	while (env != NULL && env[envCount] != NULL)
3714		envSize += strlen(env[envCount++]) + 1;
3715
3716	int32 size = (argCount + envCount + 2) * sizeof(char*) + argSize + envSize;
3717	if (size > MAX_PROCESS_ARGS_SIZE)
3718		return B_TOO_MANY_ARGS;
3719
3720	// allocate space
3721	char** flatArgs = (char**)malloc(size);
3722	if (flatArgs == NULL)
3723		return B_NO_MEMORY;
3724
3725	char** slot = flatArgs;
3726	char* stringSpace = (char*)(flatArgs + argCount + envCount + 2);
3727
3728	// copy arguments and environment
3729	for (int32 i = 0; i < argCount; i++) {
3730		int32 argSize = strlen(args[i]) + 1;
3731		memcpy(stringSpace, args[i], argSize);
3732		*slot++ = stringSpace;
3733		stringSpace += argSize;
3734	}
3735
3736	*slot++ = NULL;
3737
3738	for (int32 i = 0; i < envCount; i++) {
3739		int32 envSize = strlen(env[i]) + 1;
3740		memcpy(stringSpace, env[i], envSize);
3741		*slot++ = stringSpace;
3742		stringSpace += envSize;
3743	}
3744
3745	*slot++ = NULL;
3746
3747	thread_id thread = load_image_internal(flatArgs, size, argCount, envCount,
3748		B_NORMAL_PRIORITY, parentID, B_WAIT_TILL_LOADED, -1, 0);
3749
3750	free(flatArgs);
3751		// load_image_internal() unset our variable if it took over ownership
3752
3753	return thread;
3754}
3755
3756
3757status_t
3758wait_for_team(team_id id, status_t* _returnCode)
3759{
3760	// check whether the team exists
3761	InterruptsReadSpinLocker teamsLocker(sTeamHashLock);
3762
3763	Team* team = team_get_team_struct_locked(id);
3764	if (team == NULL)
3765		return B_BAD_TEAM_ID;
3766
3767	id = team->id;
3768
3769	teamsLocker.Unlock();
3770
3771	// wait for the main thread (it has the same ID as the team)
3772	return wait_for_thread(id, _returnCode);
3773}
3774
3775
3776status_t
3777kill_team(team_id id)
3778{
3779	InterruptsReadSpinLocker teamsLocker(sTeamHashLock);
3780
3781	Team* team = team_get_team_struct_locked(id);
3782	if (team == NULL)
3783		return B_BAD_TEAM_ID;
3784
3785	id = team->id;
3786
3787	teamsLocker.Unlock();
3788
3789	if (team == sKernelTeam)
3790		return B_NOT_ALLOWED;
3791
3792	// Just kill the team's main thread (it has same ID as the team). The
3793	// cleanup code there will take care of the team.
3794	return kill_thread(id);
3795}
3796
3797
3798status_t
3799_get_team_info(team_id id, team_info* info, size_t size)
3800{
3801	// get the team
3802	Team* team = Team::Get(id);
3803	if (team == NULL)
3804		return B_BAD_TEAM_ID;
3805	BReference<Team> teamReference(team, true);
3806
3807	// fill in the info
3808	return fill_team_info(team, info, size);
3809}
3810
3811
3812status_t
3813_get_next_team_info(int32* cookie, team_info* info, size_t size)
3814{
3815	int32 slot = *cookie;
3816	if (slot < 1)
3817		slot = 1;
3818
3819	InterruptsReadSpinLocker locker(sTeamHashLock);
3820
3821	team_id lastTeamID = peek_next_thread_id();
3822		// TODO: This is broken, since the id can wrap around!
3823
3824	// get next valid team
3825	Team* team = NULL;
3826	while (slot < lastTeamID && !(team = team_get_team_struct_locked(slot)))
3827		slot++;
3828
3829	if (team == NULL)
3830		return B_BAD_TEAM_ID;
3831
3832	// get a reference to the team and unlock
3833	BReference<Team> teamReference(team);
3834	locker.Unlock();
3835
3836	// fill in the info
3837	*cookie = ++slot;
3838	return fill_team_info(team, info, size);
3839}
3840
3841
3842status_t
3843_get_team_usage_info(team_id id, int32 who, team_usage_info* info, size_t size)
3844{
3845	if (size != sizeof(team_usage_info))
3846		return B_BAD_VALUE;
3847
3848	return common_get_team_usage_info(id, who, info, 0);
3849}
3850
3851
3852pid_t
3853getpid(void)
3854{
3855	return thread_get_current_thread()->team->id;
3856}
3857
3858
3859pid_t
3860getppid(void)
3861{
3862	Team* team = thread_get_current_thread()->team;
3863
3864	TeamLocker teamLocker(team);
3865
3866	return team->parent->id;
3867}
3868
3869
3870pid_t
3871getpgid(pid_t id)
3872{
3873	if (id < 0) {
3874		errno = EINVAL;
3875		return -1;
3876	}
3877
3878	if (id == 0) {
3879		// get process group of the calling process
3880		Team* team = thread_get_current_thread()->team;
3881		TeamLocker teamLocker(team);
3882		return team->group_id;
3883	}
3884
3885	// get the team
3886	Team* team = Team::GetAndLock(id);
3887	if (team == NULL) {
3888		errno = ESRCH;
3889		return -1;
3890	}
3891
3892	// get the team's process group ID
3893	pid_t groupID = team->group_id;
3894
3895	team->UnlockAndReleaseReference();
3896
3897	return groupID;
3898}
3899
3900
3901pid_t
3902getsid(pid_t id)
3903{
3904	if (id < 0) {
3905		errno = EINVAL;
3906		return -1;
3907	}
3908
3909	if (id == 0) {
3910		// get session of the calling process
3911		Team* team = thread_get_current_thread()->team;
3912		TeamLocker teamLocker(team);
3913		return team->session_id;
3914	}
3915
3916	// get the team
3917	Team* team = Team::GetAndLock(id);
3918	if (team == NULL) {
3919		errno = ESRCH;
3920		return -1;
3921	}
3922
3923	// get the team's session ID
3924	pid_t sessionID = team->session_id;
3925
3926	team->UnlockAndReleaseReference();
3927
3928	return sessionID;
3929}
3930
3931
3932//	#pragma mark - User syscalls
3933
3934
3935status_t
3936_user_exec(const char* userPath, const char* const* userFlatArgs,
3937	size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask)
3938{
3939	// NOTE: Since this function normally doesn't return, don't use automatic
3940	// variables that need destruction in the function scope.
3941	char path[B_PATH_NAME_LENGTH];
3942
3943	if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userFlatArgs)
3944		|| user_strlcpy(path, userPath, sizeof(path)) < B_OK)
3945		return B_BAD_ADDRESS;
3946
3947	// copy and relocate the flat arguments
3948	char** flatArgs;
3949	status_t error = copy_user_process_args(userFlatArgs, flatArgsSize,
3950		argCount, envCount, flatArgs);
3951
3952	if (error == B_OK) {
3953		error = exec_team(path, flatArgs, _ALIGN(flatArgsSize), argCount,
3954			envCount, umask);
3955			// this one only returns in case of error
3956	}
3957
3958	free(flatArgs);
3959	return error;
3960}
3961
3962
3963thread_id
3964_user_fork(void)
3965{
3966	return fork_team();
3967}
3968
3969
3970pid_t
3971_user_wait_for_child(thread_id child, uint32 flags, siginfo_t* userInfo,
3972	team_usage_info* usageInfo)
3973{
3974	if (userInfo != NULL && !IS_USER_ADDRESS(userInfo))
3975		return B_BAD_ADDRESS;
3976	if (usageInfo != NULL && !IS_USER_ADDRESS(usageInfo))
3977		return B_BAD_ADDRESS;
3978
3979	siginfo_t info;
3980	team_usage_info usage_info;
3981	pid_t foundChild = wait_for_child(child, flags, info, usage_info);
3982	if (foundChild < 0)
3983		return syscall_restart_handle_post(foundChild);
3984
3985	// copy info back to userland
3986	if (userInfo != NULL && user_memcpy(userInfo, &info, sizeof(info)) != B_OK)
3987		return B_BAD_ADDRESS;
3988	// copy usage_info back to userland
3989	if (usageInfo != NULL && user_memcpy(usageInfo, &usage_info,
3990		sizeof(usage_info)) != B_OK) {
3991		return B_BAD_ADDRESS;
3992	}
3993
3994	return foundChild;
3995}
3996
3997
3998pid_t
3999_user_process_info(pid_t process, int32 which)
4000{
4001	// we only allow to return the parent of the current process
4002	if (which == PARENT_ID
4003		&& process != 0 && process != thread_get_current_thread()->team->id)
4004		return B_BAD_VALUE;
4005
4006	pid_t result;
4007	switch (which) {
4008		case SESSION_ID:
4009			result = getsid(process);
4010			break;
4011		case GROUP_ID:
4012			result = getpgid(process);
4013			break;
4014		case PARENT_ID:
4015			result = getppid();
4016			break;
4017		default:
4018			return B_BAD_VALUE;
4019	}
4020
4021	return result >= 0 ? result : errno;
4022}
4023
4024
4025pid_t
4026_user_setpgid(pid_t processID, pid_t groupID)
4027{
4028	// setpgid() can be called either by the parent of the target process or
4029	// by the process itself to do one of two things:
4030	// * Create a new process group with the target process' ID and the target
4031	//   process as group leader.
4032	// * Set the target process' process group to an already existing one in the
4033	//   same session.
4034
4035	if (groupID < 0)
4036		return B_BAD_VALUE;
4037
4038	Team* currentTeam = thread_get_current_thread()->team;
4039	if (processID == 0)
4040		processID = currentTeam->id;
4041
4042	// if the group ID is not specified, use the target process' ID
4043	if (groupID == 0)
4044		groupID = processID;
4045
4046	// We loop when running into the following race condition: We create a new
4047	// process group, because there isn't one with that ID yet, but later when
4048	// trying to publish it, we find that someone else created and published
4049	// a group with that ID in the meantime. In that case we just restart the
4050	// whole action.
4051	while (true) {
4052		// Look up the process group by ID. If it doesn't exist yet and we are
4053		// allowed to create a new one, do that.
4054		ProcessGroup* group = ProcessGroup::Get(groupID);
4055		bool newGroup = false;
4056		if (group == NULL) {
4057			if (groupID != processID)
4058				return B_NOT_ALLOWED;
4059
4060			group = new(std::nothrow) ProcessGroup(groupID);
4061			if (group == NULL)
4062				return B_NO_MEMORY;
4063
4064			newGroup = true;
4065		}
4066		BReference<ProcessGroup> groupReference(group, true);
4067
4068		// get the target team
4069		Team* team = Team::Get(processID);
4070		if (team == NULL)
4071			return ESRCH;
4072		BReference<Team> teamReference(team, true);
4073
4074		// lock the new process group and the team's current process group
4075		while (true) {
4076			// lock the team's current process group
4077			team->LockProcessGroup();
4078
4079			ProcessGroup* oldGroup = team->group;
4080			if (oldGroup == group) {
4081				// it's the same as the target group, so just bail out
4082				oldGroup->Unlock();
4083				return group->id;
4084			}
4085
4086			oldGroup->AcquireReference();
4087
4088			// lock the target process group, if locking order allows it
4089			if (newGroup || group->id > oldGroup->id) {
4090				group->Lock();
4091				break;
4092			}
4093
4094			// try to lock
4095			if (group->TryLock())
4096				break;
4097
4098			// no dice -- unlock the team's current process group and relock in
4099			// the correct order
4100			oldGroup->Unlock();
4101
4102			group->Lock();
4103			oldGroup->Lock();
4104
4105			// check whether things are still the same
4106			TeamLocker teamLocker(team);
4107			if (team->group == oldGroup)
4108				break;
4109
4110			// something changed -- unlock everything and retry
4111			teamLocker.Unlock();
4112			oldGroup->Unlock();
4113			group->Unlock();
4114			oldGroup->ReleaseReference();
4115		}
4116
4117		// we now have references and locks of both new and old process group
4118		BReference<ProcessGroup> oldGroupReference(team->group, true);
4119		AutoLocker<ProcessGroup> oldGroupLocker(team->group, true);
4120		AutoLocker<ProcessGroup> groupLocker(group, true);
4121
4122		// also lock the target team and its parent
4123		team->LockTeamAndParent(false);
4124		TeamLocker parentLocker(team->parent, true);
4125		TeamLocker teamLocker(team, true);
4126
4127		// perform the checks
4128		if (team == currentTeam) {
4129			// we set our own group
4130
4131			// we must not change our process group ID if we're a session leader
4132			if (is_session_leader(currentTeam))
4133				return B_NOT_ALLOWED;
4134		} else {
4135			// Calling team != target team. The target team must be a child of
4136			// the calling team and in the same session. (If that's the case it
4137			// isn't a session leader either.)
4138			if (team->parent != currentTeam
4139				|| team->session_id != currentTeam->session_id) {
4140				return B_NOT_ALLOWED;
4141			}
4142
4143			// The call is also supposed to fail on a child, when the child has
4144			// already executed exec*() [EACCES].
4145			if ((team->flags & TEAM_FLAG_EXEC_DONE) != 0)
4146				return EACCES;
4147		}
4148
4149		// If we created a new process group, publish it now.
4150		if (newGroup) {
4151			InterruptsSpinLocker groupHashLocker(sGroupHashLock);
4152			if (sGroupHash.Lookup(groupID)) {
4153				// A group with the group ID appeared since we first checked.
4154				// Back to square one.
4155				continue;
4156			}
4157
4158			group->PublishLocked(team->group->Session());
4159		} else if (group->Session()->id != team->session_id) {
4160			// The existing target process group belongs to a different session.
4161			// That's not allowed.
4162			return B_NOT_ALLOWED;
4163		}
4164
4165		// Everything is ready -- set the group.
4166		remove_team_from_group(team);
4167		insert_team_into_group(group, team);
4168
4169		// Changing the process group might have changed the situation for a
4170		// parent waiting in wait_for_child(). Hence we notify it.
4171		team->parent->dead_children.condition_variable.NotifyAll();
4172
4173		return group->id;
4174	}
4175}
4176
4177
4178pid_t
4179_user_setsid(void)
4180{
4181	Team* team = thread_get_current_thread()->team;
4182
4183	// create a new process group and session
4184	ProcessGroup* group = new(std::nothrow) ProcessGroup(team->id);
4185	if (group == NULL)
4186		return B_NO_MEMORY;
4187	BReference<ProcessGroup> groupReference(group, true);
4188	AutoLocker<ProcessGroup> groupLocker(group);
4189
4190	ProcessSession* session = new(std::nothrow) ProcessSession(group->id);
4191	if (session == NULL)
4192		return B_NO_MEMORY;
4193	BReference<ProcessSession> sessionReference(session, true);
4194
4195	// lock the team's current process group, parent, and the team itself
4196	team->LockTeamParentAndProcessGroup();
4197	BReference<ProcessGroup> oldGroupReference(team->group);
4198	AutoLocker<ProcessGroup> oldGroupLocker(team->group, true);
4199	TeamLocker parentLocker(team->parent, true);
4200	TeamLocker teamLocker(team, true);
4201
4202	// the team must not already be a process group leader
4203	if (is_process_group_leader(team))
4204		return B_NOT_ALLOWED;
4205
4206	// remove the team from the old and add it to the new process group
4207	remove_team_from_group(team);
4208	group->Publish(session);
4209	insert_team_into_group(group, team);
4210
4211	// Changing the process group might have changed the situation for a
4212	// parent waiting in wait_for_child(). Hence we notify it.
4213	team->parent->dead_children.condition_variable.NotifyAll();
4214
4215	return group->id;
4216}
4217
4218
4219status_t
4220_user_wait_for_team(team_id id, status_t* _userReturnCode)
4221{
4222	status_t returnCode;
4223	status_t status;
4224
4225	if (_userReturnCode != NULL && !IS_USER_ADDRESS(_userReturnCode))
4226		return B_BAD_ADDRESS;
4227
4228	status = wait_for_team(id, &returnCode);
4229	if (status >= B_OK && _userReturnCode != NULL) {
4230		if (user_memcpy(_userReturnCode, &returnCode, sizeof(returnCode))
4231				!= B_OK)
4232			return B_BAD_ADDRESS;
4233		return B_OK;
4234	}
4235
4236	return syscall_restart_handle_post(status);
4237}
4238
4239
4240thread_id
4241_user_load_image(const char* const* userFlatArgs, size_t flatArgsSize,
4242	int32 argCount, int32 envCount, int32 priority, uint32 flags,
4243	port_id errorPort, uint32 errorToken)
4244{
4245	TRACE(("_user_load_image: argc = %" B_PRId32 "\n", argCount));
4246
4247	if (argCount < 1)
4248		return B_BAD_VALUE;
4249
4250	// copy and relocate the flat arguments
4251	char** flatArgs;
4252	status_t error = copy_user_process_args(userFlatArgs, flatArgsSize,
4253		argCount, envCount, flatArgs);
4254	if (error != B_OK)
4255		return error;
4256
4257	thread_id thread = load_image_internal(flatArgs, _ALIGN(flatArgsSize),
4258		argCount, envCount, priority, B_CURRENT_TEAM, flags, errorPort,
4259		errorToken);
4260
4261	free(flatArgs);
4262		// load_image_internal() unset our variable if it took over ownership
4263
4264	return thread;
4265}
4266
4267
4268void
4269_user_exit_team(status_t returnValue)
4270{
4271	Thread* thread = thread_get_current_thread();
4272	Team* team = thread->team;
4273
4274	// set this thread's exit status
4275	thread->exit.status = returnValue;
4276
4277	// set the team exit status
4278	TeamLocker teamLocker(team);
4279
4280	if (!team->exit.initialized) {
4281		team->exit.reason = CLD_EXITED;
4282		team->exit.signal = 0;
4283		team->exit.signaling_user = 0;
4284		team->exit.status = returnValue;
4285		team->exit.initialized = true;
4286	}
4287
4288	teamLocker.Unlock();
4289
4290	// Stop the thread, if the team is being debugged and that has been
4291	// requested.
4292	if ((atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_PREVENT_EXIT) != 0)
4293		user_debug_stop_thread();
4294
4295	// Send this thread a SIGKILL. This makes sure the thread will not return to
4296	// userland. The signal handling code forwards the signal to the main
4297	// thread (if that's not already this one), which will take the team down.
4298	Signal signal(SIGKILL, SI_USER, B_OK, team->id);
4299	send_signal_to_thread(thread, signal, 0);
4300}
4301
4302
4303status_t
4304_user_kill_team(team_id team)
4305{
4306	return kill_team(team);
4307}
4308
4309
4310status_t
4311_user_get_team_info(team_id id, team_info* userInfo)
4312{
4313	status_t status;
4314	team_info info;
4315
4316	if (!IS_USER_ADDRESS(userInfo))
4317		return B_BAD_ADDRESS;
4318
4319	status = _get_team_info(id, &info, sizeof(team_info));
4320	if (status == B_OK) {
4321		if (user_memcpy(userInfo, &info, sizeof(team_info)) < B_OK)
4322			return B_BAD_ADDRESS;
4323	}
4324
4325	return status;
4326}
4327
4328
4329status_t
4330_user_get_next_team_info(int32* userCookie, team_info* userInfo)
4331{
4332	status_t status;
4333	team_info info;
4334	int32 cookie;
4335
4336	if (!IS_USER_ADDRESS(userCookie)
4337		|| !IS_USER_ADDRESS(userInfo)
4338		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
4339		return B_BAD_ADDRESS;
4340
4341	status = _get_next_team_info(&cookie, &info, sizeof(team_info));
4342	if (status != B_OK)
4343		return status;
4344
4345	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
4346		|| user_memcpy(userInfo, &info, sizeof(team_info)) < B_OK)
4347		return B_BAD_ADDRESS;
4348
4349	return status;
4350}
4351
4352
4353team_id
4354_user_get_current_team(void)
4355{
4356	return team_get_current_team_id();
4357}
4358
4359
4360status_t
4361_user_get_team_usage_info(team_id team, int32 who, team_usage_info* userInfo,
4362	size_t size)
4363{
4364	if (size != sizeof(team_usage_info))
4365		return B_BAD_VALUE;
4366
4367	team_usage_info info;
4368	status_t status = common_get_team_usage_info(team, who, &info,
4369		B_CHECK_PERMISSION);
4370
4371	if (userInfo == NULL || !IS_USER_ADDRESS(userInfo)
4372		|| user_memcpy(userInfo, &info, size) != B_OK) {
4373		return B_BAD_ADDRESS;
4374	}
4375
4376	return status;
4377}
4378
4379
4380status_t
4381_user_get_extended_team_info(team_id teamID, uint32 flags, void* buffer,
4382	size_t size, size_t* _sizeNeeded)
4383{
4384	// check parameters
4385	if ((buffer != NULL && !IS_USER_ADDRESS(buffer))
4386		|| (buffer == NULL && size > 0)
4387		|| _sizeNeeded == NULL || !IS_USER_ADDRESS(_sizeNeeded)) {
4388		return B_BAD_ADDRESS;
4389	}
4390
4391	KMessage info;
4392
4393	if ((flags & B_TEAM_INFO_BASIC) != 0) {
4394		// allocate memory for a copy of the needed team data
4395		struct ExtendedTeamData {
4396			team_id	id;
4397			pid_t	group_id;
4398			pid_t	session_id;
4399			uid_t	real_uid;
4400			gid_t	real_gid;
4401			uid_t	effective_uid;
4402			gid_t	effective_gid;
4403			char	name[B_OS_NAME_LENGTH];
4404		} teamClone;
4405
4406		io_context* ioContext;
4407		{
4408			// get the team structure
4409			Team* team = Team::GetAndLock(teamID);
4410			if (team == NULL)
4411				return B_BAD_TEAM_ID;
4412			BReference<Team> teamReference(team, true);
4413			TeamLocker teamLocker(team, true);
4414
4415			// copy the data
4416			teamClone.id = team->id;
4417			strlcpy(teamClone.name, team->Name(), sizeof(teamClone.name));
4418			teamClone.group_id = team->group_id;
4419			teamClone.session_id = team->session_id;
4420			teamClone.real_uid = team->real_uid;
4421			teamClone.real_gid = team->real_gid;
4422			teamClone.effective_uid = team->effective_uid;
4423			teamClone.effective_gid = team->effective_gid;
4424
4425			// also fetch a reference to the I/O context
4426			ioContext = team->io_context;
4427			vfs_get_io_context(ioContext);
4428		}
4429		CObjectDeleter<io_context> ioContextPutter(ioContext,
4430			&vfs_put_io_context);
4431
4432		// add the basic data to the info message
4433		if (info.AddInt32("id", teamClone.id) != B_OK
4434			|| info.AddString("name", teamClone.name) != B_OK
4435			|| info.AddInt32("process group", teamClone.group_id) != B_OK
4436			|| info.AddInt32("session", teamClone.session_id) != B_OK
4437			|| info.AddInt32("uid", teamClone.real_uid) != B_OK
4438			|| info.AddInt32("gid", teamClone.real_gid) != B_OK
4439			|| info.AddInt32("euid", teamClone.effective_uid) != B_OK
4440			|| info.AddInt32("egid", teamClone.effective_gid) != B_OK) {
4441			return B_NO_MEMORY;
4442		}
4443
4444		// get the current working directory from the I/O context
4445		dev_t cwdDevice;
4446		ino_t cwdDirectory;
4447		{
4448			MutexLocker ioContextLocker(ioContext->io_mutex);
4449			vfs_vnode_to_node_ref(ioContext->cwd, &cwdDevice, &cwdDirectory);
4450		}
4451
4452		if (info.AddInt32("cwd device", cwdDevice) != B_OK
4453			|| info.AddInt64("cwd directory", cwdDirectory) != B_OK) {
4454			return B_NO_MEMORY;
4455		}
4456	}
4457
4458	// TODO: Support the other flags!
4459
4460	// copy the needed size and, if it fits, the message back to userland
4461	size_t sizeNeeded = info.ContentSize();
4462	if (user_memcpy(_sizeNeeded, &sizeNeeded, sizeof(sizeNeeded)) != B_OK)
4463		return B_BAD_ADDRESS;
4464
4465	if (sizeNeeded > size)
4466		return B_BUFFER_OVERFLOW;
4467
4468	if (user_memcpy(buffer, info.Buffer(), sizeNeeded) != B_OK)
4469		return B_BAD_ADDRESS;
4470
4471	return B_OK;
4472}
4473