summaryrefslogtreecommitdiff
path: root/src/aio
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2020-09-28 18:38:27 -0400
committerRich Felker <dalias@aerifal.cx>2020-09-28 18:56:20 -0400
commit34904d830a9fd1f6fc47218f38c111698303d2fe (patch)
treec43e8b5659386f5a3ed4f5e749d389f2fb91027b /src/aio
parenta5aff1972c9e3981566414b09a28e331ccd2be5d (diff)
downloadmusl-34904d830a9fd1f6fc47218f38c111698303d2fe.tar.gz
fix fork of processes with active async io contexts
previously, if a file descriptor had aio operations pending in the parent before fork, attempting to close it in the child would attempt to cancel a thread belonging to the parent. this could deadlock, fail, or crash the whole process of the cancellation signal handler was not yet installed in the parent. in addition, further use of aio from the child could malfunction or deadlock. POSIX specifies that async io operations are not inherited by the child on fork, so clear the entire aio fd map in the child, and take the aio map lock (with signals blocked) across the fork so that the lock is kept in a consistent state.
Diffstat (limited to 'src/aio')
-rw-r--r--src/aio/aio.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/src/aio/aio.c b/src/aio/aio.c
index 6d34fa86..f59679c3 100644
--- a/src/aio/aio.c
+++ b/src/aio/aio.c
@@ -392,6 +392,20 @@ int __aio_close(int fd)
return fd;
}
+void __aio_atfork(int who)
+{
+ if (who<0) {
+ pthread_rwlock_rdlock(&maplock);
+ return;
+ }
+ if (who>0 && 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);
+}
+
weak_alias(aio_cancel, aio_cancel64);
weak_alias(aio_error, aio_error64);
weak_alias(aio_fsync, aio_fsync64);