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