summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/aio/aio.c19
-rw-r--r--src/process/_Fork.c3
-rw-r--r--src/process/fork.c3
3 files changed, 21 insertions, 4 deletions
diff --git a/src/aio/aio.c b/src/aio/aio.c
index fa24f6b6..82f8eccb 100644
--- a/src/aio/aio.c
+++ b/src/aio/aio.c
@@ -401,11 +401,26 @@ void __aio_atfork(int who)
if (who<0) {
pthread_rwlock_rdlock(&maplock);
return;
+ } else if (!who) {
+ pthread_rwlock_unlock(&maplock);
+ return;
}
- if (who>0 && map) for (int a=0; a<(-1U/2+1)>>24; a++)
+ aio_fd_cnt = 0;
+ if (pthread_rwlock_tryrdlock(&maplock)) {
+ /* Obtaining lock may fail if _Fork was called nor via
+ * fork. In this case, no further aio is possible from
+ * child and we can just null out map so __aio_close
+ * does not attempt to do anything. */
+ map = 0;
+ return;
+ }
+ if (map) for (int a=0; a<(-1U/2+1)>>24; a++)
if (map[a]) for (int b=0; b<256; b++)
if (map[a][b]) for (int c=0; c<256; c++)
if (map[a][b][c]) for (int d=0; d<256; d++)
map[a][b][c][d] = 0;
- pthread_rwlock_unlock(&maplock);
+ /* Re-initialize the rwlock rather than unlocking since there
+ * may have been more than one reference on it in the parent.
+ * We are not a lock holder anyway; the thread in the parent was. */
+ pthread_rwlock_init(&maplock, 0);
}
diff --git a/src/process/_Fork.c b/src/process/_Fork.c
index da063868..fb0fdc2c 100644
--- a/src/process/_Fork.c
+++ b/src/process/_Fork.c
@@ -14,7 +14,6 @@ pid_t _Fork(void)
pid_t ret;
sigset_t set;
__block_all_sigs(&set);
- __aio_atfork(-1);
LOCK(__abort_lock);
#ifdef SYS_fork
ret = __syscall(SYS_fork);
@@ -32,7 +31,7 @@ pid_t _Fork(void)
if (libc.need_locks) libc.need_locks = -1;
}
UNLOCK(__abort_lock);
- __aio_atfork(!ret);
+ if (!ret) __aio_atfork(1);
__restore_sigs(&set);
return __syscall_ret(ret);
}
diff --git a/src/process/fork.c b/src/process/fork.c
index ff71845c..80e804b1 100644
--- a/src/process/fork.c
+++ b/src/process/fork.c
@@ -36,6 +36,7 @@ static volatile int *const *const atfork_locks[] = {
static void dummy(int x) { }
weak_alias(dummy, __fork_handler);
weak_alias(dummy, __malloc_atfork);
+weak_alias(dummy, __aio_atfork);
weak_alias(dummy, __ldso_atfork);
static void dummy_0(void) { }
@@ -50,6 +51,7 @@ pid_t fork(void)
int need_locks = libc.need_locks > 0;
if (need_locks) {
__ldso_atfork(-1);
+ __aio_atfork(-1);
__inhibit_ptc();
for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
@@ -75,6 +77,7 @@ pid_t fork(void)
if (ret) UNLOCK(*atfork_locks[i]);
else **atfork_locks[i] = 0;
__release_ptc();
+ if (ret) __aio_atfork(0);
__ldso_atfork(!ret);
}
__restore_sigs(&set);