2 * Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
13 #include <errno_private.h>
15 #include <libroot_private.h>
16 #include <pthread_private.h>
17 #include <runtime_loader.h>
19 #include <user_thread.h>
22 typedef struct fork_hook
{
23 struct fork_hook
*next
;
24 void (*function
)(void);
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.
44 add_fork_hook(fork_hook
**_hooks
, fork_hook
**_lastHook
, void (*function
)(void))
46 fork_hook
*hook
= (fork_hook
*)malloc(sizeof(struct fork_hook
));
50 hook
->function
= function
;
53 // add hook at the end of the list
55 if (*_hooks
== NULL
) {
56 // first entry of this list
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
;
73 (*_lastHook
)->next
= hook
;
79 // add hook at the beginning of the list
88 /** Calls all hooks in the specified list in ascending order.
92 call_fork_hooks(fork_hook
*hook
)
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().
107 __register_atfork(void (*prepare
)(void), void (*parent
)(void), void (*child
)(void))
113 status
= mutex_lock(&sForkLock
);
114 if (status
!= B_OK
) {
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
);
144 status
= mutex_lock(&sForkLock
);
145 if (status
!= B_OK
) {
150 // call preparation hooks
151 call_fork_hooks(sPrepareHooks
);
152 __heap_before_fork();
154 thread
= _kern_fork();
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
);
172 __heap_after_fork_parent();
173 call_fork_hooks(sParentHooks
);
174 mutex_unlock(&sForkLock
);
180 // something went wrong