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