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