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