|
@@ -1,15 +1,85 @@
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <errno.h>
|
|
#include "libc.h"
|
|
#include "libc.h"
|
|
|
|
+#include "lock.h"
|
|
|
|
+#include "pthread_impl.h"
|
|
|
|
+#include "fork_impl.h"
|
|
|
|
+
|
|
|
|
+static volatile int *const dummy_lockptr = 0;
|
|
|
|
+
|
|
|
|
+weak_alias(dummy_lockptr, __at_quick_exit_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __atexit_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __dlerror_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __gettext_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __locale_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __random_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __sem_open_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __stdio_ofl_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __syslog_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __timezone_lockptr);
|
|
|
|
+weak_alias(dummy_lockptr, __bump_lockptr);
|
|
|
|
+
|
|
|
|
+weak_alias(dummy_lockptr, __vmlock_lockptr);
|
|
|
|
+
|
|
|
|
+static volatile int *const *const atfork_locks[] = {
|
|
|
|
+ &__at_quick_exit_lockptr,
|
|
|
|
+ &__atexit_lockptr,
|
|
|
|
+ &__dlerror_lockptr,
|
|
|
|
+ &__gettext_lockptr,
|
|
|
|
+ &__locale_lockptr,
|
|
|
|
+ &__random_lockptr,
|
|
|
|
+ &__sem_open_lockptr,
|
|
|
|
+ &__stdio_ofl_lockptr,
|
|
|
|
+ &__syslog_lockptr,
|
|
|
|
+ &__timezone_lockptr,
|
|
|
|
+ &__bump_lockptr,
|
|
|
|
+};
|
|
|
|
|
|
static void dummy(int x) { }
|
|
static void dummy(int x) { }
|
|
weak_alias(dummy, __fork_handler);
|
|
weak_alias(dummy, __fork_handler);
|
|
|
|
+weak_alias(dummy, __malloc_atfork);
|
|
|
|
+weak_alias(dummy, __ldso_atfork);
|
|
|
|
+
|
|
|
|
+static void dummy_0(void) { }
|
|
|
|
+weak_alias(dummy_0, __tl_lock);
|
|
|
|
+weak_alias(dummy_0, __tl_unlock);
|
|
|
|
|
|
pid_t fork(void)
|
|
pid_t fork(void)
|
|
{
|
|
{
|
|
|
|
+ sigset_t set;
|
|
__fork_handler(-1);
|
|
__fork_handler(-1);
|
|
|
|
+ __block_app_sigs(&set);
|
|
|
|
+ int need_locks = libc.need_locks > 0;
|
|
|
|
+ if (need_locks) {
|
|
|
|
+ __ldso_atfork(-1);
|
|
|
|
+ __inhibit_ptc();
|
|
|
|
+ for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
|
|
|
|
+ if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
|
|
|
|
+ __malloc_atfork(-1);
|
|
|
|
+ __tl_lock();
|
|
|
|
+ }
|
|
|
|
+ pthread_t self=__pthread_self(), next=self->next;
|
|
pid_t ret = _Fork();
|
|
pid_t ret = _Fork();
|
|
int errno_save = errno;
|
|
int errno_save = errno;
|
|
|
|
+ if (need_locks) {
|
|
|
|
+ if (!ret) {
|
|
|
|
+ for (pthread_t td=next; td!=self; td=td->next)
|
|
|
|
+ td->tid = -1;
|
|
|
|
+ if (__vmlock_lockptr) {
|
|
|
|
+ __vmlock_lockptr[0] = 0;
|
|
|
|
+ __vmlock_lockptr[1] = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ __tl_unlock();
|
|
|
|
+ __malloc_atfork(!ret);
|
|
|
|
+ for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
|
|
|
|
+ if (*atfork_locks[i])
|
|
|
|
+ if (ret) UNLOCK(*atfork_locks[i]);
|
|
|
|
+ else **atfork_locks[i] = 0;
|
|
|
|
+ __release_ptc();
|
|
|
|
+ __ldso_atfork(!ret);
|
|
|
|
+ }
|
|
|
|
+ __restore_sigs(&set);
|
|
__fork_handler(!ret);
|
|
__fork_handler(!ret);
|
|
if (ret<0) errno = errno_save;
|
|
if (ret<0) errno = errno_save;
|
|
return ret;
|
|
return ret;
|