1 | /* Allocate a new thread structure. |
2 | Copyright (C) 2000-2022 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 <assert.h> |
20 | #include <errno.h> |
21 | #include <pthread.h> |
22 | #include <stdlib.h> |
23 | #include <string.h> |
24 | |
25 | #include <pt-internal.h> |
26 | |
27 | /* This braindamage is necessary because the standard says that some |
28 | of the threads functions "shall fail" if "No thread could be found |
29 | corresponding to that specified by the given thread ID." */ |
30 | |
31 | /* The size of the thread ID lookup table. */ |
32 | int __pthread_max_threads; |
33 | |
34 | /* List of thread structures corresponding to free thread IDs. */ |
35 | struct __pthread *__pthread_free_threads; |
36 | pthread_mutex_t __pthread_free_threads_lock; |
37 | |
38 | static inline error_t |
39 | initialize_pthread (struct __pthread *new) |
40 | { |
41 | error_t err; |
42 | |
43 | err = __pthread_init_specific (thread: new); |
44 | if (err) |
45 | return err; |
46 | |
47 | new->nr_refs = 1; |
48 | new->cancel_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; |
49 | new->cancel_hook = NULL; |
50 | new->cancel_hook_arg = NULL; |
51 | new->cancel_state = PTHREAD_CANCEL_ENABLE; |
52 | new->cancel_type = PTHREAD_CANCEL_DEFERRED; |
53 | new->cancel_pending = 0; |
54 | |
55 | new->state_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; |
56 | new->state_cond = (pthread_cond_t) PTHREAD_COND_INITIALIZER; |
57 | new->terminated = FALSE; |
58 | |
59 | memset (&new->res_state, '\0', sizeof (new->res_state)); |
60 | |
61 | new->tcb = NULL; |
62 | |
63 | new->next = 0; |
64 | new->prevp = 0; |
65 | |
66 | return 0; |
67 | } |
68 | |
69 | |
70 | /* Allocate a new thread structure and its pthread thread ID (but not |
71 | a kernel thread). */ |
72 | int |
73 | __pthread_alloc (struct __pthread **pthread) |
74 | { |
75 | error_t err; |
76 | |
77 | struct __pthread *new; |
78 | struct __pthread **threads; |
79 | struct __pthread **old_threads; |
80 | int max_threads; |
81 | int new_max_threads; |
82 | |
83 | __pthread_mutex_lock (&__pthread_free_threads_lock); |
84 | for (new = __pthread_free_threads; new; new = new->next) |
85 | { |
86 | /* There is no need to take NEW->STATE_LOCK: if NEW is on this |
87 | list, then it is protected by __PTHREAD_FREE_THREADS_LOCK |
88 | except in __pthread_dealloc_finish where after it is added to the |
89 | list (with the lock held), it drops the lock and then sets |
90 | NEW->STATE and immediately stops using NEW. */ |
91 | if (new->terminated) |
92 | { |
93 | __pthread_dequeue (thread: new); |
94 | break; |
95 | } |
96 | } |
97 | __pthread_mutex_unlock (&__pthread_free_threads_lock); |
98 | |
99 | if (new) |
100 | { |
101 | if (new->tcb) |
102 | { |
103 | /* Drop old values */ |
104 | _dl_deallocate_tls (new->tcb, 1); |
105 | } |
106 | |
107 | err = initialize_pthread (new); |
108 | if (!err) |
109 | *pthread = new; |
110 | return err; |
111 | } |
112 | |
113 | /* Allocate a new thread structure. */ |
114 | new = malloc (size: sizeof (struct __pthread)); |
115 | if (new == NULL) |
116 | return ENOMEM; |
117 | |
118 | err = initialize_pthread (new); |
119 | if (err) |
120 | { |
121 | free (ptr: new); |
122 | return err; |
123 | } |
124 | |
125 | retry: |
126 | __libc_rwlock_wrlock (GL (dl_pthread_threads_lock)); |
127 | |
128 | if (GL (dl_pthread_num_threads) < __pthread_max_threads) |
129 | { |
130 | /* We have a free slot. Use the slot number plus one as the |
131 | thread ID for the new thread. */ |
132 | new->thread = 1 + GL (dl_pthread_num_threads)++; |
133 | GL (dl_pthread_threads)[new->thread - 1] = NULL; |
134 | |
135 | __libc_rwlock_unlock (GL (dl_pthread_threads_lock)); |
136 | |
137 | *pthread = new; |
138 | return 0; |
139 | } |
140 | #ifdef PTHREAD_THREADS_MAX |
141 | else if (GL (dl_pthread_num_threads) >= PTHREAD_THREADS_MAX) |
142 | { |
143 | /* We have reached the limit on the number of threads per process. */ |
144 | __libc_rwlock_unlock (GL (dl_pthread_threads_lock)); |
145 | |
146 | free (new); |
147 | return EAGAIN; |
148 | } |
149 | #endif |
150 | |
151 | /* We are going to enlarge the threads table. Save its current |
152 | size. We're going to release the lock before doing the necessary |
153 | memory allocation, since that's a potentially blocking operation. */ |
154 | max_threads = __pthread_max_threads; |
155 | |
156 | __libc_rwlock_unlock (GL (dl_pthread_threads_lock)); |
157 | |
158 | /* Allocate a new lookup table that's twice as large. */ |
159 | new_max_threads |
160 | = max_threads > 0 ? max_threads * 2 : _POSIX_THREAD_THREADS_MAX; |
161 | threads = malloc (size: new_max_threads * sizeof (struct __pthread *)); |
162 | if (threads == NULL) |
163 | { |
164 | free (ptr: new); |
165 | return ENOMEM; |
166 | } |
167 | |
168 | __libc_rwlock_wrlock (GL (dl_pthread_threads_lock)); |
169 | |
170 | /* Check if nobody else has already enlarged the table. */ |
171 | if (max_threads != __pthread_max_threads) |
172 | { |
173 | /* Yep, they did. */ |
174 | __libc_rwlock_unlock (GL (dl_pthread_threads_lock)); |
175 | |
176 | /* Free the newly allocated table and try again to allocate a slot. */ |
177 | free (ptr: threads); |
178 | goto retry; |
179 | } |
180 | |
181 | /* Copy over the contents of the old table. */ |
182 | memcpy (dest: threads, src: GL (dl_pthread_threads), |
183 | n: __pthread_max_threads * sizeof (struct __pthread *)); |
184 | |
185 | /* Save the location of the old table. We want to deallocate its |
186 | storage after we released the lock. */ |
187 | old_threads = GL (dl_pthread_threads); |
188 | |
189 | /* Replace the table with the new one. */ |
190 | __pthread_max_threads = new_max_threads; |
191 | GL (dl_pthread_threads) = threads; |
192 | |
193 | /* And allocate ourselves one of the newly created slots. */ |
194 | new->thread = 1 + GL (dl_pthread_num_threads)++; |
195 | GL (dl_pthread_threads)[new->thread - 1] = NULL; |
196 | |
197 | __libc_rwlock_unlock (GL (dl_pthread_threads_lock)); |
198 | |
199 | free (ptr: old_threads); |
200 | |
201 | *pthread = new; |
202 | return 0; |
203 | } |
204 | |
205 | void |
206 | attribute_hidden |
207 | __pthread_init_static_tls (struct link_map *map) |
208 | { |
209 | int i; |
210 | |
211 | __libc_rwlock_wrlock (GL (dl_pthread_threads_lock)); |
212 | for (i = 0; i < GL (dl_pthread_num_threads); ++i) |
213 | { |
214 | struct __pthread *t = GL (dl_pthread_threads)[i]; |
215 | |
216 | if (t == NULL) |
217 | continue; |
218 | |
219 | # if TLS_TCB_AT_TP |
220 | void *dest = (char *) t->tcb - map->l_tls_offset; |
221 | # elif TLS_DTV_AT_TP |
222 | void *dest = (char *) t->tcb + map->l_tls_offset + TLS_PRE_TCB_SIZE; |
223 | # else |
224 | # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" |
225 | # endif |
226 | |
227 | /* Initialize the memory. */ |
228 | memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size), |
229 | c: '\0', n: map->l_tls_blocksize - map->l_tls_initimage_size); |
230 | } |
231 | __libc_rwlock_unlock (GL (dl_pthread_threads_lock)); |
232 | } |
233 | |