xref: /haiku/src/system/kernel/team.cpp (revision 4cc4f7bb1845789f95d5ebc68cbb0b859e72f6ff)
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 
68 struct team_key {
69 	team_id id;
70 };
71 
72 struct 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 
84 namespace {
85 
86 
87 class TeamNotificationService : public DefaultNotificationService {
88 public:
89 							TeamNotificationService();
90 
91 			void			Notify(uint32 eventCode, Team* team);
92 };
93 
94 
95 // #pragma mark - TeamTable
96 
97 
98 typedef BKernel::TeamThreadTable<Team> TeamTable;
99 
100 
101 // #pragma mark - ProcessGroupHashDefinition
102 
103 
104 struct 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 
129 typedef 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
139 static TeamTable sTeamHash;
140 static spinlock sTeamHashLock = B_SPINLOCK_INITIALIZER;
141 
142 // the pid_t -> ProcessGroup hash table and the lock protecting it
143 static ProcessGroupHashTable sGroupHash;
144 static spinlock sGroupHashLock = B_SPINLOCK_INITIALIZER;
145 
146 static 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.
150 static ProcessGroupList sOrphanedCheckProcessGroups;
151 static 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)
156 static int32 sMaxTeams = 2048;
157 static int32 sUsedTeams = 1;
158 
159 static TeamNotificationService sNotificationService;
160 
161 
162 // #pragma mark - TeamListIterator
163 
164 
165 TeamListIterator::TeamListIterator()
166 {
167 	// queue the entry
168 	InterruptsSpinLocker locker(sTeamHashLock);
169 	sTeamHash.InsertIteratorEntry(&fEntry);
170 }
171 
172 
173 TeamListIterator::~TeamListIterator()
174 {
175 	// remove the entry
176 	InterruptsSpinLocker locker(sTeamHashLock);
177 	sTeamHash.RemoveIteratorEntry(&fEntry);
178 }
179 
180 
181 Team*
182 TeamListIterator::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
198 namespace TeamTracing {
199 
200 class TeamForked : public AbstractTraceEntry {
201 public:
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 
214 private:
215 	thread_id			fForkedThread;
216 };
217 
218 
219 class ExecTeam : public AbstractTraceEntry {
220 public:
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 
267 private:
268 	char*	fPath;
269 	int32	fArgCount;
270 	char*	fArgs;
271 };
272 
273 
274 static const char*
275 job_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 
292 class SetJobControlState : public AbstractTraceEntry {
293 public:
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 
310 private:
311 	team_id				fTeam;
312 	job_control_state	fNewState;
313 	int					fSignal;
314 };
315 
316 
317 class WaitForChild : public AbstractTraceEntry {
318 public:
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 
333 private:
334 	pid_t	fChild;
335 	uint32	fFlags;
336 };
337 
338 
339 class WaitForChildDone : public AbstractTraceEntry {
340 public:
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 
372 private:
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 
391 TeamNotificationService::TeamNotificationService()
392 	: DefaultNotificationService("teams")
393 {
394 }
395 
396 
397 void
398 TeamNotificationService::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 
414 Team::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 
495 Team::~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*
534 Team::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*
569 Team::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*
590 Team::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 */
621 void
622 Team::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 */
657 void
658 Team::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 */
672 void
673 Team::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 */
691 void
692 Team::UnlockTeamParentAndProcessGroup()
693 {
694 	group->Unlock();
695 
696 	if (parent != NULL)
697 		parent->Unlock();
698 
699 	Unlock();
700 }
701 
702 
703 void
704 Team::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 
736 void
737 Team::UnlockTeamAndProcessGroup()
738 {
739 	group->Unlock();
740 	Unlock();
741 }
742 
743 
744 void
745 Team::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 
754 void
755 Team::SetArgs(const char* args)
756 {
757 	strlcpy(fArgs, args, sizeof(fArgs));
758 }
759 
760 
761 void
762 Team::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 
773 void
774 Team::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 
795 void
796 Team::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 */
812 status_t
813 Team::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 */
837 void
838 Team::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 */
855 void
856 Team::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 */
866 bool
867 Team::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 */
882 void
883 Team::UserDefinedTimersRemoved(int32 count)
884 {
885 	atomic_add(&fUserDefinedTimerCount, -count);
886 }
887 
888 
889 void
890 Team::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 */
911 bigtime_t
912 Team::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 */
941 bigtime_t
942 Team::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 
964 ProcessGroup::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 
977 ProcessGroup::~ProcessGroup()
978 {
979 	TRACE(("ProcessGroup::~ProcessGroup(): id = %ld\n", group->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*
1003 ProcessGroup::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 */
1016 void
1017 ProcessGroup::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 */
1027 void
1028 ProcessGroup::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 */
1043 bool
1044 ProcessGroup::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 
1070 void
1071 ProcessGroup::ScheduleOrphanedCheck()
1072 {
1073 	MutexLocker orphanedCheckLocker(sOrphanedCheckLock);
1074 
1075 	if (!fInOrphanedCheckList) {
1076 		sOrphanedCheckProcessGroups.Add(this);
1077 		fInOrphanedCheckList = true;
1078 	}
1079 }
1080 
1081 
1082 void
1083 ProcessGroup::UnsetOrphanedCheck()
1084 {
1085 	fInOrphanedCheckList = false;
1086 }
1087 
1088 
1089 //	#pragma mark - ProcessSession
1090 
1091 
1092 ProcessSession::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 
1104 ProcessSession::~ProcessSession()
1105 {
1106 	mutex_destroy(&fLock);
1107 }
1108 
1109 
1110 //	#pragma mark - KDL functions
1111 
1112 
1113 static void
1114 _dump_team_info(Team* team)
1115 {
1116 	kprintf("TEAM: %p\n", team);
1117 	kprintf("id:               %ld (%#lx)\n", team->id, team->id);
1118 	kprintf("serial_number:    %" B_PRId64 "\n", team->serial_number);
1119 	kprintf("name:             '%s'\n", team->Name());
1120 	kprintf("args:             '%s'\n", team->Args());
1121 	kprintf("hash_next:        %p\n", team->hash_next);
1122 	kprintf("parent:           %p", team->parent);
1123 	if (team->parent != NULL) {
1124 		kprintf(" (id = %ld)\n", team->parent->id);
1125 	} else
1126 		kprintf("\n");
1127 
1128 	kprintf("children:         %p\n", team->children);
1129 	kprintf("num_threads:      %d\n", team->num_threads);
1130 	kprintf("state:            %d\n", team->state);
1131 	kprintf("flags:            0x%lx\n", team->flags);
1132 	kprintf("io_context:       %p\n", team->io_context);
1133 	if (team->address_space)
1134 		kprintf("address_space:    %p\n", team->address_space);
1135 	kprintf("user data:        %p (area %ld)\n", (void*)team->user_data,
1136 		team->user_data_area);
1137 	kprintf("free user thread: %p\n", team->free_user_threads);
1138 	kprintf("main_thread:      %p\n", team->main_thread);
1139 	kprintf("thread_list:      %p\n", team->thread_list);
1140 	kprintf("group_id:         %ld\n", team->group_id);
1141 	kprintf("session_id:       %ld\n", team->session_id);
1142 }
1143 
1144 
1145 static int
1146 dump_team_info(int argc, char** argv)
1147 {
1148 	team_id id = -1;
1149 	bool found = false;
1150 
1151 	if (argc < 2) {
1152 		Thread* thread = thread_get_current_thread();
1153 		if (thread != NULL && thread->team != NULL)
1154 			_dump_team_info(thread->team);
1155 		else
1156 			kprintf("No current team!\n");
1157 		return 0;
1158 	}
1159 
1160 	id = strtoul(argv[1], NULL, 0);
1161 	if (IS_KERNEL_ADDRESS(id)) {
1162 		// semi-hack
1163 		_dump_team_info((Team*)id);
1164 		return 0;
1165 	}
1166 
1167 	// walk through the thread list, trying to match name or id
1168 	for (TeamTable::Iterator it = sTeamHash.GetIterator();
1169 		Team* team = it.Next();) {
1170 		if ((team->Name() && strcmp(argv[1], team->Name()) == 0)
1171 			|| team->id == id) {
1172 			_dump_team_info(team);
1173 			found = true;
1174 			break;
1175 		}
1176 	}
1177 
1178 	if (!found)
1179 		kprintf("team \"%s\" (%ld) doesn't exist!\n", argv[1], id);
1180 	return 0;
1181 }
1182 
1183 
1184 static int
1185 dump_teams(int argc, char** argv)
1186 {
1187 	kprintf("team           id  parent      name\n");
1188 
1189 	for (TeamTable::Iterator it = sTeamHash.GetIterator();
1190 		Team* team = it.Next();) {
1191 		kprintf("%p%7ld  %p  %s\n", team, team->id, team->parent, team->Name());
1192 	}
1193 
1194 	return 0;
1195 }
1196 
1197 
1198 //	#pragma mark - Private functions
1199 
1200 
1201 /*!	Inserts team \a team into the child list of team \a parent.
1202 
1203 	The caller must hold the lock of both \a parent and \a team.
1204 
1205 	\param parent The parent team.
1206 	\param team The team to be inserted into \a parent's child list.
1207 */
1208 static void
1209 insert_team_into_parent(Team* parent, Team* team)
1210 {
1211 	ASSERT(parent != NULL);
1212 
1213 	team->siblings_next = parent->children;
1214 	parent->children = team;
1215 	team->parent = parent;
1216 }
1217 
1218 
1219 /*!	Removes team \a team from the child list of team \a parent.
1220 
1221 	The caller must hold the lock of both \a parent and \a team.
1222 
1223 	\param parent The parent team.
1224 	\param team The team to be removed from \a parent's child list.
1225 */
1226 static void
1227 remove_team_from_parent(Team* parent, Team* team)
1228 {
1229 	Team* child;
1230 	Team* last = NULL;
1231 
1232 	for (child = parent->children; child != NULL;
1233 			child = child->siblings_next) {
1234 		if (child == team) {
1235 			if (last == NULL)
1236 				parent->children = child->siblings_next;
1237 			else
1238 				last->siblings_next = child->siblings_next;
1239 
1240 			team->parent = NULL;
1241 			break;
1242 		}
1243 		last = child;
1244 	}
1245 }
1246 
1247 
1248 /*!	Returns whether the given team is a session leader.
1249 	The caller must hold the team's lock or its process group's lock.
1250 */
1251 static bool
1252 is_session_leader(Team* team)
1253 {
1254 	return team->session_id == team->id;
1255 }
1256 
1257 
1258 /*!	Returns whether the given team is a process group leader.
1259 	The caller must hold the team's lock or its process group's lock.
1260 */
1261 static bool
1262 is_process_group_leader(Team* team)
1263 {
1264 	return team->group_id == team->id;
1265 }
1266 
1267 
1268 /*!	Inserts the given team into the given process group.
1269 	The caller must hold the process group's lock, the team's lock, and the
1270 	team's parent's lock.
1271 */
1272 static void
1273 insert_team_into_group(ProcessGroup* group, Team* team)
1274 {
1275 	team->group = group;
1276 	team->group_id = group->id;
1277 	team->session_id = group->Session()->id;
1278 
1279 	team->group_next = group->teams;
1280 	group->teams = team;
1281 	group->AcquireReference();
1282 }
1283 
1284 
1285 /*!	Removes the given team from its process group.
1286 
1287 	The caller must hold the process group's lock, the team's lock, and the
1288 	team's parent's lock. Interrupts must be enabled.
1289 
1290 	\param team The team that'll be removed from its process group.
1291 */
1292 static void
1293 remove_team_from_group(Team* team)
1294 {
1295 	ProcessGroup* group = team->group;
1296 	Team* current;
1297 	Team* last = NULL;
1298 
1299 	// the team must be in a process group to let this function have any effect
1300 	if  (group == NULL)
1301 		return;
1302 
1303 	for (current = group->teams; current != NULL;
1304 			current = current->group_next) {
1305 		if (current == team) {
1306 			if (last == NULL)
1307 				group->teams = current->group_next;
1308 			else
1309 				last->group_next = current->group_next;
1310 
1311 			team->group = NULL;
1312 			break;
1313 		}
1314 		last = current;
1315 	}
1316 
1317 	team->group = NULL;
1318 	team->group_next = NULL;
1319 
1320 	group->ReleaseReference();
1321 }
1322 
1323 
1324 static status_t
1325 create_team_user_data(Team* team)
1326 {
1327 	void* address;
1328 	size_t size = 4 * B_PAGE_SIZE;
1329 	virtual_address_restrictions virtualRestrictions = {};
1330 	virtualRestrictions.address = (void*)KERNEL_USER_DATA_BASE;
1331 	virtualRestrictions.address_specification = B_BASE_ADDRESS;
1332 	physical_address_restrictions physicalRestrictions = {};
1333 	team->user_data_area = create_area_etc(team->id, "user area", size,
1334 		B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA, 0, &virtualRestrictions,
1335 		&physicalRestrictions, &address);
1336 	if (team->user_data_area < 0)
1337 		return team->user_data_area;
1338 
1339 	team->user_data = (addr_t)address;
1340 	team->used_user_data = 0;
1341 	team->user_data_size = size;
1342 	team->free_user_threads = NULL;
1343 
1344 	return B_OK;
1345 }
1346 
1347 
1348 static void
1349 delete_team_user_data(Team* team)
1350 {
1351 	if (team->user_data_area >= 0) {
1352 		vm_delete_area(team->id, team->user_data_area, true);
1353 		team->user_data = 0;
1354 		team->used_user_data = 0;
1355 		team->user_data_size = 0;
1356 		team->user_data_area = -1;
1357 		while (free_user_thread* entry = team->free_user_threads) {
1358 			team->free_user_threads = entry->next;
1359 			free(entry);
1360 		}
1361 	}
1362 }
1363 
1364 
1365 static status_t
1366 copy_user_process_args(const char* const* userFlatArgs, size_t flatArgsSize,
1367 	int32 argCount, int32 envCount, char**& _flatArgs)
1368 {
1369 	if (argCount < 0 || envCount < 0)
1370 		return B_BAD_VALUE;
1371 
1372 	if (flatArgsSize > MAX_PROCESS_ARGS_SIZE)
1373 		return B_TOO_MANY_ARGS;
1374 	if ((argCount + envCount + 2) * sizeof(char*) > flatArgsSize)
1375 		return B_BAD_VALUE;
1376 
1377 	if (!IS_USER_ADDRESS(userFlatArgs))
1378 		return B_BAD_ADDRESS;
1379 
1380 	// allocate kernel memory
1381 	char** flatArgs = (char**)malloc(flatArgsSize);
1382 	if (flatArgs == NULL)
1383 		return B_NO_MEMORY;
1384 
1385 	if (user_memcpy(flatArgs, userFlatArgs, flatArgsSize) != B_OK) {
1386 		free(flatArgs);
1387 		return B_BAD_ADDRESS;
1388 	}
1389 
1390 	// check and relocate the array
1391 	status_t error = B_OK;
1392 	const char* stringBase = (char*)flatArgs + argCount + envCount + 2;
1393 	const char* stringEnd = (char*)flatArgs + flatArgsSize;
1394 	for (int32 i = 0; i < argCount + envCount + 2; i++) {
1395 		if (i == argCount || i == argCount + envCount + 1) {
1396 			// check array null termination
1397 			if (flatArgs[i] != NULL) {
1398 				error = B_BAD_VALUE;
1399 				break;
1400 			}
1401 		} else {
1402 			// check string
1403 			char* arg = (char*)flatArgs + (flatArgs[i] - (char*)userFlatArgs);
1404 			size_t maxLen = stringEnd - arg;
1405 			if (arg < stringBase || arg >= stringEnd
1406 					|| strnlen(arg, maxLen) == maxLen) {
1407 				error = B_BAD_VALUE;
1408 				break;
1409 			}
1410 
1411 			flatArgs[i] = arg;
1412 		}
1413 	}
1414 
1415 	if (error == B_OK)
1416 		_flatArgs = flatArgs;
1417 	else
1418 		free(flatArgs);
1419 
1420 	return error;
1421 }
1422 
1423 
1424 static void
1425 free_team_arg(struct team_arg* teamArg)
1426 {
1427 	if (teamArg != NULL) {
1428 		free(teamArg->flat_args);
1429 		free(teamArg->path);
1430 		free(teamArg);
1431 	}
1432 }
1433 
1434 
1435 static status_t
1436 create_team_arg(struct team_arg** _teamArg, const char* path, char** flatArgs,
1437 	size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask,
1438 	port_id port, uint32 token)
1439 {
1440 	struct team_arg* teamArg = (struct team_arg*)malloc(sizeof(team_arg));
1441 	if (teamArg == NULL)
1442 		return B_NO_MEMORY;
1443 
1444 	teamArg->path = strdup(path);
1445 	if (teamArg->path == NULL) {
1446 		free(teamArg);
1447 		return B_NO_MEMORY;
1448 	}
1449 
1450 	// copy the args over
1451 
1452 	teamArg->flat_args = flatArgs;
1453 	teamArg->flat_args_size = flatArgsSize;
1454 	teamArg->arg_count = argCount;
1455 	teamArg->env_count = envCount;
1456 	teamArg->umask = umask;
1457 	teamArg->error_port = port;
1458 	teamArg->error_token = token;
1459 
1460 	*_teamArg = teamArg;
1461 	return B_OK;
1462 }
1463 
1464 
1465 static status_t
1466 team_create_thread_start_internal(void* args)
1467 {
1468 	status_t err;
1469 	Thread* thread;
1470 	Team* team;
1471 	struct team_arg* teamArgs = (struct team_arg*)args;
1472 	const char* path;
1473 	addr_t entry;
1474 	char** userArgs;
1475 	char** userEnv;
1476 	struct user_space_program_args* programArgs;
1477 	uint32 argCount, envCount;
1478 
1479 	thread = thread_get_current_thread();
1480 	team = thread->team;
1481 	cache_node_launched(teamArgs->arg_count, teamArgs->flat_args);
1482 
1483 	TRACE(("team_create_thread_start: entry thread %ld\n", thread->id));
1484 
1485 	// Main stack area layout is currently as follows (starting from 0):
1486 	//
1487 	// size								| usage
1488 	// ---------------------------------+--------------------------------
1489 	// USER_MAIN_THREAD_STACK_SIZE		| actual stack
1490 	// TLS_SIZE							| TLS data
1491 	// sizeof(user_space_program_args)	| argument structure for the runtime
1492 	//									| loader
1493 	// flat arguments size				| flat process arguments and environment
1494 
1495 	// TODO: ENV_SIZE is a) limited, and b) not used after libroot copied it to
1496 	// the heap
1497 	// TODO: we could reserve the whole USER_STACK_REGION upfront...
1498 
1499 	argCount = teamArgs->arg_count;
1500 	envCount = teamArgs->env_count;
1501 
1502 	programArgs = (struct user_space_program_args*)(thread->user_stack_base
1503 		+ thread->user_stack_size + TLS_SIZE);
1504 
1505 	userArgs = (char**)(programArgs + 1);
1506 	userEnv = userArgs + argCount + 1;
1507 	path = teamArgs->path;
1508 
1509 	if (user_strlcpy(programArgs->program_path, path,
1510 				sizeof(programArgs->program_path)) < B_OK
1511 		|| user_memcpy(&programArgs->arg_count, &argCount, sizeof(int32)) < B_OK
1512 		|| user_memcpy(&programArgs->args, &userArgs, sizeof(char**)) < B_OK
1513 		|| user_memcpy(&programArgs->env_count, &envCount, sizeof(int32)) < B_OK
1514 		|| user_memcpy(&programArgs->env, &userEnv, sizeof(char**)) < B_OK
1515 		|| user_memcpy(&programArgs->error_port, &teamArgs->error_port,
1516 				sizeof(port_id)) < B_OK
1517 		|| user_memcpy(&programArgs->error_token, &teamArgs->error_token,
1518 				sizeof(uint32)) < B_OK
1519 		|| user_memcpy(&programArgs->umask, &teamArgs->umask, sizeof(mode_t)) < B_OK
1520 		|| user_memcpy(userArgs, teamArgs->flat_args,
1521 				teamArgs->flat_args_size) < B_OK) {
1522 		// the team deletion process will clean this mess
1523 		free_team_arg(teamArgs);
1524 		return B_BAD_ADDRESS;
1525 	}
1526 
1527 	TRACE(("team_create_thread_start: loading elf binary '%s'\n", path));
1528 
1529 	// set team args and update state
1530 	team->Lock();
1531 	team->SetArgs(path, teamArgs->flat_args + 1, argCount - 1);
1532 	team->state = TEAM_STATE_NORMAL;
1533 	team->Unlock();
1534 
1535 	free_team_arg(teamArgs);
1536 		// the arguments are already on the user stack, we no longer need
1537 		// them in this form
1538 
1539 	// NOTE: Normally arch_thread_enter_userspace() never returns, that is
1540 	// automatic variables with function scope will never be destroyed.
1541 	{
1542 		// find runtime_loader path
1543 		KPath runtimeLoaderPath;
1544 		err = find_directory(B_BEOS_SYSTEM_DIRECTORY, gBootDevice, false,
1545 			runtimeLoaderPath.LockBuffer(), runtimeLoaderPath.BufferSize());
1546 		if (err < B_OK) {
1547 			TRACE(("team_create_thread_start: find_directory() failed: %s\n",
1548 				strerror(err)));
1549 			return err;
1550 		}
1551 		runtimeLoaderPath.UnlockBuffer();
1552 		err = runtimeLoaderPath.Append("runtime_loader");
1553 
1554 		if (err == B_OK) {
1555 			err = elf_load_user_image(runtimeLoaderPath.Path(), team, 0,
1556 				&entry);
1557 		}
1558 	}
1559 
1560 	if (err < B_OK) {
1561 		// Luckily, we don't have to clean up the mess we created - that's
1562 		// done for us by the normal team deletion process
1563 		TRACE(("team_create_thread_start: elf_load_user_image() failed: "
1564 			"%s\n", strerror(err)));
1565 		return err;
1566 	}
1567 
1568 	TRACE(("team_create_thread_start: loaded elf. entry = %#lx\n", entry));
1569 
1570 	// enter userspace -- returns only in case of error
1571 	return thread_enter_userspace_new_team(thread, (addr_t)entry,
1572 		programArgs, NULL);
1573 }
1574 
1575 
1576 static status_t
1577 team_create_thread_start(void* args)
1578 {
1579 	team_create_thread_start_internal(args);
1580 	thread_exit();
1581 		// does not return
1582 	return B_OK;
1583 }
1584 
1585 
1586 static thread_id
1587 load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount,
1588 	int32 envCount, int32 priority, team_id parentID, uint32 flags,
1589 	port_id errorPort, uint32 errorToken)
1590 {
1591 	char** flatArgs = _flatArgs;
1592 	thread_id thread;
1593 	status_t status;
1594 	struct team_arg* teamArgs;
1595 	struct team_loading_info loadingInfo;
1596 	io_context* parentIOContext = NULL;
1597 	team_id teamID;
1598 
1599 	if (flatArgs == NULL || argCount == 0)
1600 		return B_BAD_VALUE;
1601 
1602 	const char* path = flatArgs[0];
1603 
1604 	TRACE(("load_image_internal: name '%s', args = %p, argCount = %ld\n",
1605 		path, flatArgs, argCount));
1606 
1607 	// cut the path from the main thread name
1608 	const char* threadName = strrchr(path, '/');
1609 	if (threadName != NULL)
1610 		threadName++;
1611 	else
1612 		threadName = path;
1613 
1614 	// create the main thread object
1615 	Thread* mainThread;
1616 	status = Thread::Create(threadName, mainThread);
1617 	if (status != B_OK)
1618 		return status;
1619 	BReference<Thread> mainThreadReference(mainThread, true);
1620 
1621 	// create team object
1622 	Team* team = Team::Create(mainThread->id, path, false);
1623 	if (team == NULL)
1624 		return B_NO_MEMORY;
1625 	BReference<Team> teamReference(team, true);
1626 
1627 	if (flags & B_WAIT_TILL_LOADED) {
1628 		loadingInfo.thread = thread_get_current_thread();
1629 		loadingInfo.result = B_ERROR;
1630 		loadingInfo.done = false;
1631 		team->loading_info = &loadingInfo;
1632 	}
1633 
1634 	// get the parent team
1635 	Team* parent = Team::Get(parentID);
1636 	if (parent == NULL)
1637 		return B_BAD_TEAM_ID;
1638 	BReference<Team> parentReference(parent, true);
1639 
1640 	parent->LockTeamAndProcessGroup();
1641 	team->Lock();
1642 
1643 	// inherit the parent's user/group
1644 	inherit_parent_user_and_group(team, parent);
1645 
1646  	InterruptsSpinLocker teamsLocker(sTeamHashLock);
1647 
1648 	sTeamHash.Insert(team);
1649 	sUsedTeams++;
1650 
1651 	teamsLocker.Unlock();
1652 
1653 	insert_team_into_parent(parent, team);
1654 	insert_team_into_group(parent->group, team);
1655 
1656 	// get a reference to the parent's I/O context -- we need it to create ours
1657 	parentIOContext = parent->io_context;
1658 	vfs_get_io_context(parentIOContext);
1659 
1660 	team->Unlock();
1661 	parent->UnlockTeamAndProcessGroup();
1662 
1663 	// notify team listeners
1664 	sNotificationService.Notify(TEAM_ADDED, team);
1665 
1666 	// check the executable's set-user/group-id permission
1667 	update_set_id_user_and_group(team, path);
1668 
1669 	status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize, argCount,
1670 		envCount, (mode_t)-1, errorPort, errorToken);
1671 	if (status != B_OK)
1672 		goto err1;
1673 
1674 	_flatArgs = NULL;
1675 		// args are owned by the team_arg structure now
1676 
1677 	// create a new io_context for this team
1678 	team->io_context = vfs_new_io_context(parentIOContext, true);
1679 	if (!team->io_context) {
1680 		status = B_NO_MEMORY;
1681 		goto err2;
1682 	}
1683 
1684 	// We don't need the parent's I/O context any longer.
1685 	vfs_put_io_context(parentIOContext);
1686 	parentIOContext = NULL;
1687 
1688 	// remove any fds that have the CLOEXEC flag set (emulating BeOS behaviour)
1689 	vfs_exec_io_context(team->io_context);
1690 
1691 	// create an address space for this team
1692 	status = VMAddressSpace::Create(team->id, USER_BASE, USER_SIZE, false,
1693 		&team->address_space);
1694 	if (status != B_OK)
1695 		goto err3;
1696 
1697 	// create the user data area
1698 	status = create_team_user_data(team);
1699 	if (status != B_OK)
1700 		goto err4;
1701 
1702 	// In case we start the main thread, we shouldn't access the team object
1703 	// afterwards, so cache the team's ID.
1704 	teamID = team->id;
1705 
1706 	// Create a kernel thread, but under the context of the new team
1707 	// The new thread will take over ownership of teamArgs.
1708 	thread = thread_create_thread(
1709 		ThreadCreationAttributes(team_create_thread_start, threadName,
1710 			B_NORMAL_PRIORITY, teamArgs, teamID, mainThread),
1711 		false);
1712 	if (thread < 0) {
1713 		status = thread;
1714 		goto err5;
1715 	}
1716 
1717 	// The team has been created successfully, so we keep the reference. Or
1718 	// more precisely: It's owned by the team's main thread, now.
1719 	teamReference.Detach();
1720 
1721 	// wait for the loader of the new team to finish its work
1722 	if ((flags & B_WAIT_TILL_LOADED) != 0) {
1723 		InterruptsSpinLocker schedulerLocker(gSchedulerLock);
1724 
1725 		// resume the team's main thread
1726 		if (mainThread != NULL && mainThread->state == B_THREAD_SUSPENDED)
1727 			scheduler_enqueue_in_run_queue(mainThread);
1728 
1729 		// Now suspend ourselves until loading is finished. We will be woken
1730 		// either by the thread, when it finished or aborted loading, or when
1731 		// the team is going to die (e.g. is killed). In either case the one
1732 		// setting `loadingInfo.done' is responsible for removing the info from
1733 		// the team structure.
1734 		while (!loadingInfo.done) {
1735 			thread_get_current_thread()->next_state = B_THREAD_SUSPENDED;
1736 			scheduler_reschedule();
1737 		}
1738 
1739 		schedulerLocker.Unlock();
1740 
1741 		if (loadingInfo.result < B_OK)
1742 			return loadingInfo.result;
1743 	}
1744 
1745 	// notify the debugger
1746 	user_debug_team_created(teamID);
1747 
1748 	return thread;
1749 
1750 err5:
1751 	delete_team_user_data(team);
1752 err4:
1753 	team->address_space->Put();
1754 err3:
1755 	vfs_put_io_context(team->io_context);
1756 err2:
1757 	free_team_arg(teamArgs);
1758 err1:
1759 	if (parentIOContext != NULL)
1760 		vfs_put_io_context(parentIOContext);
1761 
1762 	// Remove the team structure from the process group, the parent team, and
1763 	// the team hash table and delete the team structure.
1764 	parent->LockTeamAndProcessGroup();
1765 	team->Lock();
1766 
1767 	remove_team_from_group(team);
1768 	remove_team_from_parent(team->parent, team);
1769 
1770 	team->Unlock();
1771 	parent->UnlockTeamAndProcessGroup();
1772 
1773 	teamsLocker.Lock();
1774 	sTeamHash.Remove(team);
1775 	teamsLocker.Unlock();
1776 
1777 	sNotificationService.Notify(TEAM_REMOVED, team);
1778 
1779 	return status;
1780 }
1781 
1782 
1783 /*!	Almost shuts down the current team and loads a new image into it.
1784 	If successful, this function does not return and will takeover ownership of
1785 	the arguments provided.
1786 	This function may only be called in a userland team (caused by one of the
1787 	exec*() syscalls).
1788 */
1789 static status_t
1790 exec_team(const char* path, char**& _flatArgs, size_t flatArgsSize,
1791 	int32 argCount, int32 envCount, mode_t umask)
1792 {
1793 	// NOTE: Since this function normally doesn't return, don't use automatic
1794 	// variables that need destruction in the function scope.
1795 	char** flatArgs = _flatArgs;
1796 	Team* team = thread_get_current_thread()->team;
1797 	struct team_arg* teamArgs;
1798 	const char* threadName;
1799 	thread_id nubThreadID = -1;
1800 
1801 	TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld): team %ld\n",
1802 		path, argCount, envCount, team->id));
1803 
1804 	T(ExecTeam(path, argCount, flatArgs, envCount, flatArgs + argCount + 1));
1805 
1806 	// switching the kernel at run time is probably not a good idea :)
1807 	if (team == team_get_kernel_team())
1808 		return B_NOT_ALLOWED;
1809 
1810 	// we currently need to be single threaded here
1811 	// TODO: maybe we should just kill all other threads and
1812 	//	make the current thread the team's main thread?
1813 	Thread* currentThread = thread_get_current_thread();
1814 	if (currentThread != team->main_thread)
1815 		return B_NOT_ALLOWED;
1816 
1817 	// The debug nub thread, a pure kernel thread, is allowed to survive.
1818 	// We iterate through the thread list to make sure that there's no other
1819 	// thread.
1820 	TeamLocker teamLocker(team);
1821 	InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
1822 
1823 	if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED)
1824 		nubThreadID = team->debug_info.nub_thread;
1825 
1826 	debugInfoLocker.Unlock();
1827 
1828 	for (Thread* thread = team->thread_list; thread != NULL;
1829 			thread = thread->team_next) {
1830 		if (thread != team->main_thread && thread->id != nubThreadID)
1831 			return B_NOT_ALLOWED;
1832 	}
1833 
1834 	team->DeleteUserTimers(true);
1835 	team->ResetSignalsOnExec();
1836 
1837 	teamLocker.Unlock();
1838 
1839 	status_t status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize,
1840 		argCount, envCount, umask, -1, 0);
1841 	if (status != B_OK)
1842 		return status;
1843 
1844 	_flatArgs = NULL;
1845 		// args are owned by the team_arg structure now
1846 
1847 	// TODO: remove team resources if there are any left
1848 	// thread_atkernel_exit() might not be called at all
1849 
1850 	thread_reset_for_exec();
1851 
1852 	user_debug_prepare_for_exec();
1853 
1854 	delete_team_user_data(team);
1855 	vm_delete_areas(team->address_space, false);
1856 	xsi_sem_undo(team);
1857 	delete_owned_ports(team);
1858 	sem_delete_owned_sems(team);
1859 	remove_images(team);
1860 	vfs_exec_io_context(team->io_context);
1861 	delete_realtime_sem_context(team->realtime_sem_context);
1862 	team->realtime_sem_context = NULL;
1863 
1864 	status = create_team_user_data(team);
1865 	if (status != B_OK) {
1866 		// creating the user data failed -- we're toast
1867 		// TODO: We should better keep the old user area in the first place.
1868 		free_team_arg(teamArgs);
1869 		exit_thread(status);
1870 		return status;
1871 	}
1872 
1873 	user_debug_finish_after_exec();
1874 
1875 	// rename the team
1876 
1877 	team->Lock();
1878 	team->SetName(path);
1879 	team->Unlock();
1880 
1881 	// cut the path from the team name and rename the main thread, too
1882 	threadName = strrchr(path, '/');
1883 	if (threadName != NULL)
1884 		threadName++;
1885 	else
1886 		threadName = path;
1887 	rename_thread(thread_get_current_thread_id(), threadName);
1888 
1889 	atomic_or(&team->flags, TEAM_FLAG_EXEC_DONE);
1890 
1891 	// Update user/group according to the executable's set-user/group-id
1892 	// permission.
1893 	update_set_id_user_and_group(team, path);
1894 
1895 	user_debug_team_exec();
1896 
1897 	// notify team listeners
1898 	sNotificationService.Notify(TEAM_EXEC, team);
1899 
1900 	// get a user thread for the thread
1901 	user_thread* userThread = team_allocate_user_thread(team);
1902 		// cannot fail (the allocation for the team would have failed already)
1903 	ThreadLocker currentThreadLocker(currentThread);
1904 	currentThread->user_thread = userThread;
1905 	currentThreadLocker.Unlock();
1906 
1907 	// create the user stack for the thread
1908 	status = thread_create_user_stack(currentThread->team, currentThread, NULL,
1909 		0, sizeof(user_space_program_args) + teamArgs->flat_args_size);
1910 	if (status == B_OK) {
1911 		// prepare the stack, load the runtime loader, and enter userspace
1912 		team_create_thread_start(teamArgs);
1913 			// does never return
1914 	} else
1915 		free_team_arg(teamArgs);
1916 
1917 	// Sorry, we have to kill ourselves, there is no way out anymore
1918 	// (without any areas left and all that).
1919 	exit_thread(status);
1920 
1921 	// We return a status here since the signal that is sent by the
1922 	// call above is not immediately handled.
1923 	return B_ERROR;
1924 }
1925 
1926 
1927 static thread_id
1928 fork_team(void)
1929 {
1930 	Thread* parentThread = thread_get_current_thread();
1931 	Team* parentTeam = parentThread->team;
1932 	Team* team;
1933 	arch_fork_arg* forkArgs;
1934 	struct area_info info;
1935 	thread_id threadID;
1936 	status_t status;
1937 	int32 cookie;
1938 
1939 	TRACE(("fork_team(): team %ld\n", parentTeam->id));
1940 
1941 	if (parentTeam == team_get_kernel_team())
1942 		return B_NOT_ALLOWED;
1943 
1944 	// create a new team
1945 	// TODO: this is very similar to load_image_internal() - maybe we can do
1946 	// something about it :)
1947 
1948 	// create the main thread object
1949 	Thread* thread;
1950 	status = Thread::Create(parentThread->name, thread);
1951 	if (status != B_OK)
1952 		return status;
1953 	BReference<Thread> threadReference(thread, true);
1954 
1955 	// create the team object
1956 	team = Team::Create(thread->id, NULL, false);
1957 	if (team == NULL)
1958 		return B_NO_MEMORY;
1959 
1960 	parentTeam->LockTeamAndProcessGroup();
1961 	team->Lock();
1962 
1963 	team->SetName(parentTeam->Name());
1964 	team->SetArgs(parentTeam->Args());
1965 
1966 	// Inherit the parent's user/group.
1967 	inherit_parent_user_and_group(team, parentTeam);
1968 
1969 	// inherit signal handlers
1970 	team->InheritSignalActions(parentTeam);
1971 
1972 	InterruptsSpinLocker teamsLocker(sTeamHashLock);
1973 
1974 	sTeamHash.Insert(team);
1975 	sUsedTeams++;
1976 
1977 	teamsLocker.Unlock();
1978 
1979 	insert_team_into_parent(parentTeam, team);
1980 	insert_team_into_group(parentTeam->group, team);
1981 
1982 	team->Unlock();
1983 	parentTeam->UnlockTeamAndProcessGroup();
1984 
1985 	// notify team listeners
1986 	sNotificationService.Notify(TEAM_ADDED, team);
1987 
1988 	// inherit some team debug flags
1989 	team->debug_info.flags |= atomic_get(&parentTeam->debug_info.flags)
1990 		& B_TEAM_DEBUG_INHERITED_FLAGS;
1991 
1992 	forkArgs = (arch_fork_arg*)malloc(sizeof(arch_fork_arg));
1993 	if (forkArgs == NULL) {
1994 		status = B_NO_MEMORY;
1995 		goto err1;
1996 	}
1997 
1998 	// create a new io_context for this team
1999 	team->io_context = vfs_new_io_context(parentTeam->io_context, false);
2000 	if (!team->io_context) {
2001 		status = B_NO_MEMORY;
2002 		goto err2;
2003 	}
2004 
2005 	// duplicate the realtime sem context
2006 	if (parentTeam->realtime_sem_context) {
2007 		team->realtime_sem_context = clone_realtime_sem_context(
2008 			parentTeam->realtime_sem_context);
2009 		if (team->realtime_sem_context == NULL) {
2010 			status = B_NO_MEMORY;
2011 			goto err25;
2012 		}
2013 	}
2014 
2015 	// create an address space for this team
2016 	status = VMAddressSpace::Create(team->id, USER_BASE, USER_SIZE, false,
2017 		&team->address_space);
2018 	if (status < B_OK)
2019 		goto err3;
2020 
2021 	// copy all areas of the team
2022 	// TODO: should be able to handle stack areas differently (ie. don't have
2023 	// them copy-on-write)
2024 
2025 	cookie = 0;
2026 	while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
2027 		if (info.area == parentTeam->user_data_area) {
2028 			// don't clone the user area; just create a new one
2029 			status = create_team_user_data(team);
2030 			if (status != B_OK)
2031 				break;
2032 
2033 			thread->user_thread = team_allocate_user_thread(team);
2034 		} else {
2035 			void* address;
2036 			area_id area = vm_copy_area(team->address_space->ID(), info.name,
2037 				&address, B_CLONE_ADDRESS, info.protection, info.area);
2038 			if (area < B_OK) {
2039 				status = area;
2040 				break;
2041 			}
2042 
2043 			if (info.area == parentThread->user_stack_area)
2044 				thread->user_stack_area = area;
2045 		}
2046 	}
2047 
2048 	if (status < B_OK)
2049 		goto err4;
2050 
2051 	if (thread->user_thread == NULL) {
2052 #if KDEBUG
2053 		panic("user data area not found, parent area is %ld",
2054 			parentTeam->user_data_area);
2055 #endif
2056 		status = B_ERROR;
2057 		goto err4;
2058 	}
2059 
2060 	thread->user_stack_base = parentThread->user_stack_base;
2061 	thread->user_stack_size = parentThread->user_stack_size;
2062 	thread->user_local_storage = parentThread->user_local_storage;
2063 	thread->sig_block_mask = parentThread->sig_block_mask;
2064 	thread->signal_stack_base = parentThread->signal_stack_base;
2065 	thread->signal_stack_size = parentThread->signal_stack_size;
2066 	thread->signal_stack_enabled = parentThread->signal_stack_enabled;
2067 
2068 	arch_store_fork_frame(forkArgs);
2069 
2070 	// copy image list
2071 	image_info imageInfo;
2072 	cookie = 0;
2073 	while (get_next_image_info(parentTeam->id, &cookie, &imageInfo) == B_OK) {
2074 		image_id image = register_image(team, &imageInfo, sizeof(imageInfo));
2075 		if (image < 0)
2076 			goto err5;
2077 	}
2078 
2079 	// create the main thread
2080 	{
2081 		ThreadCreationAttributes threadCreationAttributes(NULL,
2082 			parentThread->name, parentThread->priority, NULL, team->id, thread);
2083 		threadCreationAttributes.forkArgs = forkArgs;
2084 		threadID = thread_create_thread(threadCreationAttributes, false);
2085 		if (threadID < 0) {
2086 			status = threadID;
2087 			goto err5;
2088 		}
2089 	}
2090 
2091 	// notify the debugger
2092 	user_debug_team_created(team->id);
2093 
2094 	T(TeamForked(threadID));
2095 
2096 	resume_thread(threadID);
2097 	return threadID;
2098 
2099 err5:
2100 	remove_images(team);
2101 err4:
2102 	team->address_space->RemoveAndPut();
2103 err3:
2104 	delete_realtime_sem_context(team->realtime_sem_context);
2105 err25:
2106 	vfs_put_io_context(team->io_context);
2107 err2:
2108 	free(forkArgs);
2109 err1:
2110 	// Remove the team structure from the process group, the parent team, and
2111 	// the team hash table and delete the team structure.
2112 	parentTeam->LockTeamAndProcessGroup();
2113 	team->Lock();
2114 
2115 	remove_team_from_group(team);
2116 	remove_team_from_parent(team->parent, team);
2117 
2118 	team->Unlock();
2119 	parentTeam->UnlockTeamAndProcessGroup();
2120 
2121 	teamsLocker.Lock();
2122 	sTeamHash.Remove(team);
2123 	teamsLocker.Unlock();
2124 
2125 	sNotificationService.Notify(TEAM_REMOVED, team);
2126 
2127 	team->ReleaseReference();
2128 
2129 	return status;
2130 }
2131 
2132 
2133 /*!	Returns if the specified team \a parent has any children belonging to the
2134 	process group with the specified ID \a groupID.
2135 	The caller must hold \a parent's lock.
2136 */
2137 static bool
2138 has_children_in_group(Team* parent, pid_t groupID)
2139 {
2140 	for (Team* child = parent->children; child != NULL;
2141 			child = child->siblings_next) {
2142 		TeamLocker childLocker(child);
2143 		if (child->group_id == groupID)
2144 			return true;
2145 	}
2146 
2147 	return false;
2148 }
2149 
2150 
2151 /*!	Returns the first job control entry from \a children, which matches \a id.
2152 	\a id can be:
2153 	- \code > 0 \endcode: Matching an entry with that team ID.
2154 	- \code == -1 \endcode: Matching any entry.
2155 	- \code < -1 \endcode: Matching any entry with a process group ID of \c -id.
2156 	\c 0 is an invalid value for \a id.
2157 
2158 	The caller must hold the lock of the team that \a children belongs to.
2159 
2160 	\param children The job control entry list to check.
2161 	\param id The match criterion.
2162 	\return The first matching entry or \c NULL, if none matches.
2163 */
2164 static job_control_entry*
2165 get_job_control_entry(team_job_control_children& children, pid_t id)
2166 {
2167 	for (JobControlEntryList::Iterator it = children.entries.GetIterator();
2168 		 job_control_entry* entry = it.Next();) {
2169 
2170 		if (id > 0) {
2171 			if (entry->thread == id)
2172 				return entry;
2173 		} else if (id == -1) {
2174 			return entry;
2175 		} else {
2176 			pid_t processGroup
2177 				= (entry->team ? entry->team->group_id : entry->group_id);
2178 			if (processGroup == -id)
2179 				return entry;
2180 		}
2181 	}
2182 
2183 	return NULL;
2184 }
2185 
2186 
2187 /*!	Returns the first job control entry from one of team's dead, continued, or
2188     stopped children which matches \a id.
2189 	\a id can be:
2190 	- \code > 0 \endcode: Matching an entry with that team ID.
2191 	- \code == -1 \endcode: Matching any entry.
2192 	- \code < -1 \endcode: Matching any entry with a process group ID of \c -id.
2193 	\c 0 is an invalid value for \a id.
2194 
2195 	The caller must hold \a team's lock.
2196 
2197 	\param team The team whose dead, stopped, and continued child lists shall be
2198 		checked.
2199 	\param id The match criterion.
2200 	\param flags Specifies which children shall be considered. Dead children
2201 		always are. Stopped children are considered when \a flags is ORed
2202 		bitwise with \c WUNTRACED, continued children when \a flags is ORed
2203 		bitwise with \c WCONTINUED.
2204 	\return The first matching entry or \c NULL, if none matches.
2205 */
2206 static job_control_entry*
2207 get_job_control_entry(Team* team, pid_t id, uint32 flags)
2208 {
2209 	job_control_entry* entry = get_job_control_entry(team->dead_children, id);
2210 
2211 	if (entry == NULL && (flags & WCONTINUED) != 0)
2212 		entry = get_job_control_entry(team->continued_children, id);
2213 
2214 	if (entry == NULL && (flags & WUNTRACED) != 0)
2215 		entry = get_job_control_entry(team->stopped_children, id);
2216 
2217 	return entry;
2218 }
2219 
2220 
2221 job_control_entry::job_control_entry()
2222 	:
2223 	has_group_ref(false)
2224 {
2225 }
2226 
2227 
2228 job_control_entry::~job_control_entry()
2229 {
2230 	if (has_group_ref) {
2231 		InterruptsSpinLocker groupHashLocker(sGroupHashLock);
2232 
2233 		ProcessGroup* group = sGroupHash.Lookup(group_id);
2234 		if (group == NULL) {
2235 			panic("job_control_entry::~job_control_entry(): unknown group "
2236 				"ID: %ld", group_id);
2237 			return;
2238 		}
2239 
2240 		groupHashLocker.Unlock();
2241 
2242 		group->ReleaseReference();
2243 	}
2244 }
2245 
2246 
2247 /*!	Invoked when the owning team is dying, initializing the entry according to
2248 	the dead state.
2249 
2250 	The caller must hold the owning team's lock and the scheduler lock.
2251 */
2252 void
2253 job_control_entry::InitDeadState()
2254 {
2255 	if (team != NULL) {
2256 		ASSERT(team->exit.initialized);
2257 
2258 		group_id = team->group_id;
2259 		team->group->AcquireReference();
2260 		has_group_ref = true;
2261 
2262 		thread = team->id;
2263 		status = team->exit.status;
2264 		reason = team->exit.reason;
2265 		signal = team->exit.signal;
2266 		signaling_user = team->exit.signaling_user;
2267 
2268 		team = NULL;
2269 	}
2270 }
2271 
2272 
2273 job_control_entry&
2274 job_control_entry::operator=(const job_control_entry& other)
2275 {
2276 	state = other.state;
2277 	thread = other.thread;
2278 	signal = other.signal;
2279 	has_group_ref = false;
2280 	signaling_user = other.signaling_user;
2281 	team = other.team;
2282 	group_id = other.group_id;
2283 	status = other.status;
2284 	reason = other.reason;
2285 
2286 	return *this;
2287 }
2288 
2289 
2290 /*! This is the kernel backend for waitid().
2291 */
2292 static thread_id
2293 wait_for_child(pid_t child, uint32 flags, siginfo_t& _info)
2294 {
2295 	Thread* thread = thread_get_current_thread();
2296 	Team* team = thread->team;
2297 	struct job_control_entry foundEntry;
2298 	struct job_control_entry* freeDeathEntry = NULL;
2299 	status_t status = B_OK;
2300 
2301 	TRACE(("wait_for_child(child = %ld, flags = %ld)\n", child, flags));
2302 
2303 	T(WaitForChild(child, flags));
2304 
2305 	pid_t originalChild = child;
2306 
2307 	bool ignoreFoundEntries = false;
2308 	bool ignoreFoundEntriesChecked = false;
2309 
2310 	while (true) {
2311 		// lock the team
2312 		TeamLocker teamLocker(team);
2313 
2314 		// A 0 child argument means to wait for all children in the process
2315 		// group of the calling team.
2316 		child = originalChild == 0 ? -team->group_id : originalChild;
2317 
2318 		// check whether any condition holds
2319 		job_control_entry* entry = get_job_control_entry(team, child, flags);
2320 
2321 		// If we don't have an entry yet, check whether there are any children
2322 		// complying to the process group specification at all.
2323 		if (entry == NULL) {
2324 			// No success yet -- check whether there are any children complying
2325 			// to the process group specification at all.
2326 			bool childrenExist = false;
2327 			if (child == -1) {
2328 				childrenExist = team->children != NULL;
2329 			} else if (child < -1) {
2330 				childrenExist = has_children_in_group(team, -child);
2331 			} else {
2332 				if (Team* childTeam = Team::Get(child)) {
2333 					BReference<Team> childTeamReference(childTeam, true);
2334 					TeamLocker childTeamLocker(childTeam);
2335 					childrenExist = childTeam->parent == team;
2336 				}
2337 			}
2338 
2339 			if (!childrenExist) {
2340 				// there is no child we could wait for
2341 				status = ECHILD;
2342 			} else {
2343 				// the children we're waiting for are still running
2344 				status = B_WOULD_BLOCK;
2345 			}
2346 		} else {
2347 			// got something
2348 			foundEntry = *entry;
2349 
2350 			// unless WNOWAIT has been specified, "consume" the wait state
2351 			if ((flags & WNOWAIT) == 0 || ignoreFoundEntries) {
2352 				if (entry->state == JOB_CONTROL_STATE_DEAD) {
2353 					// The child is dead. Reap its death entry.
2354 					freeDeathEntry = entry;
2355 					team->dead_children.entries.Remove(entry);
2356 					team->dead_children.count--;
2357 				} else {
2358 					// The child is well. Reset its job control state.
2359 					team_set_job_control_state(entry->team,
2360 						JOB_CONTROL_STATE_NONE, NULL, false);
2361 				}
2362 			}
2363 		}
2364 
2365 		// If we haven't got anything yet, prepare for waiting for the
2366 		// condition variable.
2367 		ConditionVariableEntry deadWaitEntry;
2368 
2369 		if (status == B_WOULD_BLOCK && (flags & WNOHANG) == 0)
2370 			team->dead_children.condition_variable.Add(&deadWaitEntry);
2371 
2372 		teamLocker.Unlock();
2373 
2374 		// we got our entry and can return to our caller
2375 		if (status == B_OK) {
2376 			if (ignoreFoundEntries) {
2377 				// ... unless we shall ignore found entries
2378 				delete freeDeathEntry;
2379 				freeDeathEntry = NULL;
2380 				continue;
2381 			}
2382 
2383 			break;
2384 		}
2385 
2386 		if (status != B_WOULD_BLOCK || (flags & WNOHANG) != 0) {
2387 			T(WaitForChildDone(status));
2388 			return status;
2389 		}
2390 
2391 		status = deadWaitEntry.Wait(B_CAN_INTERRUPT);
2392 		if (status == B_INTERRUPTED) {
2393 			T(WaitForChildDone(status));
2394 			return status;
2395 		}
2396 
2397 		// If SA_NOCLDWAIT is set or SIGCHLD is ignored, we shall wait until
2398 		// all our children are dead and fail with ECHILD. We check the
2399 		// condition at this point.
2400 		if (!ignoreFoundEntriesChecked) {
2401 			teamLocker.Lock();
2402 
2403 			struct sigaction& handler = team->SignalActionFor(SIGCHLD);
2404 			if ((handler.sa_flags & SA_NOCLDWAIT) != 0
2405 				|| handler.sa_handler == SIG_IGN) {
2406 				ignoreFoundEntries = true;
2407 			}
2408 
2409 			teamLocker.Unlock();
2410 
2411 			ignoreFoundEntriesChecked = true;
2412 		}
2413 	}
2414 
2415 	delete freeDeathEntry;
2416 
2417 	// When we got here, we have a valid death entry, and already got
2418 	// unregistered from the team or group. Fill in the returned info.
2419 	memset(&_info, 0, sizeof(_info));
2420 	_info.si_signo = SIGCHLD;
2421 	_info.si_pid = foundEntry.thread;
2422 	_info.si_uid = foundEntry.signaling_user;
2423 	// TODO: Fill in si_errno?
2424 
2425 	switch (foundEntry.state) {
2426 		case JOB_CONTROL_STATE_DEAD:
2427 			_info.si_code = foundEntry.reason;
2428 			_info.si_status = foundEntry.reason == CLD_EXITED
2429 				? foundEntry.status : foundEntry.signal;
2430 			break;
2431 		case JOB_CONTROL_STATE_STOPPED:
2432 			_info.si_code = CLD_STOPPED;
2433 			_info.si_status = foundEntry.signal;
2434 			break;
2435 		case JOB_CONTROL_STATE_CONTINUED:
2436 			_info.si_code = CLD_CONTINUED;
2437 			_info.si_status = 0;
2438 			break;
2439 		case JOB_CONTROL_STATE_NONE:
2440 			// can't happen
2441 			break;
2442 	}
2443 
2444 	// If SIGCHLD is blocked, we shall clear pending SIGCHLDs, if no other child
2445 	// status is available.
2446 	TeamLocker teamLocker(team);
2447 	InterruptsSpinLocker schedulerLocker(gSchedulerLock);
2448 
2449 	if (is_team_signal_blocked(team, SIGCHLD)) {
2450 		if (get_job_control_entry(team, child, flags) == NULL)
2451 			team->RemovePendingSignals(SIGNAL_TO_MASK(SIGCHLD));
2452 	}
2453 
2454 	schedulerLocker.Unlock();
2455 	teamLocker.Unlock();
2456 
2457 	// When the team is dead, the main thread continues to live in the kernel
2458 	// team for a very short time. To avoid surprises for the caller we rather
2459 	// wait until the thread is really gone.
2460 	if (foundEntry.state == JOB_CONTROL_STATE_DEAD)
2461 		wait_for_thread(foundEntry.thread, NULL);
2462 
2463 	T(WaitForChildDone(foundEntry));
2464 
2465 	return foundEntry.thread;
2466 }
2467 
2468 
2469 /*! Fills the team_info structure with information from the specified team.
2470 	Interrupts must be enabled. The team must not be locked.
2471 */
2472 static status_t
2473 fill_team_info(Team* team, team_info* info, size_t size)
2474 {
2475 	if (size != sizeof(team_info))
2476 		return B_BAD_VALUE;
2477 
2478 	// TODO: Set more informations for team_info
2479 	memset(info, 0, size);
2480 
2481 	info->team = team->id;
2482 		// immutable
2483 	info->image_count = count_images(team);
2484 		// protected by sImageMutex
2485 
2486 	TeamLocker teamLocker(team);
2487 	InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
2488 
2489 	info->thread_count = team->num_threads;
2490 	//info->area_count =
2491 	info->debugger_nub_thread = team->debug_info.nub_thread;
2492 	info->debugger_nub_port = team->debug_info.nub_port;
2493 	//info->uid =
2494 	//info->gid =
2495 
2496 	strlcpy(info->args, team->Args(), sizeof(info->args));
2497 	info->argc = 1;
2498 
2499 	return B_OK;
2500 }
2501 
2502 
2503 /*!	Returns whether the process group contains stopped processes.
2504 	The caller must hold the process group's lock.
2505 */
2506 static bool
2507 process_group_has_stopped_processes(ProcessGroup* group)
2508 {
2509 	Team* team = group->teams;
2510 	while (team != NULL) {
2511 		// the parent team's lock guards the job control entry -- acquire it
2512 		team->LockTeamAndParent(false);
2513 
2514 		if (team->job_control_entry != NULL
2515 			&& team->job_control_entry->state == JOB_CONTROL_STATE_STOPPED) {
2516 			team->UnlockTeamAndParent();
2517 			return true;
2518 		}
2519 
2520 		team->UnlockTeamAndParent();
2521 
2522 		team = team->group_next;
2523 	}
2524 
2525 	return false;
2526 }
2527 
2528 
2529 /*!	Iterates through all process groups queued in team_remove_team() and signals
2530 	those that are orphaned and have stopped processes.
2531 	The caller must not hold any team or process group locks.
2532 */
2533 static void
2534 orphaned_process_group_check()
2535 {
2536 	// process as long as there are groups in the list
2537 	while (true) {
2538 		// remove the head from the list
2539 		MutexLocker orphanedCheckLocker(sOrphanedCheckLock);
2540 
2541 		ProcessGroup* group = sOrphanedCheckProcessGroups.RemoveHead();
2542 		if (group == NULL)
2543 			return;
2544 
2545 		group->UnsetOrphanedCheck();
2546 		BReference<ProcessGroup> groupReference(group);
2547 
2548 		orphanedCheckLocker.Unlock();
2549 
2550 		AutoLocker<ProcessGroup> groupLocker(group);
2551 
2552 		// If the group is orphaned and contains stopped processes, we're
2553 		// supposed to send SIGHUP + SIGCONT.
2554 		if (group->IsOrphaned() && process_group_has_stopped_processes(group)) {
2555 			Thread* currentThread = thread_get_current_thread();
2556 
2557 			Signal signal(SIGHUP, SI_USER, B_OK, currentThread->team->id);
2558 			send_signal_to_process_group_locked(group, signal, 0);
2559 
2560 			signal.SetNumber(SIGCONT);
2561 			send_signal_to_process_group_locked(group, signal, 0);
2562 		}
2563 	}
2564 }
2565 
2566 
2567 static status_t
2568 common_get_team_usage_info(team_id id, int32 who, team_usage_info* info,
2569 	uint32 flags)
2570 {
2571 	if (who != B_TEAM_USAGE_SELF && who != B_TEAM_USAGE_CHILDREN)
2572 		return B_BAD_VALUE;
2573 
2574 	// get the team
2575 	Team* team = Team::GetAndLock(id);
2576 	if (team == NULL)
2577 		return B_BAD_TEAM_ID;
2578 	BReference<Team> teamReference(team, true);
2579 	TeamLocker teamLocker(team, true);
2580 
2581 	if ((flags & B_CHECK_PERMISSION) != 0) {
2582 		uid_t uid = geteuid();
2583 		if (uid != 0 && uid != team->effective_uid)
2584 			return B_NOT_ALLOWED;
2585 	}
2586 
2587 	bigtime_t kernelTime = 0;
2588 	bigtime_t userTime = 0;
2589 
2590 	switch (who) {
2591 		case B_TEAM_USAGE_SELF:
2592 		{
2593 			Thread* thread = team->thread_list;
2594 
2595 			for (; thread != NULL; thread = thread->team_next) {
2596 				InterruptsSpinLocker threadTimeLocker(thread->time_lock);
2597 				kernelTime += thread->kernel_time;
2598 				userTime += thread->user_time;
2599 			}
2600 
2601 			kernelTime += team->dead_threads_kernel_time;
2602 			userTime += team->dead_threads_user_time;
2603 			break;
2604 		}
2605 
2606 		case B_TEAM_USAGE_CHILDREN:
2607 		{
2608 			Team* child = team->children;
2609 			for (; child != NULL; child = child->siblings_next) {
2610 				TeamLocker childLocker(child);
2611 
2612 				Thread* thread = team->thread_list;
2613 
2614 				for (; thread != NULL; thread = thread->team_next) {
2615 					InterruptsSpinLocker threadTimeLocker(thread->time_lock);
2616 					kernelTime += thread->kernel_time;
2617 					userTime += thread->user_time;
2618 				}
2619 
2620 				kernelTime += child->dead_threads_kernel_time;
2621 				userTime += child->dead_threads_user_time;
2622 			}
2623 
2624 			kernelTime += team->dead_children.kernel_time;
2625 			userTime += team->dead_children.user_time;
2626 			break;
2627 		}
2628 	}
2629 
2630 	info->kernel_time = kernelTime;
2631 	info->user_time = userTime;
2632 
2633 	return B_OK;
2634 }
2635 
2636 
2637 //	#pragma mark - Private kernel API
2638 
2639 
2640 status_t
2641 team_init(kernel_args* args)
2642 {
2643 	// create the team hash table
2644 	new(&sTeamHash) TeamTable;
2645 	if (sTeamHash.Init(64) != B_OK)
2646 		panic("Failed to init team hash table!");
2647 
2648 	new(&sGroupHash) ProcessGroupHashTable;
2649 	if (sGroupHash.Init() != B_OK)
2650 		panic("Failed to init process group hash table!");
2651 
2652 	// create initial session and process groups
2653 
2654 	ProcessSession* session = new(std::nothrow) ProcessSession(1);
2655 	if (session == NULL)
2656 		panic("Could not create initial session.\n");
2657 	BReference<ProcessSession> sessionReference(session, true);
2658 
2659 	ProcessGroup* group = new(std::nothrow) ProcessGroup(1);
2660 	if (group == NULL)
2661 		panic("Could not create initial process group.\n");
2662 	BReference<ProcessGroup> groupReference(group, true);
2663 
2664 	group->Publish(session);
2665 
2666 	// create the kernel team
2667 	sKernelTeam = Team::Create(1, "kernel_team", true);
2668 	if (sKernelTeam == NULL)
2669 		panic("could not create kernel team!\n");
2670 	sKernelTeam->SetArgs(sKernelTeam->Name());
2671 	sKernelTeam->state = TEAM_STATE_NORMAL;
2672 
2673 	sKernelTeam->saved_set_uid = 0;
2674 	sKernelTeam->real_uid = 0;
2675 	sKernelTeam->effective_uid = 0;
2676 	sKernelTeam->saved_set_gid = 0;
2677 	sKernelTeam->real_gid = 0;
2678 	sKernelTeam->effective_gid = 0;
2679 	sKernelTeam->supplementary_groups = NULL;
2680 	sKernelTeam->supplementary_group_count = 0;
2681 
2682 	insert_team_into_group(group, sKernelTeam);
2683 
2684 	sKernelTeam->io_context = vfs_new_io_context(NULL, false);
2685 	if (sKernelTeam->io_context == NULL)
2686 		panic("could not create io_context for kernel team!\n");
2687 
2688 	// stick it in the team hash
2689 	sTeamHash.Insert(sKernelTeam);
2690 
2691 	add_debugger_command_etc("team", &dump_team_info,
2692 		"Dump info about a particular team",
2693 		"[ <id> | <address> | <name> ]\n"
2694 		"Prints information about the specified team. If no argument is given\n"
2695 		"the current team is selected.\n"
2696 		"  <id>       - The ID of the team.\n"
2697 		"  <address>  - The address of the team structure.\n"
2698 		"  <name>     - The team's name.\n", 0);
2699 	add_debugger_command_etc("teams", &dump_teams, "List all teams",
2700 		"\n"
2701 		"Prints a list of all existing teams.\n", 0);
2702 
2703 	new(&sNotificationService) TeamNotificationService();
2704 
2705 	return B_OK;
2706 }
2707 
2708 
2709 int32
2710 team_max_teams(void)
2711 {
2712 	return sMaxTeams;
2713 }
2714 
2715 
2716 int32
2717 team_used_teams(void)
2718 {
2719 	InterruptsSpinLocker teamsLocker(sTeamHashLock);
2720 	return sUsedTeams;
2721 }
2722 
2723 
2724 /*! Returns a death entry of a child team specified by ID (if any).
2725 	The caller must hold the team's lock.
2726 
2727 	\param team The team whose dead children list to check.
2728 	\param child The ID of the child for whose death entry to lock. Must be > 0.
2729 	\param _deleteEntry Return variable, indicating whether the caller needs to
2730 		delete the returned entry.
2731 	\return The death entry of the matching team, or \c NULL, if no death entry
2732 		for the team was found.
2733 */
2734 job_control_entry*
2735 team_get_death_entry(Team* team, thread_id child, bool* _deleteEntry)
2736 {
2737 	if (child <= 0)
2738 		return NULL;
2739 
2740 	job_control_entry* entry = get_job_control_entry(team->dead_children,
2741 		child);
2742 	if (entry) {
2743 		// remove the entry only, if the caller is the parent of the found team
2744 		if (team_get_current_team_id() == entry->thread) {
2745 			team->dead_children.entries.Remove(entry);
2746 			team->dead_children.count--;
2747 			*_deleteEntry = true;
2748 		} else {
2749 			*_deleteEntry = false;
2750 		}
2751 	}
2752 
2753 	return entry;
2754 }
2755 
2756 
2757 /*! Quick check to see if we have a valid team ID. */
2758 bool
2759 team_is_valid(team_id id)
2760 {
2761 	if (id <= 0)
2762 		return false;
2763 
2764 	InterruptsSpinLocker teamsLocker(sTeamHashLock);
2765 
2766 	return team_get_team_struct_locked(id) != NULL;
2767 }
2768 
2769 
2770 Team*
2771 team_get_team_struct_locked(team_id id)
2772 {
2773 	return sTeamHash.Lookup(id);
2774 }
2775 
2776 
2777 void
2778 team_set_controlling_tty(int32 ttyIndex)
2779 {
2780 	// lock the team, so its session won't change while we're playing with it
2781 	Team* team = thread_get_current_thread()->team;
2782 	TeamLocker teamLocker(team);
2783 
2784 	// get and lock the session
2785 	ProcessSession* session = team->group->Session();
2786 	AutoLocker<ProcessSession> sessionLocker(session);
2787 
2788 	// set the session's fields
2789 	session->controlling_tty = ttyIndex;
2790 	session->foreground_group = -1;
2791 }
2792 
2793 
2794 int32
2795 team_get_controlling_tty()
2796 {
2797 	// lock the team, so its session won't change while we're playing with it
2798 	Team* team = thread_get_current_thread()->team;
2799 	TeamLocker teamLocker(team);
2800 
2801 	// get and lock the session
2802 	ProcessSession* session = team->group->Session();
2803 	AutoLocker<ProcessSession> sessionLocker(session);
2804 
2805 	// get the session's field
2806 	return session->controlling_tty;
2807 }
2808 
2809 
2810 status_t
2811 team_set_foreground_process_group(int32 ttyIndex, pid_t processGroupID)
2812 {
2813 	// lock the team, so its session won't change while we're playing with it
2814 	Thread* thread = thread_get_current_thread();
2815 	Team* team = thread->team;
2816 	TeamLocker teamLocker(team);
2817 
2818 	// get and lock the session
2819 	ProcessSession* session = team->group->Session();
2820 	AutoLocker<ProcessSession> sessionLocker(session);
2821 
2822 	// check given TTY -- must be the controlling tty of the calling process
2823 	if (session->controlling_tty != ttyIndex)
2824 		return ENOTTY;
2825 
2826 	// check given process group -- must belong to our session
2827 	{
2828 		InterruptsSpinLocker groupHashLocker(sGroupHashLock);
2829 		ProcessGroup* group = sGroupHash.Lookup(processGroupID);
2830 		if (group == NULL || group->Session() != session)
2831 			return B_BAD_VALUE;
2832 	}
2833 
2834 	// If we are a background group, we can do that unharmed only when we
2835 	// ignore or block SIGTTOU. Otherwise the group gets a SIGTTOU.
2836 	if (session->foreground_group != -1
2837 		&& session->foreground_group != team->group_id
2838 		&& team->SignalActionFor(SIGTTOU).sa_handler != SIG_IGN) {
2839 		InterruptsSpinLocker schedulerLocker(gSchedulerLock);
2840 
2841 		if (!is_team_signal_blocked(team, SIGTTOU)) {
2842 			pid_t groupID = team->group_id;
2843 
2844 			schedulerLocker.Unlock();
2845 			sessionLocker.Unlock();
2846 			teamLocker.Unlock();
2847 
2848 			Signal signal(SIGTTOU, SI_USER, B_OK, team->id);
2849 			send_signal_to_process_group(groupID, signal, 0);
2850 			return B_INTERRUPTED;
2851 		}
2852 	}
2853 
2854 	session->foreground_group = processGroupID;
2855 
2856 	return B_OK;
2857 }
2858 
2859 
2860 /*!	Removes the specified team from the global team hash, from its process
2861 	group, and from its parent.
2862 	It also moves all of its children to the kernel team.
2863 
2864 	The caller must hold the following locks:
2865 	- \a team's process group's lock,
2866 	- the kernel team's lock,
2867 	- \a team's parent team's lock (might be the kernel team), and
2868 	- \a team's lock.
2869 */
2870 void
2871 team_remove_team(Team* team, pid_t& _signalGroup)
2872 {
2873 	Team* parent = team->parent;
2874 
2875 	// remember how long this team lasted
2876 	parent->dead_children.kernel_time += team->dead_threads_kernel_time
2877 		+ team->dead_children.kernel_time;
2878 	parent->dead_children.user_time += team->dead_threads_user_time
2879 		+ team->dead_children.user_time;
2880 
2881 	// remove the team from the hash table
2882 	InterruptsSpinLocker teamsLocker(sTeamHashLock);
2883 	sTeamHash.Remove(team);
2884 	sUsedTeams--;
2885 	teamsLocker.Unlock();
2886 
2887 	// The team can no longer be accessed by ID. Navigation to it is still
2888 	// possible from its process group and its parent and children, but that
2889 	// will be rectified shortly.
2890 	team->state = TEAM_STATE_DEATH;
2891 
2892 	// If we're a controlling process (i.e. a session leader with controlling
2893 	// terminal), there's a bit of signalling we have to do. We can't do any of
2894 	// the signaling here due to the bunch of locks we're holding, but we need
2895 	// to determine, whom to signal.
2896 	_signalGroup = -1;
2897 	bool isSessionLeader = false;
2898 	if (team->session_id == team->id
2899 		&& team->group->Session()->controlling_tty >= 0) {
2900 		isSessionLeader = true;
2901 
2902 		ProcessSession* session = team->group->Session();
2903 
2904 		AutoLocker<ProcessSession> sessionLocker(session);
2905 
2906 		session->controlling_tty = -1;
2907 		_signalGroup = session->foreground_group;
2908 	}
2909 
2910 	// remove us from our process group
2911 	remove_team_from_group(team);
2912 
2913 	// move the team's children to the kernel team
2914 	while (Team* child = team->children) {
2915 		// remove the child from the current team and add it to the kernel team
2916 		TeamLocker childLocker(child);
2917 
2918 		remove_team_from_parent(team, child);
2919 		insert_team_into_parent(sKernelTeam, child);
2920 
2921 		// move job control entries too
2922 		sKernelTeam->stopped_children.entries.MoveFrom(
2923 			&team->stopped_children.entries);
2924 		sKernelTeam->continued_children.entries.MoveFrom(
2925 			&team->continued_children.entries);
2926 
2927 		// If the team was a session leader with controlling terminal,
2928 		// we need to send SIGHUP + SIGCONT to all newly-orphaned process
2929 		// groups with stopped processes. Due to locking complications we can't
2930 		// do that here, so we only check whether we were a reason for the
2931 		// child's process group not being an orphan and, if so, schedule a
2932 		// later check (cf. orphaned_process_group_check()).
2933 		if (isSessionLeader) {
2934 			ProcessGroup* childGroup = child->group;
2935 			if (childGroup->Session()->id == team->session_id
2936 				&& childGroup->id != team->group_id) {
2937 				childGroup->ScheduleOrphanedCheck();
2938 			}
2939 		}
2940 
2941 		// Note, we don't move the dead children entries. Those will be deleted
2942 		// when the team structure is deleted.
2943 	}
2944 
2945 	// remove us from our parent
2946 	remove_team_from_parent(parent, team);
2947 }
2948 
2949 
2950 /*!	Kills all threads but the main thread of the team and shuts down user
2951 	debugging for it.
2952 	To be called on exit of the team's main thread. No locks must be held.
2953 
2954 	\param team The team in question.
2955 	\return The port of the debugger for the team, -1 if none. To be passed to
2956 		team_delete_team().
2957 */
2958 port_id
2959 team_shutdown_team(Team* team)
2960 {
2961 	ASSERT(thread_get_current_thread() == team->main_thread);
2962 
2963 	TeamLocker teamLocker(team);
2964 
2965 	// Make sure debugging changes won't happen anymore.
2966 	port_id debuggerPort = -1;
2967 	while (true) {
2968 		// If a debugger change is in progress for the team, we'll have to
2969 		// wait until it is done.
2970 		ConditionVariableEntry waitForDebuggerEntry;
2971 		bool waitForDebugger = false;
2972 
2973 		InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
2974 
2975 		if (team->debug_info.debugger_changed_condition != NULL) {
2976 			team->debug_info.debugger_changed_condition->Add(
2977 				&waitForDebuggerEntry);
2978 			waitForDebugger = true;
2979 		} else if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
2980 			// The team is being debugged. That will stop with the termination
2981 			// of the nub thread. Since we set the team state to death, no one
2982 			// can install a debugger anymore. We fetch the debugger's port to
2983 			// send it a message at the bitter end.
2984 			debuggerPort = team->debug_info.debugger_port;
2985 		}
2986 
2987 		debugInfoLocker.Unlock();
2988 
2989 		if (!waitForDebugger)
2990 			break;
2991 
2992 		// wait for the debugger change to be finished
2993 		teamLocker.Unlock();
2994 
2995 		waitForDebuggerEntry.Wait();
2996 
2997 		teamLocker.Lock();
2998 	}
2999 
3000 	// Mark the team as shutting down. That will prevent new threads from being
3001 	// created and debugger changes from taking place.
3002 	team->state = TEAM_STATE_SHUTDOWN;
3003 
3004 	// delete all timers
3005 	team->DeleteUserTimers(false);
3006 
3007 	// deactivate CPU time user timers for the team
3008 	InterruptsSpinLocker schedulerLocker(gSchedulerLock);
3009 
3010 	if (team->HasActiveCPUTimeUserTimers())
3011 		team->DeactivateCPUTimeUserTimers();
3012 
3013 	schedulerLocker.Unlock();
3014 
3015 	// kill all threads but the main thread
3016 	team_death_entry deathEntry;
3017 	deathEntry.condition.Init(team, "team death");
3018 
3019 	while (true) {
3020 		team->death_entry = &deathEntry;
3021 		deathEntry.remaining_threads = 0;
3022 
3023 		Thread* thread = team->thread_list;
3024 		while (thread != NULL) {
3025 			if (thread != team->main_thread) {
3026 				Signal signal(SIGKILLTHR, SI_USER, B_OK, team->id);
3027 				send_signal_to_thread(thread, signal, B_DO_NOT_RESCHEDULE);
3028 				deathEntry.remaining_threads++;
3029 			}
3030 
3031 			thread = thread->team_next;
3032 		}
3033 
3034 		if (deathEntry.remaining_threads == 0)
3035 			break;
3036 
3037 		// there are threads to wait for
3038 		ConditionVariableEntry entry;
3039 		deathEntry.condition.Add(&entry);
3040 
3041 		teamLocker.Unlock();
3042 
3043 		entry.Wait();
3044 
3045 		teamLocker.Lock();
3046 	}
3047 
3048 	team->death_entry = NULL;
3049 
3050 	return debuggerPort;
3051 }
3052 
3053 
3054 /*!	Called on team exit to notify threads waiting on the team and free most
3055 	resources associated with it.
3056 	The caller shouldn't hold any locks.
3057 */
3058 void
3059 team_delete_team(Team* team, port_id debuggerPort)
3060 {
3061 	// Not quite in our job description, but work that has been left by
3062 	// team_remove_team() and that can be done now that we're not holding any
3063 	// locks.
3064 	orphaned_process_group_check();
3065 
3066 	team_id teamID = team->id;
3067 
3068 	ASSERT(team->num_threads == 0);
3069 
3070 	// If someone is waiting for this team to be loaded, but it dies
3071 	// unexpectedly before being done, we need to notify the waiting
3072 	// thread now.
3073 
3074 	TeamLocker teamLocker(team);
3075 
3076 	if (team->loading_info) {
3077 		// there's indeed someone waiting
3078 		struct team_loading_info* loadingInfo = team->loading_info;
3079 		team->loading_info = NULL;
3080 
3081 		loadingInfo->result = B_ERROR;
3082 		loadingInfo->done = true;
3083 
3084 		InterruptsSpinLocker schedulerLocker(gSchedulerLock);
3085 
3086 		// wake up the waiting thread
3087 		if (loadingInfo->thread->state == B_THREAD_SUSPENDED)
3088 			scheduler_enqueue_in_run_queue(loadingInfo->thread);
3089 	}
3090 
3091 	// notify team watchers
3092 
3093 	{
3094 		// we're not reachable from anyone anymore at this point, so we
3095 		// can safely access the list without any locking
3096 		struct team_watcher* watcher;
3097 		while ((watcher = (struct team_watcher*)list_remove_head_item(
3098 				&team->watcher_list)) != NULL) {
3099 			watcher->hook(teamID, watcher->data);
3100 			free(watcher);
3101 		}
3102 	}
3103 
3104 	teamLocker.Unlock();
3105 
3106 	sNotificationService.Notify(TEAM_REMOVED, team);
3107 
3108 	// free team resources
3109 
3110 	delete_realtime_sem_context(team->realtime_sem_context);
3111 	xsi_sem_undo(team);
3112 	remove_images(team);
3113 	team->address_space->RemoveAndPut();
3114 
3115 	team->ReleaseReference();
3116 
3117 	// notify the debugger, that the team is gone
3118 	user_debug_team_deleted(teamID, debuggerPort);
3119 }
3120 
3121 
3122 Team*
3123 team_get_kernel_team(void)
3124 {
3125 	return sKernelTeam;
3126 }
3127 
3128 
3129 team_id
3130 team_get_kernel_team_id(void)
3131 {
3132 	if (!sKernelTeam)
3133 		return 0;
3134 
3135 	return sKernelTeam->id;
3136 }
3137 
3138 
3139 team_id
3140 team_get_current_team_id(void)
3141 {
3142 	return thread_get_current_thread()->team->id;
3143 }
3144 
3145 
3146 status_t
3147 team_get_address_space(team_id id, VMAddressSpace** _addressSpace)
3148 {
3149 	if (id == sKernelTeam->id) {
3150 		// we're the kernel team, so we don't have to go through all
3151 		// the hassle (locking and hash lookup)
3152 		*_addressSpace = VMAddressSpace::GetKernel();
3153 		return B_OK;
3154 	}
3155 
3156 	InterruptsSpinLocker teamsLocker(sTeamHashLock);
3157 
3158 	Team* team = team_get_team_struct_locked(id);
3159 	if (team == NULL)
3160 		return B_BAD_VALUE;
3161 
3162 	team->address_space->Get();
3163 	*_addressSpace = team->address_space;
3164 	return B_OK;
3165 }
3166 
3167 
3168 /*!	Sets the team's job control state.
3169 	The caller must hold the parent team's lock. Interrupts are allowed to be
3170 	enabled or disabled. In the latter case the scheduler lock may be held as
3171 	well.
3172 	\a team The team whose job control state shall be set.
3173 	\a newState The new state to be set.
3174 	\a signal The signal the new state was caused by. Can \c NULL, if none. Then
3175 		the caller is responsible for filling in the following fields of the
3176 		entry before releasing the parent team's lock, unless the new state is
3177 		\c JOB_CONTROL_STATE_NONE:
3178 		- \c signal: The number of the signal causing the state change.
3179 		- \c signaling_user: The real UID of the user sending the signal.
3180 	\a schedulerLocked indicates whether the scheduler lock is being held, too.
3181 */
3182 void
3183 team_set_job_control_state(Team* team, job_control_state newState,
3184 	Signal* signal, bool schedulerLocked)
3185 {
3186 	if (team == NULL || team->job_control_entry == NULL)
3187 		return;
3188 
3189 	// don't touch anything, if the state stays the same or the team is already
3190 	// dead
3191 	job_control_entry* entry = team->job_control_entry;
3192 	if (entry->state == newState || entry->state == JOB_CONTROL_STATE_DEAD)
3193 		return;
3194 
3195 	T(SetJobControlState(team->id, newState, signal));
3196 
3197 	// remove from the old list
3198 	switch (entry->state) {
3199 		case JOB_CONTROL_STATE_NONE:
3200 			// entry is in no list ATM
3201 			break;
3202 		case JOB_CONTROL_STATE_DEAD:
3203 			// can't get here
3204 			break;
3205 		case JOB_CONTROL_STATE_STOPPED:
3206 			team->parent->stopped_children.entries.Remove(entry);
3207 			break;
3208 		case JOB_CONTROL_STATE_CONTINUED:
3209 			team->parent->continued_children.entries.Remove(entry);
3210 			break;
3211 	}
3212 
3213 	entry->state = newState;
3214 
3215 	if (signal != NULL) {
3216 		entry->signal = signal->Number();
3217 		entry->signaling_user = signal->SendingUser();
3218 	}
3219 
3220 	// add to new list
3221 	team_job_control_children* childList = NULL;
3222 	switch (entry->state) {
3223 		case JOB_CONTROL_STATE_NONE:
3224 			// entry doesn't get into any list
3225 			break;
3226 		case JOB_CONTROL_STATE_DEAD:
3227 			childList = &team->parent->dead_children;
3228 			team->parent->dead_children.count++;
3229 			break;
3230 		case JOB_CONTROL_STATE_STOPPED:
3231 			childList = &team->parent->stopped_children;
3232 			break;
3233 		case JOB_CONTROL_STATE_CONTINUED:
3234 			childList = &team->parent->continued_children;
3235 			break;
3236 	}
3237 
3238 	if (childList != NULL) {
3239 		childList->entries.Add(entry);
3240 		team->parent->dead_children.condition_variable.NotifyAll(
3241 			schedulerLocked);
3242 	}
3243 }
3244 
3245 
3246 /*! Adds a hook to the team that is called as soon as this team goes away.
3247 	This call might get public in the future.
3248 */
3249 status_t
3250 start_watching_team(team_id teamID, void (*hook)(team_id, void*), void* data)
3251 {
3252 	if (hook == NULL || teamID < B_OK)
3253 		return B_BAD_VALUE;
3254 
3255 	// create the watcher object
3256 	team_watcher* watcher = (team_watcher*)malloc(sizeof(team_watcher));
3257 	if (watcher == NULL)
3258 		return B_NO_MEMORY;
3259 
3260 	watcher->hook = hook;
3261 	watcher->data = data;
3262 
3263 	// add watcher, if the team isn't already dying
3264 	// get the team
3265 	Team* team = Team::GetAndLock(teamID);
3266 	if (team == NULL) {
3267 		free(watcher);
3268 		return B_BAD_TEAM_ID;
3269 	}
3270 
3271 	list_add_item(&team->watcher_list, watcher);
3272 
3273 	team->UnlockAndReleaseReference();
3274 
3275 	return B_OK;
3276 }
3277 
3278 
3279 status_t
3280 stop_watching_team(team_id teamID, void (*hook)(team_id, void*), void* data)
3281 {
3282 	if (hook == NULL || teamID < 0)
3283 		return B_BAD_VALUE;
3284 
3285 	// get team and remove watcher (if present)
3286 	Team* team = Team::GetAndLock(teamID);
3287 	if (team == NULL)
3288 		return B_BAD_TEAM_ID;
3289 
3290 	// search for watcher
3291 	team_watcher* watcher = NULL;
3292 	while ((watcher = (team_watcher*)list_get_next_item(
3293 			&team->watcher_list, watcher)) != NULL) {
3294 		if (watcher->hook == hook && watcher->data == data) {
3295 			// got it!
3296 			list_remove_item(&team->watcher_list, watcher);
3297 			break;
3298 		}
3299 	}
3300 
3301 	team->UnlockAndReleaseReference();
3302 
3303 	if (watcher == NULL)
3304 		return B_ENTRY_NOT_FOUND;
3305 
3306 	free(watcher);
3307 	return B_OK;
3308 }
3309 
3310 
3311 /*!	Allocates a user_thread structure from the team.
3312 	The team lock must be held, unless the function is called for the team's
3313 	main thread. Interrupts must be enabled.
3314 */
3315 struct user_thread*
3316 team_allocate_user_thread(Team* team)
3317 {
3318 	if (team->user_data == 0)
3319 		return NULL;
3320 
3321 	// take an entry from the free list, if any
3322 	if (struct free_user_thread* entry = team->free_user_threads) {
3323 		user_thread* thread = entry->thread;
3324 		team->free_user_threads = entry->next;
3325 		free(entry);
3326 		return thread;
3327 	}
3328 
3329 	while (true) {
3330 		// enough space left?
3331 		size_t needed = ROUNDUP(sizeof(user_thread), 8);
3332 		if (team->user_data_size - team->used_user_data < needed) {
3333 			// try to resize the area
3334 			if (resize_area(team->user_data_area,
3335 					team->user_data_size + B_PAGE_SIZE) != B_OK) {
3336 				return NULL;
3337 			}
3338 
3339 			// resized user area successfully -- try to allocate the user_thread
3340 			// again
3341 			team->user_data_size += B_PAGE_SIZE;
3342 			continue;
3343 		}
3344 
3345 		// allocate the user_thread
3346 		user_thread* thread
3347 			= (user_thread*)(team->user_data + team->used_user_data);
3348 		team->used_user_data += needed;
3349 
3350 		return thread;
3351 	}
3352 }
3353 
3354 
3355 /*!	Frees the given user_thread structure.
3356 	The team's lock must not be held. Interrupts must be enabled.
3357 	\param team The team the user thread was allocated from.
3358 	\param userThread The user thread to free.
3359 */
3360 void
3361 team_free_user_thread(Team* team, struct user_thread* userThread)
3362 {
3363 	if (userThread == NULL)
3364 		return;
3365 
3366 	// create a free list entry
3367 	free_user_thread* entry
3368 		= (free_user_thread*)malloc(sizeof(free_user_thread));
3369 	if (entry == NULL) {
3370 		// we have to leak the user thread :-/
3371 		return;
3372 	}
3373 
3374 	// add to free list
3375 	TeamLocker teamLocker(team);
3376 
3377 	entry->thread = userThread;
3378 	entry->next = team->free_user_threads;
3379 	team->free_user_threads = entry;
3380 }
3381 
3382 
3383 //	#pragma mark - Associated data interface
3384 
3385 
3386 AssociatedData::AssociatedData()
3387 	:
3388 	fOwner(NULL)
3389 {
3390 }
3391 
3392 
3393 AssociatedData::~AssociatedData()
3394 {
3395 }
3396 
3397 
3398 void
3399 AssociatedData::OwnerDeleted(AssociatedDataOwner* owner)
3400 {
3401 }
3402 
3403 
3404 AssociatedDataOwner::AssociatedDataOwner()
3405 {
3406 	mutex_init(&fLock, "associated data owner");
3407 }
3408 
3409 
3410 AssociatedDataOwner::~AssociatedDataOwner()
3411 {
3412 	mutex_destroy(&fLock);
3413 }
3414 
3415 
3416 bool
3417 AssociatedDataOwner::AddData(AssociatedData* data)
3418 {
3419 	MutexLocker locker(fLock);
3420 
3421 	if (data->Owner() != NULL)
3422 		return false;
3423 
3424 	data->AcquireReference();
3425 	fList.Add(data);
3426 	data->SetOwner(this);
3427 
3428 	return true;
3429 }
3430 
3431 
3432 bool
3433 AssociatedDataOwner::RemoveData(AssociatedData* data)
3434 {
3435 	MutexLocker locker(fLock);
3436 
3437 	if (data->Owner() != this)
3438 		return false;
3439 
3440 	data->SetOwner(NULL);
3441 	fList.Remove(data);
3442 
3443 	locker.Unlock();
3444 
3445 	data->ReleaseReference();
3446 
3447 	return true;
3448 }
3449 
3450 
3451 void
3452 AssociatedDataOwner::PrepareForDeletion()
3453 {
3454 	MutexLocker locker(fLock);
3455 
3456 	// move all data to a temporary list and unset the owner
3457 	DataList list;
3458 	list.MoveFrom(&fList);
3459 
3460 	for (DataList::Iterator it = list.GetIterator();
3461 		AssociatedData* data = it.Next();) {
3462 		data->SetOwner(NULL);
3463 	}
3464 
3465 	locker.Unlock();
3466 
3467 	// call the notification hooks and release our references
3468 	while (AssociatedData* data = list.RemoveHead()) {
3469 		data->OwnerDeleted(this);
3470 		data->ReleaseReference();
3471 	}
3472 }
3473 
3474 
3475 /*!	Associates data with the current team.
3476 	When the team is deleted, the data object is notified.
3477 	The team acquires a reference to the object.
3478 
3479 	\param data The data object.
3480 	\return \c true on success, \c false otherwise. Fails only when the supplied
3481 		data object is already associated with another owner.
3482 */
3483 bool
3484 team_associate_data(AssociatedData* data)
3485 {
3486 	return thread_get_current_thread()->team->AddData(data);
3487 }
3488 
3489 
3490 /*!	Dissociates data from the current team.
3491 	Balances an earlier call to team_associate_data().
3492 
3493 	\param data The data object.
3494 	\return \c true on success, \c false otherwise. Fails only when the data
3495 		object is not associated with the current team.
3496 */
3497 bool
3498 team_dissociate_data(AssociatedData* data)
3499 {
3500 	return thread_get_current_thread()->team->RemoveData(data);
3501 }
3502 
3503 
3504 //	#pragma mark - Public kernel API
3505 
3506 
3507 thread_id
3508 load_image(int32 argCount, const char** args, const char** env)
3509 {
3510 	return load_image_etc(argCount, args, env, B_NORMAL_PRIORITY,
3511 		B_CURRENT_TEAM, B_WAIT_TILL_LOADED);
3512 }
3513 
3514 
3515 thread_id
3516 load_image_etc(int32 argCount, const char* const* args,
3517 	const char* const* env, int32 priority, team_id parentID, uint32 flags)
3518 {
3519 	// we need to flatten the args and environment
3520 
3521 	if (args == NULL)
3522 		return B_BAD_VALUE;
3523 
3524 	// determine total needed size
3525 	int32 argSize = 0;
3526 	for (int32 i = 0; i < argCount; i++)
3527 		argSize += strlen(args[i]) + 1;
3528 
3529 	int32 envCount = 0;
3530 	int32 envSize = 0;
3531 	while (env != NULL && env[envCount] != NULL)
3532 		envSize += strlen(env[envCount++]) + 1;
3533 
3534 	int32 size = (argCount + envCount + 2) * sizeof(char*) + argSize + envSize;
3535 	if (size > MAX_PROCESS_ARGS_SIZE)
3536 		return B_TOO_MANY_ARGS;
3537 
3538 	// allocate space
3539 	char** flatArgs = (char**)malloc(size);
3540 	if (flatArgs == NULL)
3541 		return B_NO_MEMORY;
3542 
3543 	char** slot = flatArgs;
3544 	char* stringSpace = (char*)(flatArgs + argCount + envCount + 2);
3545 
3546 	// copy arguments and environment
3547 	for (int32 i = 0; i < argCount; i++) {
3548 		int32 argSize = strlen(args[i]) + 1;
3549 		memcpy(stringSpace, args[i], argSize);
3550 		*slot++ = stringSpace;
3551 		stringSpace += argSize;
3552 	}
3553 
3554 	*slot++ = NULL;
3555 
3556 	for (int32 i = 0; i < envCount; i++) {
3557 		int32 envSize = strlen(env[i]) + 1;
3558 		memcpy(stringSpace, env[i], envSize);
3559 		*slot++ = stringSpace;
3560 		stringSpace += envSize;
3561 	}
3562 
3563 	*slot++ = NULL;
3564 
3565 	thread_id thread = load_image_internal(flatArgs, size, argCount, envCount,
3566 		B_NORMAL_PRIORITY, parentID, B_WAIT_TILL_LOADED, -1, 0);
3567 
3568 	free(flatArgs);
3569 		// load_image_internal() unset our variable if it took over ownership
3570 
3571 	return thread;
3572 }
3573 
3574 
3575 status_t
3576 wait_for_team(team_id id, status_t* _returnCode)
3577 {
3578 	// check whether the team exists
3579 	InterruptsSpinLocker teamsLocker(sTeamHashLock);
3580 
3581 	Team* team = team_get_team_struct_locked(id);
3582 	if (team == NULL)
3583 		return B_BAD_TEAM_ID;
3584 
3585 	id = team->id;
3586 
3587 	teamsLocker.Unlock();
3588 
3589 	// wait for the main thread (it has the same ID as the team)
3590 	return wait_for_thread(id, _returnCode);
3591 }
3592 
3593 
3594 status_t
3595 kill_team(team_id id)
3596 {
3597 	InterruptsSpinLocker teamsLocker(sTeamHashLock);
3598 
3599 	Team* team = team_get_team_struct_locked(id);
3600 	if (team == NULL)
3601 		return B_BAD_TEAM_ID;
3602 
3603 	id = team->id;
3604 
3605 	teamsLocker.Unlock();
3606 
3607 	if (team == sKernelTeam)
3608 		return B_NOT_ALLOWED;
3609 
3610 	// Just kill the team's main thread (it has same ID as the team). The
3611 	// cleanup code there will take care of the team.
3612 	return kill_thread(id);
3613 }
3614 
3615 
3616 status_t
3617 _get_team_info(team_id id, team_info* info, size_t size)
3618 {
3619 	// get the team
3620 	Team* team = Team::Get(id);
3621 	if (team == NULL)
3622 		return B_BAD_TEAM_ID;
3623 	BReference<Team> teamReference(team, true);
3624 
3625 	// fill in the info
3626 	return fill_team_info(team, info, size);
3627 }
3628 
3629 
3630 status_t
3631 _get_next_team_info(int32* cookie, team_info* info, size_t size)
3632 {
3633 	int32 slot = *cookie;
3634 	if (slot < 1)
3635 		slot = 1;
3636 
3637 	InterruptsSpinLocker locker(sTeamHashLock);
3638 
3639 	team_id lastTeamID = peek_next_thread_id();
3640 		// TODO: This is broken, since the id can wrap around!
3641 
3642 	// get next valid team
3643 	Team* team = NULL;
3644 	while (slot < lastTeamID && !(team = team_get_team_struct_locked(slot)))
3645 		slot++;
3646 
3647 	if (team == NULL)
3648 		return B_BAD_TEAM_ID;
3649 
3650 	// get a reference to the team and unlock
3651 	BReference<Team> teamReference(team);
3652 	locker.Unlock();
3653 
3654 	// fill in the info
3655 	*cookie = ++slot;
3656 	return fill_team_info(team, info, size);
3657 }
3658 
3659 
3660 status_t
3661 _get_team_usage_info(team_id id, int32 who, team_usage_info* info, size_t size)
3662 {
3663 	if (size != sizeof(team_usage_info))
3664 		return B_BAD_VALUE;
3665 
3666 	return common_get_team_usage_info(id, who, info, 0);
3667 }
3668 
3669 
3670 pid_t
3671 getpid(void)
3672 {
3673 	return thread_get_current_thread()->team->id;
3674 }
3675 
3676 
3677 pid_t
3678 getppid(void)
3679 {
3680 	Team* team = thread_get_current_thread()->team;
3681 
3682 	TeamLocker teamLocker(team);
3683 
3684 	return team->parent->id;
3685 }
3686 
3687 
3688 pid_t
3689 getpgid(pid_t id)
3690 {
3691 	if (id < 0) {
3692 		errno = EINVAL;
3693 		return -1;
3694 	}
3695 
3696 	if (id == 0) {
3697 		// get process group of the calling process
3698 		Team* team = thread_get_current_thread()->team;
3699 		TeamLocker teamLocker(team);
3700 		return team->group_id;
3701 	}
3702 
3703 	// get the team
3704 	Team* team = Team::GetAndLock(id);
3705 	if (team == NULL) {
3706 		errno = ESRCH;
3707 		return -1;
3708 	}
3709 
3710 	// get the team's process group ID
3711 	pid_t groupID = team->group_id;
3712 
3713 	team->UnlockAndReleaseReference();
3714 
3715 	return groupID;
3716 }
3717 
3718 
3719 pid_t
3720 getsid(pid_t id)
3721 {
3722 	if (id < 0) {
3723 		errno = EINVAL;
3724 		return -1;
3725 	}
3726 
3727 	if (id == 0) {
3728 		// get session of the calling process
3729 		Team* team = thread_get_current_thread()->team;
3730 		TeamLocker teamLocker(team);
3731 		return team->session_id;
3732 	}
3733 
3734 	// get the team
3735 	Team* team = Team::GetAndLock(id);
3736 	if (team == NULL) {
3737 		errno = ESRCH;
3738 		return -1;
3739 	}
3740 
3741 	// get the team's session ID
3742 	pid_t sessionID = team->session_id;
3743 
3744 	team->UnlockAndReleaseReference();
3745 
3746 	return sessionID;
3747 }
3748 
3749 
3750 //	#pragma mark - User syscalls
3751 
3752 
3753 status_t
3754 _user_exec(const char* userPath, const char* const* userFlatArgs,
3755 	size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask)
3756 {
3757 	// NOTE: Since this function normally doesn't return, don't use automatic
3758 	// variables that need destruction in the function scope.
3759 	char path[B_PATH_NAME_LENGTH];
3760 
3761 	if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userFlatArgs)
3762 		|| user_strlcpy(path, userPath, sizeof(path)) < B_OK)
3763 		return B_BAD_ADDRESS;
3764 
3765 	// copy and relocate the flat arguments
3766 	char** flatArgs;
3767 	status_t error = copy_user_process_args(userFlatArgs, flatArgsSize,
3768 		argCount, envCount, flatArgs);
3769 
3770 	if (error == B_OK) {
3771 		error = exec_team(path, flatArgs, _ALIGN(flatArgsSize), argCount,
3772 			envCount, umask);
3773 			// this one only returns in case of error
3774 	}
3775 
3776 	free(flatArgs);
3777 	return error;
3778 }
3779 
3780 
3781 thread_id
3782 _user_fork(void)
3783 {
3784 	return fork_team();
3785 }
3786 
3787 
3788 pid_t
3789 _user_wait_for_child(thread_id child, uint32 flags, siginfo_t* userInfo)
3790 {
3791 	if (userInfo != NULL && !IS_USER_ADDRESS(userInfo))
3792 		return B_BAD_ADDRESS;
3793 
3794 	siginfo_t info;
3795 	pid_t foundChild = wait_for_child(child, flags, info);
3796 	if (foundChild < 0)
3797 		return syscall_restart_handle_post(foundChild);
3798 
3799 	// copy info back to userland
3800 	if (userInfo != NULL && user_memcpy(userInfo, &info, sizeof(info)) != B_OK)
3801 		return B_BAD_ADDRESS;
3802 
3803 	return foundChild;
3804 }
3805 
3806 
3807 pid_t
3808 _user_process_info(pid_t process, int32 which)
3809 {
3810 	// we only allow to return the parent of the current process
3811 	if (which == PARENT_ID
3812 		&& process != 0 && process != thread_get_current_thread()->team->id)
3813 		return B_BAD_VALUE;
3814 
3815 	pid_t result;
3816 	switch (which) {
3817 		case SESSION_ID:
3818 			result = getsid(process);
3819 			break;
3820 		case GROUP_ID:
3821 			result = getpgid(process);
3822 			break;
3823 		case PARENT_ID:
3824 			result = getppid();
3825 			break;
3826 		default:
3827 			return B_BAD_VALUE;
3828 	}
3829 
3830 	return result >= 0 ? result : errno;
3831 }
3832 
3833 
3834 pid_t
3835 _user_setpgid(pid_t processID, pid_t groupID)
3836 {
3837 	// setpgid() can be called either by the parent of the target process or
3838 	// by the process itself to do one of two things:
3839 	// * Create a new process group with the target process' ID and the target
3840 	//   process as group leader.
3841 	// * Set the target process' process group to an already existing one in the
3842 	//   same session.
3843 
3844 	if (groupID < 0)
3845 		return B_BAD_VALUE;
3846 
3847 	Team* currentTeam = thread_get_current_thread()->team;
3848 	if (processID == 0)
3849 		processID = currentTeam->id;
3850 
3851 	// if the group ID is not specified, use the target process' ID
3852 	if (groupID == 0)
3853 		groupID = processID;
3854 
3855 	// We loop when running into the following race condition: We create a new
3856 	// process group, because there isn't one with that ID yet, but later when
3857 	// trying to publish it, we find that someone else created and published
3858 	// a group with that ID in the meantime. In that case we just restart the
3859 	// whole action.
3860 	while (true) {
3861 		// Look up the process group by ID. If it doesn't exist yet and we are
3862 		// allowed to create a new one, do that.
3863 		ProcessGroup* group = ProcessGroup::Get(groupID);
3864 		bool newGroup = false;
3865 		if (group == NULL) {
3866 			if (groupID != processID)
3867 				return B_NOT_ALLOWED;
3868 
3869 			group = new(std::nothrow) ProcessGroup(groupID);
3870 			if (group == NULL)
3871 				return B_NO_MEMORY;
3872 
3873 			newGroup = true;
3874 		}
3875 		BReference<ProcessGroup> groupReference(group, true);
3876 
3877 		// get the target team
3878 		Team* team = Team::Get(processID);
3879 		if (team == NULL)
3880 			return ESRCH;
3881 		BReference<Team> teamReference(team, true);
3882 
3883 		// lock the new process group and the team's current process group
3884 		while (true) {
3885 			// lock the team's current process group
3886 			team->LockProcessGroup();
3887 
3888 			ProcessGroup* oldGroup = team->group;
3889 			if (oldGroup == group) {
3890 				// it's the same as the target group, so just bail out
3891 				oldGroup->Unlock();
3892 				return group->id;
3893 			}
3894 
3895 			oldGroup->AcquireReference();
3896 
3897 			// lock the target process group, if locking order allows it
3898 			if (newGroup || group->id > oldGroup->id) {
3899 				group->Lock();
3900 				break;
3901 			}
3902 
3903 			// try to lock
3904 			if (group->TryLock())
3905 				break;
3906 
3907 			// no dice -- unlock the team's current process group and relock in
3908 			// the correct order
3909 			oldGroup->Unlock();
3910 
3911 			group->Lock();
3912 			oldGroup->Lock();
3913 
3914 			// check whether things are still the same
3915 			TeamLocker teamLocker(team);
3916 			if (team->group == oldGroup)
3917 				break;
3918 
3919 			// something changed -- unlock everything and retry
3920 			teamLocker.Unlock();
3921 			oldGroup->Unlock();
3922 			group->Unlock();
3923 			oldGroup->ReleaseReference();
3924 		}
3925 
3926 		// we now have references and locks of both new and old process group
3927 		BReference<ProcessGroup> oldGroupReference(team->group, true);
3928 		AutoLocker<ProcessGroup> oldGroupLocker(team->group, true);
3929 		AutoLocker<ProcessGroup> groupLocker(group, true);
3930 
3931 		// also lock the target team and its parent
3932 		team->LockTeamAndParent(false);
3933 		TeamLocker parentLocker(team->parent, true);
3934 		TeamLocker teamLocker(team, true);
3935 
3936 		// perform the checks
3937 		if (team == currentTeam) {
3938 			// we set our own group
3939 
3940 			// we must not change our process group ID if we're a session leader
3941 			if (is_session_leader(currentTeam))
3942 				return B_NOT_ALLOWED;
3943 		} else {
3944 			// Calling team != target team. The target team must be a child of
3945 			// the calling team and in the same session. (If that's the case it
3946 			// isn't a session leader either.)
3947 			if (team->parent != currentTeam
3948 				|| team->session_id != currentTeam->session_id) {
3949 				return B_NOT_ALLOWED;
3950 			}
3951 
3952 			// The call is also supposed to fail on a child, when the child has
3953 			// already executed exec*() [EACCES].
3954 			if ((team->flags & TEAM_FLAG_EXEC_DONE) != 0)
3955 				return EACCES;
3956 		}
3957 
3958 		// If we created a new process group, publish it now.
3959 		if (newGroup) {
3960 			InterruptsSpinLocker groupHashLocker(sGroupHashLock);
3961 			if (sGroupHash.Lookup(groupID)) {
3962 				// A group with the group ID appeared since we first checked.
3963 				// Back to square one.
3964 				continue;
3965 			}
3966 
3967 			group->PublishLocked(team->group->Session());
3968 		} else if (group->Session()->id != team->session_id) {
3969 			// The existing target process group belongs to a different session.
3970 			// That's not allowed.
3971 			return B_NOT_ALLOWED;
3972 		}
3973 
3974 		// Everything is ready -- set the group.
3975 		remove_team_from_group(team);
3976 		insert_team_into_group(group, team);
3977 
3978 		// Changing the process group might have changed the situation for a
3979 		// parent waiting in wait_for_child(). Hence we notify it.
3980 		team->parent->dead_children.condition_variable.NotifyAll(false);
3981 
3982 		return group->id;
3983 	}
3984 }
3985 
3986 
3987 pid_t
3988 _user_setsid(void)
3989 {
3990 	Team* team = thread_get_current_thread()->team;
3991 
3992 	// create a new process group and session
3993 	ProcessGroup* group = new(std::nothrow) ProcessGroup(team->id);
3994 	if (group == NULL)
3995 		return B_NO_MEMORY;
3996 	BReference<ProcessGroup> groupReference(group, true);
3997 	AutoLocker<ProcessGroup> groupLocker(group);
3998 
3999 	ProcessSession* session = new(std::nothrow) ProcessSession(group->id);
4000 	if (session == NULL)
4001 		return B_NO_MEMORY;
4002 	BReference<ProcessSession> sessionReference(session, true);
4003 
4004 	// lock the team's current process group, parent, and the team itself
4005 	team->LockTeamParentAndProcessGroup();
4006 	AutoLocker<ProcessGroup> oldGroupLocker(team->group, true);
4007 	TeamLocker parentLocker(team->parent, true);
4008 	TeamLocker teamLocker(team, true);
4009 
4010 	// the team must not already be a process group leader
4011 	if (is_process_group_leader(team))
4012 		return B_NOT_ALLOWED;
4013 
4014 	// remove the team from the old and add it to the new process group
4015 	remove_team_from_group(team);
4016 	group->Publish(session);
4017 	insert_team_into_group(group, team);
4018 
4019 	// Changing the process group might have changed the situation for a
4020 	// parent waiting in wait_for_child(). Hence we notify it.
4021 	team->parent->dead_children.condition_variable.NotifyAll(false);
4022 
4023 	return group->id;
4024 }
4025 
4026 
4027 status_t
4028 _user_wait_for_team(team_id id, status_t* _userReturnCode)
4029 {
4030 	status_t returnCode;
4031 	status_t status;
4032 
4033 	if (_userReturnCode != NULL && !IS_USER_ADDRESS(_userReturnCode))
4034 		return B_BAD_ADDRESS;
4035 
4036 	status = wait_for_team(id, &returnCode);
4037 	if (status >= B_OK && _userReturnCode != NULL) {
4038 		if (user_memcpy(_userReturnCode, &returnCode, sizeof(returnCode))
4039 				!= B_OK)
4040 			return B_BAD_ADDRESS;
4041 		return B_OK;
4042 	}
4043 
4044 	return syscall_restart_handle_post(status);
4045 }
4046 
4047 
4048 thread_id
4049 _user_load_image(const char* const* userFlatArgs, size_t flatArgsSize,
4050 	int32 argCount, int32 envCount, int32 priority, uint32 flags,
4051 	port_id errorPort, uint32 errorToken)
4052 {
4053 	TRACE(("_user_load_image: argc = %ld\n", argCount));
4054 
4055 	if (argCount < 1)
4056 		return B_BAD_VALUE;
4057 
4058 	// copy and relocate the flat arguments
4059 	char** flatArgs;
4060 	status_t error = copy_user_process_args(userFlatArgs, flatArgsSize,
4061 		argCount, envCount, flatArgs);
4062 	if (error != B_OK)
4063 		return error;
4064 
4065 	thread_id thread = load_image_internal(flatArgs, _ALIGN(flatArgsSize),
4066 		argCount, envCount, priority, B_CURRENT_TEAM, flags, errorPort,
4067 		errorToken);
4068 
4069 	free(flatArgs);
4070 		// load_image_internal() unset our variable if it took over ownership
4071 
4072 	return thread;
4073 }
4074 
4075 
4076 void
4077 _user_exit_team(status_t returnValue)
4078 {
4079 	Thread* thread = thread_get_current_thread();
4080 	Team* team = thread->team;
4081 
4082 	// set this thread's exit status
4083 	thread->exit.status = returnValue;
4084 
4085 	// set the team exit status
4086 	TeamLocker teamLocker(team);
4087 
4088 	if (!team->exit.initialized) {
4089 		team->exit.reason = CLD_EXITED;
4090 		team->exit.signal = 0;
4091 		team->exit.signaling_user = 0;
4092 		team->exit.status = returnValue;
4093 		team->exit.initialized = true;
4094 	}
4095 
4096 	teamLocker.Unlock();
4097 
4098 	// Stop the thread, if the team is being debugged and that has been
4099 	// requested.
4100 	if ((atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_PREVENT_EXIT) != 0)
4101 		user_debug_stop_thread();
4102 
4103 	// Send this thread a SIGKILL. This makes sure the thread will not return to
4104 	// userland. The signal handling code forwards the signal to the main
4105 	// thread (if that's not already this one), which will take the team down.
4106 	Signal signal(SIGKILL, SI_USER, B_OK, team->id);
4107 	send_signal_to_thread(thread, signal, 0);
4108 }
4109 
4110 
4111 status_t
4112 _user_kill_team(team_id team)
4113 {
4114 	return kill_team(team);
4115 }
4116 
4117 
4118 status_t
4119 _user_get_team_info(team_id id, team_info* userInfo)
4120 {
4121 	status_t status;
4122 	team_info info;
4123 
4124 	if (!IS_USER_ADDRESS(userInfo))
4125 		return B_BAD_ADDRESS;
4126 
4127 	status = _get_team_info(id, &info, sizeof(team_info));
4128 	if (status == B_OK) {
4129 		if (user_memcpy(userInfo, &info, sizeof(team_info)) < B_OK)
4130 			return B_BAD_ADDRESS;
4131 	}
4132 
4133 	return status;
4134 }
4135 
4136 
4137 status_t
4138 _user_get_next_team_info(int32* userCookie, team_info* userInfo)
4139 {
4140 	status_t status;
4141 	team_info info;
4142 	int32 cookie;
4143 
4144 	if (!IS_USER_ADDRESS(userCookie)
4145 		|| !IS_USER_ADDRESS(userInfo)
4146 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
4147 		return B_BAD_ADDRESS;
4148 
4149 	status = _get_next_team_info(&cookie, &info, sizeof(team_info));
4150 	if (status != B_OK)
4151 		return status;
4152 
4153 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
4154 		|| user_memcpy(userInfo, &info, sizeof(team_info)) < B_OK)
4155 		return B_BAD_ADDRESS;
4156 
4157 	return status;
4158 }
4159 
4160 
4161 team_id
4162 _user_get_current_team(void)
4163 {
4164 	return team_get_current_team_id();
4165 }
4166 
4167 
4168 status_t
4169 _user_get_team_usage_info(team_id team, int32 who, team_usage_info* userInfo,
4170 	size_t size)
4171 {
4172 	if (size != sizeof(team_usage_info))
4173 		return B_BAD_VALUE;
4174 
4175 	team_usage_info info;
4176 	status_t status = common_get_team_usage_info(team, who, &info,
4177 		B_CHECK_PERMISSION);
4178 
4179 	if (userInfo == NULL || !IS_USER_ADDRESS(userInfo)
4180 		|| user_memcpy(userInfo, &info, size) != B_OK) {
4181 		return B_BAD_ADDRESS;
4182 	}
4183 
4184 	return status;
4185 }
4186 
4187 
4188 status_t
4189 _user_get_extended_team_info(team_id teamID, uint32 flags, void* buffer,
4190 	size_t size, size_t* _sizeNeeded)
4191 {
4192 	// check parameters
4193 	if ((buffer != NULL && !IS_USER_ADDRESS(buffer))
4194 		|| (buffer == NULL && size > 0)
4195 		|| _sizeNeeded == NULL || !IS_USER_ADDRESS(_sizeNeeded)) {
4196 		return B_BAD_ADDRESS;
4197 	}
4198 
4199 	KMessage info;
4200 
4201 	if ((flags & B_TEAM_INFO_BASIC) != 0) {
4202 		// allocate memory for a copy of the needed team data
4203 		struct ExtendedTeamData {
4204 			team_id	id;
4205 			pid_t	group_id;
4206 			pid_t	session_id;
4207 			uid_t	real_uid;
4208 			gid_t	real_gid;
4209 			uid_t	effective_uid;
4210 			gid_t	effective_gid;
4211 			char	name[B_OS_NAME_LENGTH];
4212 		};
4213 
4214 		ExtendedTeamData* teamClone
4215 			= (ExtendedTeamData*)malloc(sizeof(ExtendedTeamData));
4216 			// It would be nicer to use new, but then we'd have to use
4217 			// ObjectDeleter and declare the structure outside of the function
4218 			// due to template parameter restrictions.
4219 		if (teamClone == NULL)
4220 			return B_NO_MEMORY;
4221 		MemoryDeleter teamCloneDeleter(teamClone);
4222 
4223 		io_context* ioContext;
4224 		{
4225 			// get the team structure
4226 			Team* team = Team::GetAndLock(teamID);
4227 			if (team == NULL)
4228 				return B_BAD_TEAM_ID;
4229 			BReference<Team> teamReference(team, true);
4230 			TeamLocker teamLocker(team, true);
4231 
4232 			// copy the data
4233 			teamClone->id = team->id;
4234 			strlcpy(teamClone->name, team->Name(), sizeof(teamClone->name));
4235 			teamClone->group_id = team->group_id;
4236 			teamClone->session_id = team->session_id;
4237 			teamClone->real_uid = team->real_uid;
4238 			teamClone->real_gid = team->real_gid;
4239 			teamClone->effective_uid = team->effective_uid;
4240 			teamClone->effective_gid = team->effective_gid;
4241 
4242 			// also fetch a reference to the I/O context
4243 			ioContext = team->io_context;
4244 			vfs_get_io_context(ioContext);
4245 		}
4246 		CObjectDeleter<io_context> ioContextPutter(ioContext,
4247 			&vfs_put_io_context);
4248 
4249 		// add the basic data to the info message
4250 		if (info.AddInt32("id", teamClone->id) != B_OK
4251 			|| info.AddString("name", teamClone->name) != B_OK
4252 			|| info.AddInt32("process group", teamClone->group_id) != B_OK
4253 			|| info.AddInt32("session", teamClone->session_id) != B_OK
4254 			|| info.AddInt32("uid", teamClone->real_uid) != B_OK
4255 			|| info.AddInt32("gid", teamClone->real_gid) != B_OK
4256 			|| info.AddInt32("euid", teamClone->effective_uid) != B_OK
4257 			|| info.AddInt32("egid", teamClone->effective_gid) != B_OK) {
4258 			return B_NO_MEMORY;
4259 		}
4260 
4261 		// get the current working directory from the I/O context
4262 		dev_t cwdDevice;
4263 		ino_t cwdDirectory;
4264 		{
4265 			MutexLocker ioContextLocker(ioContext->io_mutex);
4266 			vfs_vnode_to_node_ref(ioContext->cwd, &cwdDevice, &cwdDirectory);
4267 		}
4268 
4269 		if (info.AddInt32("cwd device", cwdDevice) != B_OK
4270 			|| info.AddInt64("cwd directory", cwdDirectory) != B_OK) {
4271 			return B_NO_MEMORY;
4272 		}
4273 	}
4274 
4275 	// TODO: Support the other flags!
4276 
4277 	// copy the needed size and, if it fits, the message back to userland
4278 	size_t sizeNeeded = info.ContentSize();
4279 	if (user_memcpy(_sizeNeeded, &sizeNeeded, sizeof(sizeNeeded)) != B_OK)
4280 		return B_BAD_ADDRESS;
4281 
4282 	if (sizeNeeded > size)
4283 		return B_BUFFER_OVERFLOW;
4284 
4285 	if (user_memcpy(buffer, info.Buffer(), sizeNeeded) != B_OK)
4286 		return B_BAD_ADDRESS;
4287 
4288 	return B_OK;
4289 }
4290