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 */ 5 6 7 #include <fork.h> 8 9 #include <unistd.h> 10 #include <stdlib.h> 11 #include <errno.h> 12 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 20 21 typedef struct fork_hook { 22 struct fork_hook *next; 23 void (*function)(void); 24 } fork_hook; 25 26 #define FORK_LOCK_NAME "fork lock" 27 28 static fork_hook *sPrepareHooks, *sParentHooks, *sChildHooks; 29 static fork_hook *sLastParentHook, *sLastChildHook; 30 static mutex sForkLock = MUTEX_INITIALIZER(FORK_LOCK_NAME); 31 32 extern thread_id __main_thread_id; 33 34 35 /** Adds a hook to the specified list. 36 * If \a _lastHook is NULL, the hook will be added at the head of the list, 37 * else it will be added at the tail of the list. 38 * Since this function allocates memory, it can fail, and returns B_NO_MEMORY 39 * in that case. It returns B_OK on success. 40 */ 41 42 static status_t 43 add_fork_hook(fork_hook **_hooks, fork_hook **_lastHook, void (*function)(void)) 44 { 45 fork_hook *hook = (fork_hook *)malloc(sizeof(struct fork_hook)); 46 if (hook == NULL) 47 return B_NO_MEMORY; 48 49 hook->function = function; 50 51 if (_lastHook) { 52 // add hook at the end of the list 53 54 if (*_hooks == NULL) { 55 // first entry of this list 56 *_hooks = hook; 57 *_lastHook = hook; 58 } else { 59 // any other item 60 #if 0 61 if (*_lastHook == NULL) { 62 // search for last hook (need if an item was added to the beginning only -- 63 // this can only be the case if this function is called directly, though) 64 fork_hook *last = *_hooks; 65 while (last->next) 66 last = last->next; 67 68 *_lastHook = last; 69 } 70 #endif 71 72 (*_lastHook)->next = hook; 73 *_lastHook = hook; 74 } 75 76 hook->next = NULL; 77 } else { 78 // add hook at the beginning of the list 79 hook->next = *_hooks; 80 *_hooks = hook; 81 } 82 83 return B_OK; 84 } 85 86 87 /** Calls all hooks in the specified list in ascending order. 88 */ 89 90 static void 91 call_fork_hooks(fork_hook *hook) 92 { 93 while (hook) { 94 hook->function(); 95 hook = hook->next; 96 } 97 } 98 99 100 /** Private support function that registers the hooks that will be executed 101 * before and after the team is fork()ed. 102 * It is called from pthread_atfork() and atfork(). 103 */ 104 105 status_t 106 __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) 107 { 108 status_t status = mutex_lock(&sForkLock); 109 if (status != B_OK) 110 return status; 111 112 if (prepare) 113 status = add_fork_hook(&sPrepareHooks, NULL, prepare); 114 115 if (status == B_OK && parent) 116 status = add_fork_hook(&sParentHooks, &sLastParentHook, parent); 117 118 if (status == B_OK && child) 119 status = add_fork_hook(&sChildHooks, &sLastChildHook, child); 120 121 mutex_unlock(&sForkLock); 122 return status; 123 } 124 125 126 pid_t 127 fork(void) 128 { 129 thread_id thread; 130 status_t status; 131 132 status = mutex_lock(&sForkLock); 133 if (status != B_OK) 134 return status; 135 136 // call preparation hooks 137 call_fork_hooks(sPrepareHooks); 138 139 thread = _kern_fork(); 140 if (thread < 0) { 141 // something went wrong 142 mutex_unlock(&sForkLock); 143 __set_errno(thread); 144 return -1; 145 } 146 147 if (thread == 0) { 148 // we are the child 149 // ToDo: initialize child 150 __main_thread_id = find_thread(NULL); 151 pthread_self()->id = __main_thread_id; 152 153 mutex_init(&sForkLock, FORK_LOCK_NAME); 154 // TODO: The lock is already initialized and we in the fork()ing 155 // process we should make sure that it is in a consistent state when 156 // calling the kernel. 157 __gRuntimeLoader->reinit_after_fork(); 158 __reinit_pwd_backend_after_fork(); 159 160 call_fork_hooks(sChildHooks); 161 } else { 162 // we are the parent 163 call_fork_hooks(sParentHooks); 164 mutex_unlock(&sForkLock); 165 } 166 167 return thread; 168 } 169 170 171 pid_t 172 vfork(void) 173 { 174 return fork(); 175 } 176 177