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