Update libc.pot for 2.35 release.
[glibc.git] / posix / register-atfork.c
blob74b1b58404f3acd65c02c77bd82bded8e74c6823
1 /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
18 #include <libc-lock.h>
19 #include <stdbool.h>
20 #include <register-atfork.h>
22 #define DYNARRAY_ELEMENT struct fork_handler
23 #define DYNARRAY_STRUCT fork_handler_list
24 #define DYNARRAY_PREFIX fork_handler_list_
25 #define DYNARRAY_INITIAL_SIZE 48
26 #include <malloc/dynarray-skeleton.c>
28 static struct fork_handler_list fork_handlers;
29 static bool fork_handler_init = false;
31 static int atfork_lock = LLL_LOCK_INITIALIZER;
33 int
34 __register_atfork (void (*prepare) (void), void (*parent) (void),
35 void (*child) (void), void *dso_handle)
37 lll_lock (atfork_lock, LLL_PRIVATE);
39 if (!fork_handler_init)
41 fork_handler_list_init (&fork_handlers);
42 fork_handler_init = true;
45 struct fork_handler *newp = fork_handler_list_emplace (&fork_handlers);
46 if (newp != NULL)
48 newp->prepare_handler = prepare;
49 newp->parent_handler = parent;
50 newp->child_handler = child;
51 newp->dso_handle = dso_handle;
54 /* Release the lock. */
55 lll_unlock (atfork_lock, LLL_PRIVATE);
57 return newp == NULL ? ENOMEM : 0;
59 libc_hidden_def (__register_atfork)
61 static struct fork_handler *
62 fork_handler_list_find (struct fork_handler_list *fork_handlers,
63 void *dso_handle)
65 for (size_t i = 0; i < fork_handler_list_size (fork_handlers); i++)
67 struct fork_handler *elem = fork_handler_list_at (fork_handlers, i);
68 if (elem->dso_handle == dso_handle)
69 return elem;
71 return NULL;
74 void
75 __unregister_atfork (void *dso_handle)
77 lll_lock (atfork_lock, LLL_PRIVATE);
79 struct fork_handler *first = fork_handler_list_find (&fork_handlers,
80 dso_handle);
81 /* Removing is done by shifting the elements in the way the elements
82 that are not to be removed appear in the beginning in dynarray.
83 This avoid the quadradic run-time if a naive strategy to remove and
84 shift one element at time. */
85 if (first != NULL)
87 struct fork_handler *new_end = first;
88 first++;
89 for (; first != fork_handler_list_end (&fork_handlers); ++first)
91 if (first->dso_handle != dso_handle)
93 *new_end = *first;
94 ++new_end;
98 ptrdiff_t removed = first - new_end;
99 for (size_t i = 0; i < removed; i++)
100 fork_handler_list_remove_last (&fork_handlers);
103 lll_unlock (atfork_lock, LLL_PRIVATE);
106 void
107 __run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
109 struct fork_handler *runp;
111 if (who == atfork_run_prepare)
113 if (do_locking)
114 lll_lock (atfork_lock, LLL_PRIVATE);
115 size_t sl = fork_handler_list_size (&fork_handlers);
116 for (size_t i = sl; i > 0; i--)
118 runp = fork_handler_list_at (&fork_handlers, i - 1);
119 if (runp->prepare_handler != NULL)
120 runp->prepare_handler ();
123 else
125 size_t sl = fork_handler_list_size (&fork_handlers);
126 for (size_t i = 0; i < sl; i++)
128 runp = fork_handler_list_at (&fork_handlers, i);
129 if (who == atfork_run_child && runp->child_handler)
130 runp->child_handler ();
131 else if (who == atfork_run_parent && runp->parent_handler)
132 runp->parent_handler ();
134 if (do_locking)
135 lll_unlock (atfork_lock, LLL_PRIVATE);
140 libc_freeres_fn (free_mem)
142 lll_lock (atfork_lock, LLL_PRIVATE);
144 fork_handler_list_free (&fork_handlers);
146 lll_unlock (atfork_lock, LLL_PRIVATE);