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