vfs: check userland buffers before reading them.
[haiku.git] / src / system / libroot / posix / unistd / fork.c
bloba149fba6c92e5358a0198705e61e0a124e85fa45
1 /*
2 * Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <fork.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <errno.h>
13 #include <errno_private.h>
14 #include <locks.h>
15 #include <libroot_private.h>
16 #include <pthread_private.h>
17 #include <runtime_loader.h>
18 #include <syscalls.h>
19 #include <user_thread.h>
22 typedef struct fork_hook {
23 struct fork_hook *next;
24 void (*function)(void);
25 } fork_hook;
27 #define FORK_LOCK_NAME "fork lock"
29 static fork_hook *sPrepareHooks, *sParentHooks, *sChildHooks;
30 static fork_hook *sLastParentHook, *sLastChildHook;
31 static mutex sForkLock = MUTEX_INITIALIZER(FORK_LOCK_NAME);
33 extern thread_id __main_thread_id;
36 /** Adds a hook to the specified list.
37 * If \a _lastHook is NULL, the hook will be added at the head of the list,
38 * else it will be added at the tail of the list.
39 * Since this function allocates memory, it can fail, and returns B_NO_MEMORY
40 * in that case. It returns B_OK on success.
43 static status_t
44 add_fork_hook(fork_hook **_hooks, fork_hook **_lastHook, void (*function)(void))
46 fork_hook *hook = (fork_hook *)malloc(sizeof(struct fork_hook));
47 if (hook == NULL)
48 return B_NO_MEMORY;
50 hook->function = function;
52 if (_lastHook) {
53 // add hook at the end of the list
55 if (*_hooks == NULL) {
56 // first entry of this list
57 *_hooks = hook;
58 *_lastHook = hook;
59 } else {
60 // any other item
61 #if 0
62 if (*_lastHook == NULL) {
63 // search for last hook (need if an item was added to the beginning only --
64 // this can only be the case if this function is called directly, though)
65 fork_hook *last = *_hooks;
66 while (last->next)
67 last = last->next;
69 *_lastHook = last;
71 #endif
73 (*_lastHook)->next = hook;
74 *_lastHook = hook;
77 hook->next = NULL;
78 } else {
79 // add hook at the beginning of the list
80 hook->next = *_hooks;
81 *_hooks = hook;
84 return B_OK;
88 /** Calls all hooks in the specified list in ascending order.
91 static void
92 call_fork_hooks(fork_hook *hook)
94 while (hook) {
95 hook->function();
96 hook = hook->next;
101 /** Private support function that registers the hooks that will be executed
102 * before and after the team is fork()ed.
103 * It is called from pthread_atfork() and atfork().
106 status_t
107 __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
109 status_t status;
111 defer_signals();
113 status = mutex_lock(&sForkLock);
114 if (status != B_OK) {
115 undefer_signals();
116 return status;
119 if (prepare)
120 status = add_fork_hook(&sPrepareHooks, NULL, prepare);
122 if (status == B_OK && parent)
123 status = add_fork_hook(&sParentHooks, &sLastParentHook, parent);
125 if (status == B_OK && child)
126 status = add_fork_hook(&sChildHooks, &sLastChildHook, child);
128 mutex_unlock(&sForkLock);
130 undefer_signals();
132 return status;
136 pid_t
137 fork(void)
139 thread_id thread;
140 status_t status;
142 defer_signals();
144 status = mutex_lock(&sForkLock);
145 if (status != B_OK) {
146 undefer_signals();
147 return status;
150 // call preparation hooks
151 call_fork_hooks(sPrepareHooks);
152 __heap_before_fork();
154 thread = _kern_fork();
155 if (thread == 0) {
156 // we are the child
157 // ToDo: initialize child
158 __main_thread_id = find_thread(NULL);
159 pthread_self()->id = __main_thread_id;
161 mutex_init(&sForkLock, FORK_LOCK_NAME);
162 // TODO: The lock is already initialized and we in the fork()ing
163 // process we should make sure that it is in a consistent state when
164 // calling the kernel.
165 __gRuntimeLoader->reinit_after_fork();
166 __heap_after_fork_child();
167 __reinit_pwd_backend_after_fork();
169 call_fork_hooks(sChildHooks);
170 } else {
171 // we are the parent
172 __heap_after_fork_parent();
173 call_fork_hooks(sParentHooks);
174 mutex_unlock(&sForkLock);
177 undefer_signals();
179 if (thread < 0) {
180 // something went wrong
181 __set_errno(thread);
182 thread = -1;
185 return thread;
189 pid_t
190 vfork(void)
192 return fork();