register-atfork.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <errno.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <fork.h>
  19. #include <atomic.h>
  20. #include <tls.h>
  21. #ifdef __ARCH_USE_MMU__
  22. /* Lock to protect allocation and deallocation of fork handlers. */
  23. int __fork_lock = LLL_LOCK_INITIALIZER;
  24. /* Number of pre-allocated handler entries. */
  25. #define NHANDLER 48
  26. /* Memory pool for fork handler structures. */
  27. static struct fork_handler_pool
  28. {
  29. struct fork_handler_pool *next;
  30. struct fork_handler mem[NHANDLER];
  31. } fork_handler_pool;
  32. static struct fork_handler *
  33. fork_handler_alloc (void)
  34. {
  35. struct fork_handler_pool *runp = &fork_handler_pool;
  36. struct fork_handler *result = NULL;
  37. unsigned int i;
  38. do
  39. {
  40. /* Search for an empty entry. */
  41. for (i = 0; i < NHANDLER; ++i)
  42. if (runp->mem[i].refcntr == 0)
  43. goto found;
  44. }
  45. while ((runp = runp->next) != NULL);
  46. /* We have to allocate a new entry. */
  47. runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp));
  48. if (runp != NULL)
  49. {
  50. /* Enqueue the new memory pool into the list. */
  51. runp->next = fork_handler_pool.next;
  52. fork_handler_pool.next = runp;
  53. /* We use the last entry on the page. This means when we start
  54. searching from the front the next time we will find the first
  55. entry unused. */
  56. i = NHANDLER - 1;
  57. found:
  58. result = &runp->mem[i];
  59. result->refcntr = 1;
  60. result->need_signal = 0;
  61. }
  62. return result;
  63. }
  64. int
  65. __register_atfork (
  66. void (*prepare) (void),
  67. void (*parent) (void),
  68. void (*child) (void),
  69. void *dso_handle)
  70. {
  71. /* Get the lock to not conflict with other allocations. */
  72. lll_lock (__fork_lock, LLL_PRIVATE);
  73. struct fork_handler *newp = fork_handler_alloc ();
  74. if (newp != NULL)
  75. {
  76. /* Initialize the new record. */
  77. newp->prepare_handler = prepare;
  78. newp->parent_handler = parent;
  79. newp->child_handler = child;
  80. newp->dso_handle = dso_handle;
  81. __linkin_atfork (newp);
  82. }
  83. /* Release the lock. */
  84. lll_unlock (__fork_lock, LLL_PRIVATE);
  85. return newp == NULL ? ENOMEM : 0;
  86. }
  87. libc_hidden_def (__register_atfork)
  88. void
  89. attribute_hidden
  90. __linkin_atfork (struct fork_handler *newp)
  91. {
  92. do
  93. newp->next = __fork_handlers;
  94. while (catomic_compare_and_exchange_bool_acq (&__fork_handlers,
  95. newp, newp->next) != 0);
  96. }
  97. #else
  98. int
  99. __register_atfork (
  100. void (*prepare) (void),
  101. void (*parent) (void),
  102. void (*child) (void),
  103. void *dso_handle)
  104. {
  105. return EPERM;
  106. }
  107. libc_hidden_def (__register_atfork)
  108. #endif
  109. #if 0
  110. libc_freeres_fn (free_mem)
  111. {
  112. /* Get the lock to not conflict with running forks. */
  113. lll_lock (__fork_lock, LLL_PRIVATE);
  114. /* No more fork handlers. */
  115. __fork_handlers = NULL;
  116. /* Free eventually alloated memory blocks for the object pool. */
  117. struct fork_handler_pool *runp = fork_handler_pool.next;
  118. memset (&fork_handler_pool, '\0', sizeof (fork_handler_pool));
  119. /* Release the lock. */
  120. lll_unlock (__fork_lock, LLL_PRIVATE);
  121. /* We can free the memory after releasing the lock. */
  122. while (runp != NULL)
  123. {
  124. struct fork_handler_pool *oldp = runp;
  125. runp = runp->next;
  126. free (oldp);
  127. }
  128. }
  129. #endif