tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: pthread_atfork and locks



   Date: Mon, 23 Jun 2014 11:26:09 -0400
   From: Greg Troxel <gdt%ir.bbn.com@localhost>

   We had a big problem with this where python (among other things) would
   fork and then call malloc in the child.   If the malloc lock were taken
   by some other thread in the parent, then it would deadlock.  python is
   wrong here, as malloc is not specificed to be async-signal-safe.   But
   the workaround (which I'm a bit fuzzy on) was to take the malloc lock
   in the before handler and release it in both - in libc, not in python.

As an aside, that's probably still an issue with NetBSD libc -- I
don't see any atfork handler in our malloc code.

   > There is a long comment in src/lib/libc/gen/pthread_atfork.c
   > explaining why the child does mutex_init instead of mutex_unlock: if
   > the spin lock inside a mutex is held by another thread, then trying to
   > unlock the mutex in the child will wait forever because the other
   > thread won't be there in the child.

   I think this is unsound (calling mutex_init).   If the mutex is acquired
   in the thread that calls fork, then it should be safe to unlock it.

Calling mutex_init is safe in our implementation of libpthread.  It's
just not portable.  The question with mutex_unlock is whether, if some
other thread was trying to lock the mutex at the time of the fork,
some state internal to the mutex might be inconsistent in the child.

   Are you trying to figure out how to have the child act like a
   full-fledged process without doing an exec?   I don't think that's
   really possible.

Trying to figure out how to make a library with global state work in
multithreaded programs and in programs that use fork, without randomly
hanging or duplicating invariants or (for arc4random(3)) leaking
secrets to the children or anything horrible like that.

As far as I can tell, the intent in POSIX is that you should be able
to pthread_atfork(/*prepare*/lock, /*parent*/unlock, /*child*/unlock).
But I'm not confident we guarantee that to work in NetBSD, and we
ought to.


Home | Main Index | Thread Index | Old Index