]>
Commit | Line | Data |
---|---|---|
ec68790f | 1 | /* |
5ffab04a | 2 | * Copyright (c) 2013, 2014, 2015, 2016 Nicira, Inc. |
ec68790f BP |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #include "ovs-thread.h" | |
19 | #include <errno.h> | |
728a8b14 | 20 | #include <poll.h> |
1481a755 AA |
21 | #ifndef _WIN32 |
22 | #include <signal.h> | |
23 | #endif | |
728a8b14 BP |
24 | #include <stdlib.h> |
25 | #include <unistd.h> | |
ec68790f | 26 | #include "compiler.h" |
d2843eba | 27 | #include "fatal-signal.h" |
ed27e010 | 28 | #include "hash.h" |
b19bab5b | 29 | #include "openvswitch/list.h" |
0f2ea848 | 30 | #include "ovs-rcu.h" |
fd016ae3 | 31 | #include "openvswitch/poll-loop.h" |
d8043da7 | 32 | #include "seq.h" |
728a8b14 | 33 | #include "socket-util.h" |
ec68790f BP |
34 | #include "util.h" |
35 | ||
36 | #ifdef __CHECKER__ | |
37 | /* Omit the definitions in this file because they are somewhat difficult to | |
38 | * write without prompting "sparse" complaints, without ugliness or | |
39 | * cut-and-paste. Since "sparse" is just a checker, not a compiler, it | |
40 | * doesn't matter that we don't define them. */ | |
41 | #else | |
e6211adc | 42 | #include "openvswitch/vlog.h" |
728a8b14 BP |
43 | |
44 | VLOG_DEFINE_THIS_MODULE(ovs_thread); | |
45 | ||
46 | /* If there is a reason that we cannot fork anymore (unless the fork will be | |
47 | * immediately followed by an exec), then this points to a string that | |
48 | * explains why. */ | |
49 | static const char *must_not_fork; | |
50 | ||
51 | /* True if we created any threads beyond the main initial thread. */ | |
52 | static bool multithreaded; | |
53 | ||
97be1538 EJ |
54 | #define LOCK_FUNCTION(TYPE, FUN) \ |
55 | void \ | |
56 | ovs_##TYPE##_##FUN##_at(const struct ovs_##TYPE *l_, \ | |
57 | const char *where) \ | |
da203561 | 58 | OVS_NO_THREAD_SAFETY_ANALYSIS \ |
97be1538 EJ |
59 | { \ |
60 | struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \ | |
05bf6d3c BP |
61 | int error; \ |
62 | \ | |
63 | /* Verify that 'l' was initialized. */ \ | |
6d765f17 BP |
64 | if (OVS_UNLIKELY(!l->where)) { \ |
65 | ovs_abort(0, "%s: %s() passed uninitialized ovs_"#TYPE, \ | |
66 | where, __func__); \ | |
67 | } \ | |
05bf6d3c BP |
68 | \ |
69 | error = pthread_##TYPE##_##FUN(&l->lock); \ | |
97be1538 | 70 | if (OVS_UNLIKELY(error)) { \ |
6d765f17 | 71 | ovs_abort(error, "%s: pthread_%s_%s failed", where, #TYPE, #FUN); \ |
97be1538 EJ |
72 | } \ |
73 | l->where = where; \ | |
05bf6d3c | 74 | } |
97be1538 EJ |
75 | LOCK_FUNCTION(mutex, lock); |
76 | LOCK_FUNCTION(rwlock, rdlock); | |
77 | LOCK_FUNCTION(rwlock, wrlock); | |
884ca8ac WT |
78 | #ifdef HAVE_PTHREAD_SPIN_LOCK |
79 | LOCK_FUNCTION(spin, lock); | |
80 | #endif | |
97be1538 EJ |
81 | |
82 | #define TRY_LOCK_FUNCTION(TYPE, FUN) \ | |
83 | int \ | |
84 | ovs_##TYPE##_##FUN##_at(const struct ovs_##TYPE *l_, \ | |
85 | const char *where) \ | |
da203561 | 86 | OVS_NO_THREAD_SAFETY_ANALYSIS \ |
97be1538 EJ |
87 | { \ |
88 | struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \ | |
05bf6d3c BP |
89 | int error; \ |
90 | \ | |
91 | /* Verify that 'l' was initialized. */ \ | |
6d765f17 BP |
92 | if (OVS_UNLIKELY(!l->where)) { \ |
93 | ovs_abort(0, "%s: %s() passed uninitialized ovs_"#TYPE, \ | |
94 | where, __func__); \ | |
95 | } \ | |
05bf6d3c BP |
96 | \ |
97 | error = pthread_##TYPE##_##FUN(&l->lock); \ | |
97be1538 | 98 | if (OVS_UNLIKELY(error) && error != EBUSY) { \ |
6d765f17 | 99 | ovs_abort(error, "%s: pthread_%s_%s failed", where, #TYPE, #FUN); \ |
97be1538 EJ |
100 | } \ |
101 | if (!error) { \ | |
102 | l->where = where; \ | |
103 | } \ | |
104 | return error; \ | |
105 | } | |
106 | TRY_LOCK_FUNCTION(mutex, trylock); | |
107 | TRY_LOCK_FUNCTION(rwlock, tryrdlock); | |
108 | TRY_LOCK_FUNCTION(rwlock, trywrlock); | |
884ca8ac WT |
109 | #ifdef HAVE_PTHREAD_SPIN_LOCK |
110 | TRY_LOCK_FUNCTION(spin, trylock); | |
111 | #endif | |
97be1538 | 112 | |
05bf6d3c | 113 | #define UNLOCK_FUNCTION(TYPE, FUN, WHERE) \ |
97be1538 EJ |
114 | void \ |
115 | ovs_##TYPE##_##FUN(const struct ovs_##TYPE *l_) \ | |
da203561 | 116 | OVS_NO_THREAD_SAFETY_ANALYSIS \ |
97be1538 EJ |
117 | { \ |
118 | struct ovs_##TYPE *l = CONST_CAST(struct ovs_##TYPE *, l_); \ | |
119 | int error; \ | |
05bf6d3c BP |
120 | \ |
121 | /* Verify that 'l' was initialized. */ \ | |
122 | ovs_assert(l->where); \ | |
123 | \ | |
124 | l->where = WHERE; \ | |
97be1538 EJ |
125 | error = pthread_##TYPE##_##FUN(&l->lock); \ |
126 | if (OVS_UNLIKELY(error)) { \ | |
fa204774 | 127 | ovs_abort(error, "pthread_%s_%s failed", #TYPE, #FUN); \ |
97be1538 EJ |
128 | } \ |
129 | } | |
05bf6d3c BP |
130 | UNLOCK_FUNCTION(mutex, unlock, "<unlocked>"); |
131 | UNLOCK_FUNCTION(mutex, destroy, NULL); | |
132 | UNLOCK_FUNCTION(rwlock, unlock, "<unlocked>"); | |
133 | UNLOCK_FUNCTION(rwlock, destroy, NULL); | |
884ca8ac WT |
134 | #ifdef HAVE_PTHREAD_SPIN_LOCK |
135 | UNLOCK_FUNCTION(spin, unlock, "<unlocked>"); | |
136 | UNLOCK_FUNCTION(spin, destroy, NULL); | |
137 | #endif | |
97be1538 | 138 | |
ec68790f BP |
139 | #define XPTHREAD_FUNC1(FUNCTION, PARAM1) \ |
140 | void \ | |
141 | x##FUNCTION(PARAM1 arg1) \ | |
142 | { \ | |
143 | int error = FUNCTION(arg1); \ | |
144 | if (OVS_UNLIKELY(error)) { \ | |
145 | ovs_abort(error, "%s failed", #FUNCTION); \ | |
146 | } \ | |
147 | } | |
ec68790f BP |
148 | #define XPTHREAD_FUNC2(FUNCTION, PARAM1, PARAM2) \ |
149 | void \ | |
150 | x##FUNCTION(PARAM1 arg1, PARAM2 arg2) \ | |
151 | { \ | |
152 | int error = FUNCTION(arg1, arg2); \ | |
153 | if (OVS_UNLIKELY(error)) { \ | |
154 | ovs_abort(error, "%s failed", #FUNCTION); \ | |
155 | } \ | |
156 | } | |
f0e4e85d JS |
157 | #define XPTHREAD_FUNC3(FUNCTION, PARAM1, PARAM2, PARAM3)\ |
158 | void \ | |
159 | x##FUNCTION(PARAM1 arg1, PARAM2 arg2, PARAM3 arg3) \ | |
160 | { \ | |
161 | int error = FUNCTION(arg1, arg2, arg3); \ | |
162 | if (OVS_UNLIKELY(error)) { \ | |
163 | ovs_abort(error, "%s failed", #FUNCTION); \ | |
164 | } \ | |
165 | } | |
ec68790f | 166 | |
b847adc6 BP |
167 | XPTHREAD_FUNC1(pthread_mutexattr_init, pthread_mutexattr_t *); |
168 | XPTHREAD_FUNC1(pthread_mutexattr_destroy, pthread_mutexattr_t *); | |
169 | XPTHREAD_FUNC2(pthread_mutexattr_settype, pthread_mutexattr_t *, int); | |
170 | XPTHREAD_FUNC2(pthread_mutexattr_gettype, pthread_mutexattr_t *, int *); | |
171 | ||
6b59b543 BP |
172 | XPTHREAD_FUNC1(pthread_rwlockattr_init, pthread_rwlockattr_t *); |
173 | XPTHREAD_FUNC1(pthread_rwlockattr_destroy, pthread_rwlockattr_t *); | |
174 | #ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP | |
175 | XPTHREAD_FUNC2(pthread_rwlockattr_setkind_np, pthread_rwlockattr_t *, int); | |
176 | #endif | |
177 | ||
ec68790f | 178 | XPTHREAD_FUNC2(pthread_cond_init, pthread_cond_t *, pthread_condattr_t *); |
a8e736a8 | 179 | XPTHREAD_FUNC1(pthread_cond_destroy, pthread_cond_t *); |
ec68790f BP |
180 | XPTHREAD_FUNC1(pthread_cond_signal, pthread_cond_t *); |
181 | XPTHREAD_FUNC1(pthread_cond_broadcast, pthread_cond_t *); | |
ec68790f | 182 | |
ec2905a8 EJ |
183 | XPTHREAD_FUNC2(pthread_join, pthread_t, void **); |
184 | ||
ec68790f BP |
185 | typedef void destructor_func(void *); |
186 | XPTHREAD_FUNC2(pthread_key_create, pthread_key_t *, destructor_func *); | |
e9020da2 | 187 | XPTHREAD_FUNC1(pthread_key_delete, pthread_key_t); |
9c4c45ed | 188 | XPTHREAD_FUNC2(pthread_setspecific, pthread_key_t, const void *); |
ec68790f | 189 | |
1481a755 AA |
190 | #ifndef _WIN32 |
191 | XPTHREAD_FUNC3(pthread_sigmask, int, const sigset_t *, sigset_t *); | |
192 | #endif | |
193 | ||
834d6caf BP |
194 | static void |
195 | ovs_mutex_init__(const struct ovs_mutex *l_, int type) | |
97be1538 EJ |
196 | { |
197 | struct ovs_mutex *l = CONST_CAST(struct ovs_mutex *, l_); | |
198 | pthread_mutexattr_t attr; | |
199 | int error; | |
200 | ||
05bf6d3c | 201 | l->where = "<unlocked>"; |
97be1538 EJ |
202 | xpthread_mutexattr_init(&attr); |
203 | xpthread_mutexattr_settype(&attr, type); | |
204 | error = pthread_mutex_init(&l->lock, &attr); | |
205 | if (OVS_UNLIKELY(error)) { | |
206 | ovs_abort(error, "pthread_mutex_init failed"); | |
207 | } | |
208 | xpthread_mutexattr_destroy(&attr); | |
209 | } | |
210 | ||
834d6caf BP |
211 | /* Initializes 'mutex' as a normal (non-recursive) mutex. */ |
212 | void | |
213 | ovs_mutex_init(const struct ovs_mutex *mutex) | |
214 | { | |
215 | ovs_mutex_init__(mutex, PTHREAD_MUTEX_ERRORCHECK); | |
216 | } | |
217 | ||
218 | /* Initializes 'mutex' as a recursive mutex. */ | |
219 | void | |
220 | ovs_mutex_init_recursive(const struct ovs_mutex *mutex) | |
221 | { | |
222 | ovs_mutex_init__(mutex, PTHREAD_MUTEX_RECURSIVE); | |
223 | } | |
224 | ||
ea6f3f9a JR |
225 | /* Initializes 'mutex' as a recursive mutex. */ |
226 | void | |
227 | ovs_mutex_init_adaptive(const struct ovs_mutex *mutex) | |
228 | { | |
229 | #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP | |
230 | ovs_mutex_init__(mutex, PTHREAD_MUTEX_ADAPTIVE_NP); | |
231 | #else | |
232 | ovs_mutex_init(mutex); | |
233 | #endif | |
234 | } | |
235 | ||
97be1538 EJ |
236 | void |
237 | ovs_rwlock_init(const struct ovs_rwlock *l_) | |
238 | { | |
239 | struct ovs_rwlock *l = CONST_CAST(struct ovs_rwlock *, l_); | |
240 | int error; | |
241 | ||
05bf6d3c | 242 | l->where = "<unlocked>"; |
6b59b543 | 243 | |
6b59b543 | 244 | #ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP |
1e4eecb4 AS |
245 | pthread_rwlockattr_t attr; |
246 | xpthread_rwlockattr_init(&attr); | |
6b59b543 BP |
247 | xpthread_rwlockattr_setkind_np( |
248 | &attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); | |
1a15f390 | 249 | error = pthread_rwlock_init(&l->lock, &attr); |
1e4eecb4 AS |
250 | xpthread_rwlockattr_destroy(&attr); |
251 | #else | |
252 | /* It is important to avoid passing a rwlockattr in this case because | |
253 | * Windows pthreads 2.9.1 (and earlier) fail and abort if passed one, even | |
254 | * one without any special attributes. */ | |
255 | error = pthread_rwlock_init(&l->lock, NULL); | |
256 | #endif | |
257 | ||
97be1538 EJ |
258 | if (OVS_UNLIKELY(error)) { |
259 | ovs_abort(error, "pthread_rwlock_init failed"); | |
260 | } | |
261 | } | |
262 | ||
5724fca4 DDP |
263 | /* Provides an error-checking wrapper around pthread_cond_wait(). |
264 | * | |
265 | * If the wait can take a significant amount of time, consider bracketing this | |
266 | * call with calls to ovsrcu_quiesce_start() and ovsrcu_quiesce_end(). */ | |
97be1538 EJ |
267 | void |
268 | ovs_mutex_cond_wait(pthread_cond_t *cond, const struct ovs_mutex *mutex_) | |
5f361a2a | 269 | OVS_NO_THREAD_SAFETY_ANALYSIS |
97be1538 EJ |
270 | { |
271 | struct ovs_mutex *mutex = CONST_CAST(struct ovs_mutex *, mutex_); | |
0f2ea848 BP |
272 | int error; |
273 | ||
0f2ea848 | 274 | error = pthread_cond_wait(cond, &mutex->lock); |
0f2ea848 | 275 | |
97be1538 EJ |
276 | if (OVS_UNLIKELY(error)) { |
277 | ovs_abort(error, "pthread_cond_wait failed"); | |
278 | } | |
279 | } | |
f0e4e85d | 280 | |
884ca8ac WT |
281 | #ifdef HAVE_PTHREAD_SPIN_LOCK |
282 | static void | |
283 | ovs_spin_init__(const struct ovs_spin *l_, int pshared) | |
284 | { | |
285 | struct ovs_spin *l = CONST_CAST(struct ovs_spin *, l_); | |
286 | int error; | |
287 | ||
288 | l->where = "<unlocked>"; | |
289 | error = pthread_spin_init(&l->lock, pshared); | |
290 | if (OVS_UNLIKELY(error)) { | |
291 | ovs_abort(error, "pthread_spin_init failed"); | |
292 | } | |
293 | } | |
294 | ||
295 | void | |
296 | ovs_spin_init(const struct ovs_spin *spin) | |
297 | { | |
298 | ovs_spin_init__(spin, PTHREAD_PROCESS_PRIVATE); | |
299 | } | |
300 | #endif | |
301 | ||
d8043da7 AW |
302 | /* Initializes the 'barrier'. 'size' is the number of threads |
303 | * expected to hit the barrier. */ | |
304 | void | |
305 | ovs_barrier_init(struct ovs_barrier *barrier, uint32_t size) | |
f0e4e85d | 306 | { |
d8043da7 | 307 | barrier->size = size; |
6f008865 | 308 | atomic_count_init(&barrier->count, 0); |
d8043da7 AW |
309 | barrier->seq = seq_create(); |
310 | } | |
f0e4e85d | 311 | |
d8043da7 AW |
312 | /* Destroys the 'barrier'. */ |
313 | void | |
314 | ovs_barrier_destroy(struct ovs_barrier *barrier) | |
315 | { | |
316 | seq_destroy(barrier->seq); | |
317 | } | |
318 | ||
319 | /* Makes the calling thread block on the 'barrier' until all | |
ab355e67 JR |
320 | * 'barrier->size' threads hit the barrier. |
321 | * ovs_barrier provides the necessary acquire-release semantics to make | |
322 | * the effects of prior memory accesses of all the participating threads | |
323 | * visible on return and to prevent the following memory accesses to be | |
324 | * reordered before the ovs_barrier_block(). */ | |
d8043da7 AW |
325 | void |
326 | ovs_barrier_block(struct ovs_barrier *barrier) | |
327 | { | |
328 | uint64_t seq = seq_read(barrier->seq); | |
329 | uint32_t orig; | |
595ef8b1 | 330 | |
6f008865 | 331 | orig = atomic_count_inc(&barrier->count); |
d8043da7 | 332 | if (orig + 1 == barrier->size) { |
6f008865 | 333 | atomic_count_set(&barrier->count, 0); |
ab355e67 JR |
334 | /* seq_change() serves as a release barrier against the other threads, |
335 | * so the zeroed count is visible to them as they continue. */ | |
d8043da7 | 336 | seq_change(barrier->seq); |
6f008865 JR |
337 | } else { |
338 | /* To prevent thread from waking up by other event, | |
339 | * keeps waiting for the change of 'barrier->seq'. */ | |
340 | while (seq == seq_read(barrier->seq)) { | |
341 | seq_wait(barrier->seq, seq); | |
342 | poll_block(); | |
343 | } | |
d8043da7 | 344 | } |
f0e4e85d | 345 | } |
6878fada | 346 | \f |
91b8ec6c | 347 | DEFINE_EXTERN_PER_THREAD_DATA(ovsthread_id, OVSTHREAD_ID_UNSET); |
6878fada BP |
348 | |
349 | struct ovsthread_aux { | |
350 | void *(*start)(void *); | |
351 | void *arg; | |
8ba0a522 | 352 | char name[16]; |
6878fada BP |
353 | }; |
354 | ||
91b8ec6c EC |
355 | unsigned int |
356 | ovsthread_id_init(void) | |
357 | { | |
358 | static atomic_count next_id = ATOMIC_COUNT_INIT(0); | |
359 | ||
360 | ovs_assert(*ovsthread_id_get() == OVSTHREAD_ID_UNSET); | |
361 | return *ovsthread_id_get() = atomic_count_inc(&next_id); | |
362 | } | |
363 | ||
6878fada BP |
364 | static void * |
365 | ovsthread_wrapper(void *aux_) | |
366 | { | |
6878fada BP |
367 | struct ovsthread_aux *auxp = aux_; |
368 | struct ovsthread_aux aux; | |
369 | unsigned int id; | |
370 | ||
91b8ec6c | 371 | id = ovsthread_id_init(); |
6878fada BP |
372 | |
373 | aux = *auxp; | |
374 | free(auxp); | |
375 | ||
214694ad BP |
376 | /* The order of the following calls is important, because |
377 | * ovsrcu_quiesce_end() saves a copy of the thread name. */ | |
40e7cf56 BP |
378 | char *subprogram_name = xasprintf("%s%u", aux.name, id); |
379 | set_subprogram_name(subprogram_name); | |
380 | free(subprogram_name); | |
0f2ea848 | 381 | ovsrcu_quiesce_end(); |
214694ad | 382 | |
6878fada BP |
383 | return aux.start(aux.arg); |
384 | } | |
97be1538 | 385 | |
8147cec9 AA |
386 | static void |
387 | set_min_stack_size(pthread_attr_t *attr, size_t min_stacksize) | |
388 | { | |
389 | size_t stacksize; | |
390 | int error; | |
391 | ||
392 | error = pthread_attr_getstacksize(attr, &stacksize); | |
393 | if (error) { | |
394 | ovs_abort(error, "pthread_attr_getstacksize failed"); | |
395 | } | |
396 | ||
397 | if (stacksize < min_stacksize) { | |
398 | error = pthread_attr_setstacksize(attr, min_stacksize); | |
399 | if (error) { | |
400 | ovs_abort(error, "pthread_attr_setstacksize failed"); | |
401 | } | |
402 | } | |
403 | } | |
404 | ||
8ba0a522 BP |
405 | /* Starts a thread that calls 'start(arg)'. Sets the thread's name to 'name' |
406 | * (suffixed by its ovsthread_id()). Returns the new thread's pthread_t. */ | |
407 | pthread_t | |
408 | ovs_thread_create(const char *name, void *(*start)(void *), void *arg) | |
ec68790f | 409 | { |
13b6d087 | 410 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
6878fada | 411 | struct ovsthread_aux *aux; |
ec68790f BP |
412 | pthread_t thread; |
413 | int error; | |
414 | ||
728a8b14 | 415 | forbid_forking("multiple threads exist"); |
13b6d087 DDP |
416 | |
417 | if (ovsthread_once_start(&once)) { | |
418 | /* The first call to this function has to happen in the main thread. | |
419 | * Before the process becomes multithreaded we make sure that the | |
420 | * main thread is considered non quiescent. | |
421 | * | |
422 | * For other threads this is done in ovs_thread_wrapper(), but the | |
423 | * main thread has no such wrapper. | |
424 | * | |
425 | * There's no reason to call ovsrcu_quiesce_end() in subsequent | |
426 | * invocations of this function and it might introduce problems | |
427 | * for other threads. */ | |
428 | ovsrcu_quiesce_end(); | |
429 | ovsthread_once_done(&once); | |
430 | } | |
728a8b14 | 431 | |
1b870ac0 | 432 | multithreaded = true; |
6878fada BP |
433 | aux = xmalloc(sizeof *aux); |
434 | aux->start = start; | |
435 | aux->arg = arg; | |
8ba0a522 | 436 | ovs_strlcpy(aux->name, name, sizeof aux->name); |
6878fada | 437 | |
8147cec9 AA |
438 | /* Some small systems use a default stack size as small as 80 kB, but OVS |
439 | * requires approximately 384 kB according to the following analysis: | |
8a7903c6 | 440 | * https://mail.openvswitch.org/pipermail/ovs-dev/2016-January/308592.html |
8147cec9 AA |
441 | * |
442 | * We use 512 kB to give us some margin of error. */ | |
443 | pthread_attr_t attr; | |
444 | pthread_attr_init(&attr); | |
445 | set_min_stack_size(&attr, 512 * 1024); | |
446 | ||
5ffab04a | 447 | error = pthread_create(&thread, &attr, ovsthread_wrapper, aux); |
ec68790f BP |
448 | if (error) { |
449 | ovs_abort(error, "pthread_create failed"); | |
450 | } | |
8147cec9 | 451 | pthread_attr_destroy(&attr); |
8ba0a522 | 452 | return thread; |
ec68790f | 453 | } |
1514b275 BP |
454 | \f |
455 | bool | |
456 | ovsthread_once_start__(struct ovsthread_once *once) | |
457 | { | |
97be1538 | 458 | ovs_mutex_lock(&once->mutex); |
9230662a JR |
459 | /* Mutex synchronizes memory, so we get the current value of 'done'. */ |
460 | if (!once->done) { | |
461 | return true; | |
1514b275 | 462 | } |
97be1538 | 463 | ovs_mutex_unlock(&once->mutex); |
9230662a | 464 | return false; |
1514b275 BP |
465 | } |
466 | ||
97be1538 | 467 | void |
1514b275 BP |
468 | ovsthread_once_done(struct ovsthread_once *once) |
469 | { | |
9230662a JR |
470 | /* We need release semantics here, so that the following store may not |
471 | * be moved ahead of any of the preceding initialization operations. | |
472 | * A release atomic_thread_fence provides that prior memory accesses | |
473 | * will not be reordered to take place after the following store. */ | |
474 | atomic_thread_fence(memory_order_release); | |
475 | once->done = true; | |
97be1538 | 476 | ovs_mutex_unlock(&once->mutex); |
1514b275 | 477 | } |
728a8b14 | 478 | \f |
0f2ea848 BP |
479 | bool |
480 | single_threaded(void) | |
481 | { | |
482 | return !multithreaded; | |
483 | } | |
484 | ||
728a8b14 | 485 | /* Asserts that the process has not yet created any threads (beyond the initial |
5453ae20 BP |
486 | * thread). |
487 | * | |
488 | * ('where' is used in logging. Commonly one would use | |
489 | * assert_single_threaded() to automatically provide the caller's source file | |
490 | * and line number for 'where'.) */ | |
728a8b14 | 491 | void |
5453ae20 | 492 | assert_single_threaded_at(const char *where) |
728a8b14 BP |
493 | { |
494 | if (multithreaded) { | |
495 | VLOG_FATAL("%s: attempted operation not allowed when multithreaded", | |
496 | where); | |
497 | } | |
498 | } | |
499 | ||
40a9237d | 500 | #ifndef _WIN32 |
728a8b14 BP |
501 | /* Forks the current process (checking that this is allowed). Aborts with |
502 | * VLOG_FATAL if fork() returns an error, and otherwise returns the value | |
5453ae20 BP |
503 | * returned by fork(). |
504 | * | |
505 | * ('where' is used in logging. Commonly one would use xfork() to | |
506 | * automatically provide the caller's source file and line number for | |
507 | * 'where'.) */ | |
728a8b14 | 508 | pid_t |
5453ae20 | 509 | xfork_at(const char *where) |
728a8b14 BP |
510 | { |
511 | pid_t pid; | |
512 | ||
513 | if (must_not_fork) { | |
514 | VLOG_FATAL("%s: attempted to fork but forking not allowed (%s)", | |
515 | where, must_not_fork); | |
516 | } | |
517 | ||
518 | pid = fork(); | |
519 | if (pid < 0) { | |
97be1538 | 520 | VLOG_FATAL("%s: fork failed (%s)", where, ovs_strerror(errno)); |
728a8b14 BP |
521 | } |
522 | return pid; | |
523 | } | |
40a9237d | 524 | #endif |
728a8b14 BP |
525 | |
526 | /* Notes that the process must not call fork() from now on, for the specified | |
527 | * 'reason'. (The process may still fork() if it execs itself immediately | |
528 | * afterward.) */ | |
529 | void | |
530 | forbid_forking(const char *reason) | |
531 | { | |
532 | ovs_assert(reason != NULL); | |
533 | must_not_fork = reason; | |
534 | } | |
535 | ||
536 | /* Returns true if the process is allowed to fork, false otherwise. */ | |
537 | bool | |
538 | may_fork(void) | |
539 | { | |
540 | return !must_not_fork; | |
541 | } | |
0122f6e6 | 542 | \f |
51852a57 | 543 | /* ovsthread_stats. */ |
ed27e010 | 544 | |
51852a57 BP |
545 | void |
546 | ovsthread_stats_init(struct ovsthread_stats *stats) | |
ed27e010 | 547 | { |
ed27e010 BP |
548 | int i; |
549 | ||
51852a57 BP |
550 | ovs_mutex_init(&stats->mutex); |
551 | for (i = 0; i < ARRAY_SIZE(stats->buckets); i++) { | |
552 | stats->buckets[i] = NULL; | |
ed27e010 | 553 | } |
ed27e010 BP |
554 | } |
555 | ||
556 | void | |
51852a57 | 557 | ovsthread_stats_destroy(struct ovsthread_stats *stats) |
ed27e010 | 558 | { |
51852a57 | 559 | ovs_mutex_destroy(&stats->mutex); |
ed27e010 BP |
560 | } |
561 | ||
51852a57 BP |
562 | void * |
563 | ovsthread_stats_bucket_get(struct ovsthread_stats *stats, | |
564 | void *(*new_bucket)(void)) | |
ed27e010 | 565 | { |
51852a57 BP |
566 | unsigned int idx = ovsthread_id_self() & (ARRAY_SIZE(stats->buckets) - 1); |
567 | void *bucket = stats->buckets[idx]; | |
568 | if (!bucket) { | |
569 | ovs_mutex_lock(&stats->mutex); | |
570 | bucket = stats->buckets[idx]; | |
571 | if (!bucket) { | |
572 | bucket = stats->buckets[idx] = new_bucket(); | |
573 | } | |
574 | ovs_mutex_unlock(&stats->mutex); | |
575 | } | |
576 | return bucket; | |
ed27e010 BP |
577 | } |
578 | ||
51852a57 BP |
579 | size_t |
580 | ovs_thread_stats_next_bucket(const struct ovsthread_stats *stats, size_t i) | |
ed27e010 | 581 | { |
51852a57 BP |
582 | for (; i < ARRAY_SIZE(stats->buckets); i++) { |
583 | if (stats->buckets[i]) { | |
584 | break; | |
585 | } | |
ed27e010 | 586 | } |
51852a57 | 587 | return i; |
ed27e010 | 588 | } |
51852a57 | 589 | |
ed27e010 | 590 | \f |
be15ec48 | 591 | /* Returns the total number of cores available to this process, or 0 if the |
deaa2985 | 592 | * number cannot be determined. */ |
4974b2b8 | 593 | int |
0122f6e6 JS |
594 | count_cpu_cores(void) |
595 | { | |
deaa2985 JS |
596 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
597 | static long int n_cores; | |
598 | ||
599 | if (ovsthread_once_start(&once)) { | |
fdd73c23 | 600 | #ifndef _WIN32 |
be15ec48 DM |
601 | n_cores = sysconf(_SC_NPROCESSORS_ONLN); |
602 | #ifdef __linux__ | |
603 | if (n_cores > 0) { | |
604 | cpu_set_t *set = CPU_ALLOC(n_cores); | |
605 | ||
606 | if (set) { | |
607 | size_t size = CPU_ALLOC_SIZE(n_cores); | |
608 | ||
609 | if (!sched_getaffinity(0, size, set)) { | |
610 | n_cores = CPU_COUNT_S(size, set); | |
611 | } | |
612 | CPU_FREE(set); | |
613 | } | |
deaa2985 | 614 | } |
be15ec48 | 615 | #endif |
fdd73c23 GS |
616 | #else |
617 | SYSTEM_INFO sysinfo; | |
618 | GetSystemInfo(&sysinfo); | |
619 | n_cores = sysinfo.dwNumberOfProcessors; | |
620 | #endif | |
deaa2985 JS |
621 | ovsthread_once_done(&once); |
622 | } | |
0122f6e6 JS |
623 | |
624 | return n_cores > 0 ? n_cores : 0; | |
625 | } | |
2f8932e8 IM |
626 | |
627 | /* Returns 'true' if current thread is PMD thread. */ | |
628 | bool | |
629 | thread_is_pmd(void) | |
630 | { | |
631 | const char *name = get_subprogram_name(); | |
632 | return !strncmp(name, "pmd", 3); | |
633 | } | |
634 | ||
e9020da2 BP |
635 | \f |
636 | /* ovsthread_key. */ | |
637 | ||
638 | #define L1_SIZE 1024 | |
639 | #define L2_SIZE 1024 | |
640 | #define MAX_KEYS (L1_SIZE * L2_SIZE) | |
641 | ||
642 | /* A piece of thread-specific data. */ | |
643 | struct ovsthread_key { | |
ca6ba700 | 644 | struct ovs_list list_node; /* In 'inuse_keys' or 'free_keys'. */ |
e9020da2 BP |
645 | void (*destructor)(void *); /* Called at thread exit. */ |
646 | ||
647 | /* Indexes into the per-thread array in struct ovsthread_key_slots. | |
648 | * This key's data is stored in p1[index / L2_SIZE][index % L2_SIZE]. */ | |
649 | unsigned int index; | |
650 | }; | |
651 | ||
652 | /* Per-thread data structure. */ | |
653 | struct ovsthread_key_slots { | |
ca6ba700 | 654 | struct ovs_list list_node; /* In 'slots_list'. */ |
e9020da2 BP |
655 | void **p1[L1_SIZE]; |
656 | }; | |
657 | ||
658 | /* Contains "struct ovsthread_key_slots *". */ | |
659 | static pthread_key_t tsd_key; | |
660 | ||
661 | /* Guards data structures below. */ | |
662 | static struct ovs_mutex key_mutex = OVS_MUTEX_INITIALIZER; | |
663 | ||
664 | /* 'inuse_keys' holds "struct ovsthread_key"s that have been created and not | |
665 | * yet destroyed. | |
666 | * | |
667 | * 'free_keys' holds "struct ovsthread_key"s that have been deleted and are | |
668 | * ready for reuse. (We keep them around only to be able to easily locate | |
669 | * free indexes.) | |
670 | * | |
671 | * Together, 'inuse_keys' and 'free_keys' hold an ovsthread_key for every index | |
672 | * from 0 to n_keys - 1, inclusive. */ | |
ca6ba700 | 673 | static struct ovs_list inuse_keys OVS_GUARDED_BY(key_mutex) |
55951e15 | 674 | = OVS_LIST_INITIALIZER(&inuse_keys); |
ca6ba700 | 675 | static struct ovs_list free_keys OVS_GUARDED_BY(key_mutex) |
55951e15 | 676 | = OVS_LIST_INITIALIZER(&free_keys); |
e9020da2 BP |
677 | static unsigned int n_keys OVS_GUARDED_BY(key_mutex); |
678 | ||
679 | /* All existing struct ovsthread_key_slots. */ | |
ca6ba700 | 680 | static struct ovs_list slots_list OVS_GUARDED_BY(key_mutex) |
55951e15 | 681 | = OVS_LIST_INITIALIZER(&slots_list); |
e9020da2 BP |
682 | |
683 | static void * | |
684 | clear_slot(struct ovsthread_key_slots *slots, unsigned int index) | |
685 | { | |
686 | void **p2 = slots->p1[index / L2_SIZE]; | |
687 | if (p2) { | |
688 | void **valuep = &p2[index % L2_SIZE]; | |
689 | void *value = *valuep; | |
690 | *valuep = NULL; | |
691 | return value; | |
692 | } else { | |
693 | return NULL; | |
694 | } | |
695 | } | |
696 | ||
697 | static void | |
698 | ovsthread_key_destruct__(void *slots_) | |
699 | { | |
700 | struct ovsthread_key_slots *slots = slots_; | |
701 | struct ovsthread_key *key; | |
702 | unsigned int n; | |
703 | int i; | |
704 | ||
705 | ovs_mutex_lock(&key_mutex); | |
417e7e66 | 706 | ovs_list_remove(&slots->list_node); |
e9020da2 BP |
707 | LIST_FOR_EACH (key, list_node, &inuse_keys) { |
708 | void *value = clear_slot(slots, key->index); | |
709 | if (value && key->destructor) { | |
710 | key->destructor(value); | |
711 | } | |
712 | } | |
713 | n = n_keys; | |
714 | ovs_mutex_unlock(&key_mutex); | |
715 | ||
5657f686 | 716 | for (i = 0; i < DIV_ROUND_UP(n, L2_SIZE); i++) { |
e9020da2 BP |
717 | free(slots->p1[i]); |
718 | } | |
719 | free(slots); | |
720 | } | |
721 | ||
d2843eba GS |
722 | /* Cancels the callback to ovsthread_key_destruct__(). |
723 | * | |
724 | * Cancelling the call to the destructor during the main thread exit | |
725 | * is needed while using pthreads-win32 library in Windows. It has been | |
726 | * observed that in pthreads-win32, a call to the destructor during | |
727 | * main thread exit causes undefined behavior. */ | |
728 | static void | |
729 | ovsthread_cancel_ovsthread_key_destruct__(void *aux OVS_UNUSED) | |
730 | { | |
731 | pthread_setspecific(tsd_key, NULL); | |
732 | } | |
733 | ||
e9020da2 BP |
734 | /* Initializes '*keyp' as a thread-specific data key. The data items are |
735 | * initially null in all threads. | |
736 | * | |
737 | * If a thread exits with non-null data, then 'destructor', if nonnull, will be | |
738 | * called passing the final data value as its argument. 'destructor' must not | |
739 | * call any thread-specific data functions in this API. | |
740 | * | |
741 | * This function is similar to xpthread_key_create(). */ | |
742 | void | |
743 | ovsthread_key_create(ovsthread_key_t *keyp, void (*destructor)(void *)) | |
744 | { | |
745 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; | |
746 | struct ovsthread_key *key; | |
747 | ||
748 | if (ovsthread_once_start(&once)) { | |
749 | xpthread_key_create(&tsd_key, ovsthread_key_destruct__); | |
d2843eba GS |
750 | fatal_signal_add_hook(ovsthread_cancel_ovsthread_key_destruct__, |
751 | NULL, NULL, true); | |
e9020da2 BP |
752 | ovsthread_once_done(&once); |
753 | } | |
754 | ||
755 | ovs_mutex_lock(&key_mutex); | |
417e7e66 | 756 | if (ovs_list_is_empty(&free_keys)) { |
e9020da2 BP |
757 | key = xmalloc(sizeof *key); |
758 | key->index = n_keys++; | |
759 | if (key->index >= MAX_KEYS) { | |
760 | abort(); | |
761 | } | |
762 | } else { | |
417e7e66 | 763 | key = CONTAINER_OF(ovs_list_pop_back(&free_keys), |
e9020da2 BP |
764 | struct ovsthread_key, list_node); |
765 | } | |
417e7e66 | 766 | ovs_list_push_back(&inuse_keys, &key->list_node); |
e9020da2 BP |
767 | key->destructor = destructor; |
768 | ovs_mutex_unlock(&key_mutex); | |
769 | ||
770 | *keyp = key; | |
771 | } | |
772 | ||
773 | /* Frees 'key'. The destructor supplied to ovsthread_key_create(), if any, is | |
774 | * not called. | |
775 | * | |
776 | * This function is similar to xpthread_key_delete(). */ | |
777 | void | |
778 | ovsthread_key_delete(ovsthread_key_t key) | |
779 | { | |
780 | struct ovsthread_key_slots *slots; | |
781 | ||
782 | ovs_mutex_lock(&key_mutex); | |
783 | ||
784 | /* Move 'key' from 'inuse_keys' to 'free_keys'. */ | |
417e7e66 BW |
785 | ovs_list_remove(&key->list_node); |
786 | ovs_list_push_back(&free_keys, &key->list_node); | |
e9020da2 BP |
787 | |
788 | /* Clear this slot in all threads. */ | |
789 | LIST_FOR_EACH (slots, list_node, &slots_list) { | |
790 | clear_slot(slots, key->index); | |
791 | } | |
792 | ||
793 | ovs_mutex_unlock(&key_mutex); | |
794 | } | |
795 | ||
796 | static void ** | |
797 | ovsthread_key_lookup__(const struct ovsthread_key *key) | |
798 | { | |
799 | struct ovsthread_key_slots *slots; | |
800 | void **p2; | |
801 | ||
802 | slots = pthread_getspecific(tsd_key); | |
803 | if (!slots) { | |
804 | slots = xzalloc(sizeof *slots); | |
805 | ||
806 | ovs_mutex_lock(&key_mutex); | |
807 | pthread_setspecific(tsd_key, slots); | |
417e7e66 | 808 | ovs_list_push_back(&slots_list, &slots->list_node); |
e9020da2 BP |
809 | ovs_mutex_unlock(&key_mutex); |
810 | } | |
811 | ||
812 | p2 = slots->p1[key->index / L2_SIZE]; | |
813 | if (!p2) { | |
814 | p2 = xzalloc(L2_SIZE * sizeof *p2); | |
815 | slots->p1[key->index / L2_SIZE] = p2; | |
816 | } | |
817 | ||
818 | return &p2[key->index % L2_SIZE]; | |
819 | } | |
820 | ||
821 | /* Sets the value of thread-specific data item 'key', in the current thread, to | |
822 | * 'value'. | |
823 | * | |
824 | * This function is similar to pthread_setspecific(). */ | |
825 | void | |
826 | ovsthread_setspecific(ovsthread_key_t key, const void *value) | |
827 | { | |
828 | *ovsthread_key_lookup__(key) = CONST_CAST(void *, value); | |
829 | } | |
830 | ||
831 | /* Returns the value of thread-specific data item 'key' in the current thread. | |
832 | * | |
833 | * This function is similar to pthread_getspecific(). */ | |
834 | void * | |
835 | ovsthread_getspecific(ovsthread_key_t key) | |
836 | { | |
837 | return *ovsthread_key_lookup__(key); | |
838 | } | |
ec68790f | 839 | #endif |