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