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