about summary refs log tree commit diff
path: root/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps/unix/sysv/linux/unregister-atfork.c')
-rw-r--r--nptl/sysdeps/unix/sysv/linux/unregister-atfork.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
index 56a4f149e1..c738acd0c3 100644
--- a/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
+++ b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
@@ -67,10 +67,21 @@ __unregister_atfork (dso_handle)
      It's a single linked list so readers are.  */
   do
     {
+    again:
       if (runp->dso_handle == dso_handle)
 	{
 	  if (lastp == NULL)
-	    __fork_handlers = runp->next;
+	    {
+	      /* We have to use an atomic operation here because
+		 __linkin_atfork also uses one.  */
+	      if (catomic_compare_and_exchange_bool_acq (&__fork_handlers,
+							 runp->next, runp)
+		  != 0)
+		{
+		  runp = __fork_handlers;
+		  goto again;
+		}
+	    }
 	  else
 	    lastp->next = runp->next;