1570af302Sopenharmony_ci#include <unistd.h>
2570af302Sopenharmony_ci#include <errno.h>
3570af302Sopenharmony_ci#include "libc.h"
4570af302Sopenharmony_ci#include "lock.h"
5570af302Sopenharmony_ci#include "pthread_impl.h"
6570af302Sopenharmony_ci#include "fork_impl.h"
7570af302Sopenharmony_ci
8570af302Sopenharmony_cistatic volatile int *const dummy_lockptr = 0;
9570af302Sopenharmony_ci
10570af302Sopenharmony_ciweak_alias(dummy_lockptr, __at_quick_exit_lockptr);
11570af302Sopenharmony_ciweak_alias(dummy_lockptr, __atexit_lockptr);
12570af302Sopenharmony_ciweak_alias(dummy_lockptr, __gettext_lockptr);
13570af302Sopenharmony_ciweak_alias(dummy_lockptr, __locale_lockptr);
14570af302Sopenharmony_ciweak_alias(dummy_lockptr, __random_lockptr);
15570af302Sopenharmony_ciweak_alias(dummy_lockptr, __sem_open_lockptr);
16570af302Sopenharmony_ciweak_alias(dummy_lockptr, __stdio_ofl_lockptr);
17570af302Sopenharmony_ciweak_alias(dummy_lockptr, __syslog_lockptr);
18570af302Sopenharmony_ciweak_alias(dummy_lockptr, __timezone_lockptr);
19570af302Sopenharmony_ciweak_alias(dummy_lockptr, __bump_lockptr);
20570af302Sopenharmony_ci
21570af302Sopenharmony_ciweak_alias(dummy_lockptr, __vmlock_lockptr);
22570af302Sopenharmony_ci
23570af302Sopenharmony_cistatic volatile int *const *const atfork_locks[] = {
24570af302Sopenharmony_ci	&__at_quick_exit_lockptr,
25570af302Sopenharmony_ci	&__atexit_lockptr,
26570af302Sopenharmony_ci	&__gettext_lockptr,
27570af302Sopenharmony_ci	&__locale_lockptr,
28570af302Sopenharmony_ci	&__random_lockptr,
29570af302Sopenharmony_ci	&__sem_open_lockptr,
30570af302Sopenharmony_ci	&__stdio_ofl_lockptr,
31570af302Sopenharmony_ci	&__syslog_lockptr,
32570af302Sopenharmony_ci	&__timezone_lockptr,
33570af302Sopenharmony_ci	&__bump_lockptr,
34570af302Sopenharmony_ci};
35570af302Sopenharmony_ci
36570af302Sopenharmony_cistatic void dummy(int x) { }
37570af302Sopenharmony_ciweak_alias(dummy, __fork_handler);
38570af302Sopenharmony_ciweak_alias(dummy, __malloc_atfork);
39570af302Sopenharmony_ciweak_alias(dummy, __aio_atfork);
40570af302Sopenharmony_ciweak_alias(dummy, __pthread_key_atfork);
41570af302Sopenharmony_ciweak_alias(dummy, __ldso_atfork);
42570af302Sopenharmony_ci
43570af302Sopenharmony_cistatic void dummy_0(void) { }
44570af302Sopenharmony_ciweak_alias(dummy_0, __tl_lock);
45570af302Sopenharmony_ciweak_alias(dummy_0, __tl_unlock);
46570af302Sopenharmony_ci
47570af302Sopenharmony_cipid_t fork(void)
48570af302Sopenharmony_ci{
49570af302Sopenharmony_ci	sigset_t set;
50570af302Sopenharmony_ci	__fork_handler(-1);
51570af302Sopenharmony_ci	__block_app_sigs(&set);
52570af302Sopenharmony_ci	int need_locks = libc.need_locks > 0;
53570af302Sopenharmony_ci	if (need_locks) {
54570af302Sopenharmony_ci		__ldso_atfork(-1);
55570af302Sopenharmony_ci		__pthread_key_atfork(-1);
56570af302Sopenharmony_ci		__aio_atfork(-1);
57570af302Sopenharmony_ci		__inhibit_ptc();
58570af302Sopenharmony_ci		for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
59570af302Sopenharmony_ci			if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
60570af302Sopenharmony_ci		__malloc_atfork(-1);
61570af302Sopenharmony_ci		__tl_lock();
62570af302Sopenharmony_ci	}
63570af302Sopenharmony_ci	pthread_t self=__pthread_self(), next=self->next;
64570af302Sopenharmony_ci	pid_t ret = _Fork();
65570af302Sopenharmony_ci	int errno_save = errno;
66570af302Sopenharmony_ci	if (need_locks) {
67570af302Sopenharmony_ci		if (!ret) {
68570af302Sopenharmony_ci			for (pthread_t td=next; td!=self; td=td->next)
69570af302Sopenharmony_ci				td->tid = -1;
70570af302Sopenharmony_ci			if (__vmlock_lockptr) {
71570af302Sopenharmony_ci				__vmlock_lockptr[0] = 0;
72570af302Sopenharmony_ci				__vmlock_lockptr[1] = 0;
73570af302Sopenharmony_ci			}
74570af302Sopenharmony_ci		}
75570af302Sopenharmony_ci		__tl_unlock();
76570af302Sopenharmony_ci		__malloc_atfork(!ret);
77570af302Sopenharmony_ci		for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
78570af302Sopenharmony_ci			if (*atfork_locks[i])
79570af302Sopenharmony_ci				if (ret) UNLOCK(*atfork_locks[i]);
80570af302Sopenharmony_ci				else **atfork_locks[i] = 0;
81570af302Sopenharmony_ci		__release_ptc();
82570af302Sopenharmony_ci		if (ret) __aio_atfork(0);
83570af302Sopenharmony_ci		__pthread_key_atfork(!ret);
84570af302Sopenharmony_ci		__ldso_atfork(!ret);
85570af302Sopenharmony_ci	}
86570af302Sopenharmony_ci	__restore_sigs(&set);
87570af302Sopenharmony_ci	__fork_handler(!ret);
88570af302Sopenharmony_ci	if (ret<0) errno = errno_save;
89570af302Sopenharmony_ci	return ret;
90570af302Sopenharmony_ci}
91