]>
Commit | Line | Data |
---|---|---|
bfff8b1b | 1 | /* Copyright (C) 2002-2017 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 | ||
dd690454 RM |
26 | struct fork_handler *__fork_handlers; |
27 | ||
92d83c72 | 28 | /* Lock to protect allocation and deallocation of fork handlers. */ |
e51deae7 | 29 | int __fork_lock = LLL_LOCK_INITIALIZER; |
4f6f0a8f UD |
30 | |
31 | ||
92d83c72 UD |
32 | /* Number of pre-allocated handler entries. */ |
33 | #define NHANDLER 48 | |
34 | ||
35 | /* Memory pool for fork handler structures. */ | |
36 | static struct fork_handler_pool | |
76a50749 | 37 | { |
92d83c72 UD |
38 | struct fork_handler_pool *next; |
39 | struct fork_handler mem[NHANDLER]; | |
40 | } fork_handler_pool; | |
76a50749 | 41 | |
76a50749 | 42 | |
92d83c72 UD |
43 | static struct fork_handler * |
44 | fork_handler_alloc (void) | |
45 | { | |
46 | struct fork_handler_pool *runp = &fork_handler_pool; | |
47 | struct fork_handler *result = NULL; | |
48 | unsigned int i; | |
76a50749 | 49 | |
92d83c72 | 50 | do |
76a50749 | 51 | { |
92d83c72 UD |
52 | /* Search for an empty entry. */ |
53 | for (i = 0; i < NHANDLER; ++i) | |
54 | if (runp->mem[i].refcntr == 0) | |
55 | goto found; | |
76a50749 | 56 | } |
92d83c72 | 57 | while ((runp = runp->next) != NULL); |
76a50749 | 58 | |
92d83c72 UD |
59 | /* We have to allocate a new entry. */ |
60 | runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp)); | |
61 | if (runp != NULL) | |
76a50749 | 62 | { |
92d83c72 UD |
63 | /* Enqueue the new memory pool into the list. */ |
64 | runp->next = fork_handler_pool.next; | |
65 | fork_handler_pool.next = runp; | |
66 | ||
67 | /* We use the last entry on the page. This means when we start | |
68 | searching from the front the next time we will find the first | |
69 | entry unused. */ | |
70 | i = NHANDLER - 1; | |
71 | ||
72 | found: | |
73 | result = &runp->mem[i]; | |
74 | result->refcntr = 1; | |
75 | result->need_signal = 0; | |
76a50749 UD |
76 | } |
77 | ||
92d83c72 | 78 | return result; |
76a50749 | 79 | } |
54e0138f UD |
80 | |
81 | ||
92d83c72 | 82 | int |
80d9be81 JM |
83 | __register_atfork (void (*prepare) (void), void (*parent) (void), |
84 | void (*child) (void), void *dso_handle) | |
54e0138f | 85 | { |
92d83c72 | 86 | /* Get the lock to not conflict with other allocations. */ |
e51deae7 | 87 | lll_lock (__fork_lock, LLL_PRIVATE); |
54e0138f | 88 | |
92d83c72 UD |
89 | struct fork_handler *newp = fork_handler_alloc (); |
90 | ||
91 | if (newp != NULL) | |
92 | { | |
93 | /* Initialize the new record. */ | |
94 | newp->prepare_handler = prepare; | |
95 | newp->parent_handler = parent; | |
96 | newp->child_handler = child; | |
97 | newp->dso_handle = dso_handle; | |
98 | ||
b92e3780 | 99 | __linkin_atfork (newp); |
92d83c72 | 100 | } |
54e0138f UD |
101 | |
102 | /* Release the lock. */ | |
e51deae7 | 103 | lll_unlock (__fork_lock, LLL_PRIVATE); |
92d83c72 UD |
104 | |
105 | return newp == NULL ? ENOMEM : 0; | |
54e0138f | 106 | } |
8ba1d429 | 107 | libc_hidden_def (__register_atfork) |
dfdd294a UD |
108 | |
109 | ||
ad3371fb UD |
110 | void |
111 | attribute_hidden | |
112 | __linkin_atfork (struct fork_handler *newp) | |
113 | { | |
114 | do | |
115 | newp->next = __fork_handlers; | |
116 | while (catomic_compare_and_exchange_bool_acq (&__fork_handlers, | |
117 | newp, newp->next) != 0); | |
118 | } | |
119 | ||
120 | ||
dfdd294a UD |
121 | libc_freeres_fn (free_mem) |
122 | { | |
123 | /* Get the lock to not conflict with running forks. */ | |
e51deae7 | 124 | lll_lock (__fork_lock, LLL_PRIVATE); |
dfdd294a | 125 | |
92d83c72 UD |
126 | /* No more fork handlers. */ |
127 | __fork_handlers = NULL; | |
dfdd294a | 128 | |
c0c3f78a | 129 | /* Free eventually allocated memory blocks for the object pool. */ |
92d83c72 | 130 | struct fork_handler_pool *runp = fork_handler_pool.next; |
dfdd294a | 131 | |
92d83c72 | 132 | memset (&fork_handler_pool, '\0', sizeof (fork_handler_pool)); |
dfdd294a | 133 | |
92d83c72 | 134 | /* Release the lock. */ |
e51deae7 | 135 | lll_unlock (__fork_lock, LLL_PRIVATE); |
dfdd294a | 136 | |
92d83c72 UD |
137 | /* We can free the memory after releasing the lock. */ |
138 | while (runp != NULL) | |
dfdd294a | 139 | { |
3e335bbc | 140 | struct fork_handler_pool *oldp = runp; |
92d83c72 UD |
141 | runp = runp->next; |
142 | free (oldp); | |
dfdd294a | 143 | } |
dfdd294a | 144 | } |