Back to index

glibc  2.9
register-atfork.c
Go to the documentation of this file.
00001 /* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <fork.h>
00024 #include <atomic.h>
00025 
00026 
00027 /* Lock to protect allocation and deallocation of fork handlers.  */
00028 int __fork_lock = LLL_LOCK_INITIALIZER;
00029 
00030 
00031 /* Number of pre-allocated handler entries.  */
00032 #define NHANDLER 48
00033 
00034 /* Memory pool for fork handler structures.  */
00035 static struct fork_handler_pool
00036 {
00037   struct fork_handler_pool *next;
00038   struct fork_handler mem[NHANDLER];
00039 } fork_handler_pool;
00040 
00041 
00042 static struct fork_handler *
00043 fork_handler_alloc (void)
00044 {
00045   struct fork_handler_pool *runp = &fork_handler_pool;
00046   struct fork_handler *result = NULL;
00047   unsigned int i;
00048 
00049   do
00050     {
00051       /* Search for an empty entry.  */
00052       for (i = 0; i < NHANDLER; ++i)
00053        if (runp->mem[i].refcntr == 0)
00054          goto found;
00055     }
00056   while ((runp = runp->next) != NULL);
00057 
00058   /* We have to allocate a new entry.  */
00059   runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp));
00060   if (runp != NULL)
00061     {
00062       /* Enqueue the new memory pool into the list.  */
00063       runp->next = fork_handler_pool.next;
00064       fork_handler_pool.next = runp;
00065 
00066       /* We use the last entry on the page.  This means when we start
00067         searching from the front the next time we will find the first
00068         entry unused.  */
00069       i = NHANDLER - 1;
00070 
00071     found:
00072       result = &runp->mem[i];
00073       result->refcntr = 1;
00074       result->need_signal = 0;
00075     }
00076 
00077   return result;
00078 }
00079 
00080 
00081 int
00082 __register_atfork (prepare, parent, child, dso_handle)
00083      void (*prepare) (void);
00084      void (*parent) (void);
00085      void (*child) (void);
00086      void *dso_handle;
00087 {
00088   /* Get the lock to not conflict with other allocations.  */
00089   lll_lock (__fork_lock, LLL_PRIVATE);
00090 
00091   struct fork_handler *newp = fork_handler_alloc ();
00092 
00093   if (newp != NULL)
00094     {
00095       /* Initialize the new record.  */
00096       newp->prepare_handler = prepare;
00097       newp->parent_handler = parent;
00098       newp->child_handler = child;
00099       newp->dso_handle = dso_handle;
00100 
00101       __linkin_atfork (newp);
00102     }
00103 
00104   /* Release the lock.  */
00105   lll_unlock (__fork_lock, LLL_PRIVATE);
00106 
00107   return newp == NULL ? ENOMEM : 0;
00108 }
00109 libc_hidden_def (__register_atfork)
00110 
00111 
00112 void
00113 attribute_hidden
00114 __linkin_atfork (struct fork_handler *newp)
00115 {
00116   do
00117     newp->next = __fork_handlers;
00118   while (catomic_compare_and_exchange_bool_acq (&__fork_handlers,
00119                                           newp, newp->next) != 0);
00120 }
00121 
00122 
00123 libc_freeres_fn (free_mem)
00124 {
00125   /* Get the lock to not conflict with running forks.  */
00126   lll_lock (__fork_lock, LLL_PRIVATE);
00127 
00128   /* No more fork handlers.  */
00129   __fork_handlers = NULL;
00130 
00131   /* Free eventually alloated memory blocks for the object pool.  */
00132   struct fork_handler_pool *runp = fork_handler_pool.next;
00133 
00134   memset (&fork_handler_pool, '\0', sizeof (fork_handler_pool));
00135 
00136   /* Release the lock.  */
00137   lll_unlock (__fork_lock, LLL_PRIVATE);
00138 
00139   /* We can free the memory after releasing the lock.  */
00140   while (runp != NULL)
00141     {
00142       struct fork_handler_pool *oldp = runp;
00143       runp = runp->next;
00144       free (oldp);
00145     }
00146 }