1 | /* pthread_key_create. Hurd version. |
---|---|
2 | Copyright (C) 2002-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
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 |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <pthread.h> |
20 | #include <stdlib.h> |
21 | #include <assert.h> |
22 | |
23 | #include <pt-internal.h> |
24 | #include <pthreadP.h> |
25 | |
26 | pthread_mutex_t __pthread_key_lock; |
27 | pthread_once_t __pthread_key_once = PTHREAD_ONCE_INIT; |
28 | |
29 | void (*__pthread_static_key_destructors [PTHREAD_STATIC_KEYS]) (void *arg); |
30 | void (**__pthread_key_destructors) (void *arg) = __pthread_static_key_destructors; |
31 | int __pthread_key_size = PTHREAD_STATIC_KEYS; |
32 | int __pthread_key_count; |
33 | int __pthread_key_invalid_count = PTHREAD_STATIC_KEYS; |
34 | |
35 | int |
36 | __pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) |
37 | { |
38 | /* Where to look for the next key slot. */ |
39 | static int index; |
40 | |
41 | __pthread_key_lock_ready (); |
42 | |
43 | __pthread_mutex_lock (&__pthread_key_lock); |
44 | |
45 | do_search: |
46 | /* Use the search hint and try to find a free slot. */ |
47 | for (; index < __pthread_key_count |
48 | && __pthread_key_destructors[index] != PTHREAD_KEY_INVALID; index++) |
49 | ; |
50 | |
51 | /* See if we actually found a free element. */ |
52 | if (index < __pthread_key_count) |
53 | { |
54 | assert (__pthread_key_destructors[index] == PTHREAD_KEY_INVALID); |
55 | assert (__pthread_key_invalid_count > 0); |
56 | |
57 | __pthread_key_invalid_count--; |
58 | __pthread_key_destructors[index] = destructor; |
59 | *key = index++; |
60 | |
61 | __pthread_mutex_unlock (&__pthread_key_lock); |
62 | return 0; |
63 | } |
64 | |
65 | assert (index == __pthread_key_count); |
66 | |
67 | /* No space at the end. */ |
68 | if (__pthread_key_size == __pthread_key_count) |
69 | { |
70 | /* See if it is worth looking for a free element. */ |
71 | if (__pthread_key_invalid_count > 4 |
72 | && __pthread_key_invalid_count > __pthread_key_size / 8) |
73 | { |
74 | index = 0; |
75 | goto do_search; |
76 | } |
77 | |
78 | |
79 | /* Resize the array. */ |
80 | { |
81 | void *t; |
82 | int newsize; |
83 | |
84 | newsize = __pthread_key_size * 2; |
85 | |
86 | if (__pthread_key_destructors == __pthread_static_key_destructors) |
87 | { |
88 | /* We were still using the static array. Switch to dynamic. */ |
89 | t = malloc (size: newsize * sizeof (*__pthread_key_destructors)); |
90 | |
91 | if (t != NULL) |
92 | memcpy (t, __pthread_key_destructors, |
93 | __pthread_key_size * sizeof (*__pthread_key_destructors)); |
94 | } |
95 | else |
96 | t = realloc (ptr: __pthread_key_destructors, |
97 | size: newsize * sizeof (*__pthread_key_destructors)); |
98 | |
99 | if (t == NULL) |
100 | { |
101 | __pthread_mutex_unlock (&__pthread_key_lock); |
102 | return ENOMEM; |
103 | } |
104 | |
105 | __pthread_key_size = newsize; |
106 | __pthread_key_destructors = t; |
107 | } |
108 | } |
109 | |
110 | __pthread_key_destructors[index] = destructor; |
111 | *key = index; |
112 | |
113 | index++; |
114 | __pthread_key_count++; |
115 | |
116 | __pthread_mutex_unlock (&__pthread_key_lock); |
117 | return 0; |
118 | } |
119 | weak_alias (__pthread_key_create, pthread_key_create) |
120 | hidden_def (__pthread_key_create) |
121 |