]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/register-atfork.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / nptl / register-atfork.c
CommitLineData
2b778ceb 1/* Copyright (C) 2002-2021 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 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://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 24
27761a10
AZ
25#define DYNARRAY_ELEMENT struct fork_handler
26#define DYNARRAY_STRUCT fork_handler_list
27#define DYNARRAY_PREFIX fork_handler_list_
28#define DYNARRAY_INITIAL_SIZE 48
29#include <malloc/dynarray-skeleton.c>
76a50749 30
27761a10
AZ
31static struct fork_handler_list fork_handlers;
32static bool fork_handler_init = false;
54e0138f 33
27761a10 34static int atfork_lock = LLL_LOCK_INITIALIZER;
54e0138f 35
92d83c72 36int
80d9be81
JM
37__register_atfork (void (*prepare) (void), void (*parent) (void),
38 void (*child) (void), void *dso_handle)
54e0138f 39{
27761a10 40 lll_lock (atfork_lock, LLL_PRIVATE);
54e0138f 41
27761a10
AZ
42 if (!fork_handler_init)
43 {
44 fork_handler_list_init (&fork_handlers);
45 fork_handler_init = true;
46 }
92d83c72 47
27761a10 48 struct fork_handler *newp = fork_handler_list_emplace (&fork_handlers);
92d83c72
UD
49 if (newp != NULL)
50 {
92d83c72
UD
51 newp->prepare_handler = prepare;
52 newp->parent_handler = parent;
53 newp->child_handler = child;
54 newp->dso_handle = dso_handle;
92d83c72 55 }
54e0138f
UD
56
57 /* Release the lock. */
27761a10 58 lll_unlock (atfork_lock, LLL_PRIVATE);
92d83c72
UD
59
60 return newp == NULL ? ENOMEM : 0;
54e0138f 61}
8ba1d429 62libc_hidden_def (__register_atfork)
dfdd294a 63
27761a10
AZ
64static struct fork_handler *
65fork_handler_list_find (struct fork_handler_list *fork_handlers,
66 void *dso_handle)
67{
68 for (size_t i = 0; i < fork_handler_list_size (fork_handlers); i++)
69 {
70 struct fork_handler *elem = fork_handler_list_at (fork_handlers, i);
71 if (elem->dso_handle == dso_handle)
72 return elem;
73 }
74 return NULL;
75}
dfdd294a 76
ad3371fb 77void
27761a10 78__unregister_atfork (void *dso_handle)
ad3371fb 79{
27761a10
AZ
80 lll_lock (atfork_lock, LLL_PRIVATE);
81
82 struct fork_handler *first = fork_handler_list_find (&fork_handlers,
83 dso_handle);
84 /* Removing is done by shifting the elements in the way the elements
85 that are not to be removed appear in the beginning in dynarray.
86 This avoid the quadradic run-time if a naive strategy to remove and
87 shift one element at time. */
88 if (first != NULL)
89 {
90 struct fork_handler *new_end = first;
91 first++;
92 for (; first != fork_handler_list_end (&fork_handlers); ++first)
93 {
94 if (first->dso_handle != dso_handle)
95 {
96 *new_end = *first;
97 ++new_end;
98 }
99 }
100
101 ptrdiff_t removed = first - new_end;
102 for (size_t i = 0; i < removed; i++)
103 fork_handler_list_remove_last (&fork_handlers);
104 }
ad3371fb 105
27761a10
AZ
106 lll_unlock (atfork_lock, LLL_PRIVATE);
107}
ad3371fb 108
27761a10 109void
669ff911 110__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
dfdd294a 111{
27761a10 112 struct fork_handler *runp;
dfdd294a 113
27761a10
AZ
114 if (who == atfork_run_prepare)
115 {
669ff911
FW
116 if (do_locking)
117 lll_lock (atfork_lock, LLL_PRIVATE);
27761a10
AZ
118 size_t sl = fork_handler_list_size (&fork_handlers);
119 for (size_t i = sl; i > 0; i--)
120 {
121 runp = fork_handler_list_at (&fork_handlers, i - 1);
122 if (runp->prepare_handler != NULL)
123 runp->prepare_handler ();
124 }
125 }
126 else
127 {
128 size_t sl = fork_handler_list_size (&fork_handlers);
129 for (size_t i = 0; i < sl; i++)
130 {
131 runp = fork_handler_list_at (&fork_handlers, i);
132 if (who == atfork_run_child && runp->child_handler)
133 runp->child_handler ();
134 else if (who == atfork_run_parent && runp->parent_handler)
135 runp->parent_handler ();
136 }
669ff911
FW
137 if (do_locking)
138 lll_unlock (atfork_lock, LLL_PRIVATE);
27761a10
AZ
139 }
140}
dfdd294a 141
dfdd294a 142
27761a10
AZ
143libc_freeres_fn (free_mem)
144{
145 lll_lock (atfork_lock, LLL_PRIVATE);
dfdd294a 146
27761a10 147 fork_handler_list_free (&fork_handlers);
dfdd294a 148
27761a10 149 lll_unlock (atfork_lock, LLL_PRIVATE);
dfdd294a 150}