How to call manually fork handlers registered by `pthread_atfork()`?

170 views Asked by At

I am using vfork() in glibc and according to vfork()'s man page:

Fork handlers established using pthread_atfork(3) are not called when a multithreaded program employing the NPTL threading library calls vfork(). Fork handlers are called in this case in a program using the LinuxThreads threading library.

On NPTL fork handlers are not being called. In my specific case I need this protection to be engaged so fork handlers will be called the same way as when calling fork().

Is there a way to cause pthread library to call registered handlers or even call them manually?

I thought of using clone() as it gives more precise control of the cloned process but it also avoids fork handlers:

Handlers registered using pthread_atfork(3) are not executed during a clone call.

Also read how to reset handlers registered by pthread_atfork - in my case I don't want to remove handlers but only call them.

Thanks.

1

There are 1 answers

1
Employed Russian On

Is there a way to cause pthread library to call registered handlers or even call them manually?

If you succeeded in doing this, your program would become corrupt. There is a reason pthread_atfork handlers aren't called on vfork.


A typical usage of pthread_atfork handlers is to guarantee that any locks held in the parent process are in a consistent state in both the child and the parent after the fork.

Without handlers, suppose thread T1 is holding lock L, and thread T2 calls fork. Since only T2 will be replicated into the child, L will remain locked forever. If T2 needs that lock (say it was the malloc lock), T2 will deadlock (with T1 which doesn't exist in the child).

The solution: pthread_atfork handlers. In the parent process prepare() will acquire L, and both parent() and child() handlers will unlock their own instance of L in the parent and child processes respectively. Everything is happy1.


Now consider what happens if you do the same after vfork. prepare() acquires L as expected, but when you call parent() and child(), they unlock the same instance of L (because parent and child processes share memory). Thus L gets unlocked twice, corrupting it!


1 In practice calling either fork or vfork in a multithreaded program is fraught with peril, and doing this safely in the presence of arbitrary libraries is near impossible.