/src/openvswitch/include/openvswitch/thread.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2013, 2014 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 | | #ifndef OPENVSWITCH_THREAD_H |
18 | | #define OPENVSWITCH_THREAD_H 1 |
19 | | |
20 | | #include <pthread.h> |
21 | | #include <stddef.h> |
22 | | #include <stdbool.h> |
23 | | #include <sys/types.h> |
24 | | #include "openvswitch/compiler.h" |
25 | | |
26 | | #ifdef __cplusplus |
27 | | extern "C" { |
28 | | #endif |
29 | | |
30 | | /* Mutex. */ |
31 | | struct OVS_LOCKABLE ovs_mutex { |
32 | | pthread_mutex_t lock; |
33 | | const char *where; /* NULL if and only if uninitialized. */ |
34 | | }; |
35 | | |
36 | | #ifdef HAVE_PTHREAD_SPIN_LOCK |
37 | | struct OVS_LOCKABLE ovs_spin { |
38 | | pthread_spinlock_t lock; |
39 | | const char *where; /* NULL if and only if uninitialized. */ |
40 | | }; |
41 | | #endif |
42 | | |
43 | | /* "struct ovs_mutex" initializer. */ |
44 | | #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP |
45 | 0 | #define OVS_MUTEX_INITIALIZER { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, \ |
46 | 0 | "<unlocked>" } |
47 | | #else |
48 | | #define OVS_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, "<unlocked>" } |
49 | | #endif |
50 | | |
51 | | #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP |
52 | | #define OVS_ADAPTIVE_MUTEX_INITIALIZER \ |
53 | | { PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP, "<unlocked>" } |
54 | | #else |
55 | | #define OVS_ADAPTIVE_MUTEX_INITIALIZER OVS_MUTEX_INITIALIZER |
56 | | #endif |
57 | | |
58 | | /* ovs_mutex functions analogous to pthread_mutex_*() functions. |
59 | | * |
60 | | * Most of these functions abort the process with an error message on any |
61 | | * error. ovs_mutex_trylock() is an exception: it passes through a 0 or EBUSY |
62 | | * return value to the caller and aborts on any other error. */ |
63 | | void ovs_mutex_init(const struct ovs_mutex *); |
64 | | void ovs_mutex_init_recursive(const struct ovs_mutex *); |
65 | | void ovs_mutex_init_adaptive(const struct ovs_mutex *); |
66 | | void ovs_mutex_destroy(const struct ovs_mutex *); |
67 | | void ovs_mutex_unlock(const struct ovs_mutex *mutex) OVS_RELEASES(mutex); |
68 | | void ovs_mutex_lock_at(const struct ovs_mutex *mutex, const char *where) |
69 | | OVS_ACQUIRES(mutex); |
70 | | #define ovs_mutex_lock(mutex) \ |
71 | 186 | ovs_mutex_lock_at(mutex, OVS_SOURCE_LOCATOR) |
72 | | |
73 | | int ovs_mutex_trylock_at(const struct ovs_mutex *mutex, const char *where) |
74 | | OVS_TRY_LOCK(0, mutex); |
75 | | #define ovs_mutex_trylock(mutex) \ |
76 | 0 | ovs_mutex_trylock_at(mutex, OVS_SOURCE_LOCATOR) |
77 | | |
78 | | void ovs_mutex_cond_wait(pthread_cond_t *, const struct ovs_mutex *mutex) |
79 | | OVS_REQUIRES(mutex); |
80 | | |
81 | | #ifdef HAVE_PTHREAD_SPIN_LOCK |
82 | | void ovs_spin_init(const struct ovs_spin *); |
83 | | void ovs_spin_destroy(const struct ovs_spin *); |
84 | | void ovs_spin_unlock(const struct ovs_spin *spin) OVS_RELEASES(spin); |
85 | | void ovs_spin_lock_at(const struct ovs_spin *spin, const char *where) |
86 | | OVS_ACQUIRES(spin); |
87 | | #define ovs_spin_lock(spin) \ |
88 | 0 | ovs_spin_lock_at(spin, OVS_SOURCE_LOCATOR) |
89 | | |
90 | | int ovs_spin_trylock_at(const struct ovs_spin *spin, const char *where) |
91 | | OVS_TRY_LOCK(0, spin); |
92 | | #define ovs_spin_trylock(spin) \ |
93 | | ovs_spin_trylock_at(spin, OVS_SOURCE_LOCATOR) |
94 | | #endif |
95 | | |
96 | | /* Convenient once-only execution. |
97 | | * |
98 | | * |
99 | | * Problem |
100 | | * ======= |
101 | | * |
102 | | * POSIX provides pthread_once_t and pthread_once() as primitives for running a |
103 | | * set of code only once per process execution. They are used like this: |
104 | | * |
105 | | * static void run_once(void) { ...initialization... } |
106 | | * static pthread_once_t once = PTHREAD_ONCE_INIT; |
107 | | * ... |
108 | | * pthread_once(&once, run_once); |
109 | | * |
110 | | * pthread_once() does not allow passing any parameters to the initialization |
111 | | * function, which is often inconvenient, because it means that the function |
112 | | * can only access data declared at file scope. |
113 | | * |
114 | | * |
115 | | * Solution |
116 | | * ======== |
117 | | * |
118 | | * Use ovsthread_once, like this, instead: |
119 | | * |
120 | | * static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
121 | | * |
122 | | * if (ovsthread_once_start(&once)) { |
123 | | * ...initialization... |
124 | | * ovsthread_once_done(&once); |
125 | | * } |
126 | | */ |
127 | | |
128 | | struct ovsthread_once { |
129 | | bool done; /* Non-atomic, false negatives possible. */ |
130 | | struct ovs_mutex mutex; |
131 | | }; |
132 | | |
133 | | #define OVSTHREAD_ONCE_INITIALIZER \ |
134 | 0 | { \ |
135 | 0 | false, \ |
136 | 0 | OVS_MUTEX_INITIALIZER, \ |
137 | 0 | } |
138 | | |
139 | | static inline bool ovsthread_once_start(struct ovsthread_once *once) |
140 | | OVS_TRY_LOCK(true, once->mutex); |
141 | | void ovsthread_once_done(struct ovsthread_once *once) |
142 | | OVS_RELEASES(once->mutex); |
143 | | |
144 | | bool ovsthread_once_start__(struct ovsthread_once *once) |
145 | | OVS_TRY_LOCK(true, once->mutex); |
146 | | |
147 | | /* Returns true if this is the first call to ovsthread_once_start() for |
148 | | * 'once'. In this case, the caller should perform whatever initialization |
149 | | * actions it needs to do, then call ovsthread_once_done() for 'once'. |
150 | | * |
151 | | * Returns false if this is not the first call to ovsthread_once_start() for |
152 | | * 'once'. In this case, the call will not return until after |
153 | | * ovsthread_once_done() has been called. */ |
154 | | static inline bool |
155 | | ovsthread_once_start(struct ovsthread_once *once) |
156 | 0 | { |
157 | | /* We may be reading 'done' at the same time as the first thread |
158 | | * is writing on it, or we can be using a stale copy of it. The |
159 | | * worst that can happen is that we call ovsthread_once_start__() |
160 | | * once when strictly not necessary. */ |
161 | 0 | return OVS_UNLIKELY(!once->done && ovsthread_once_start__(once)); |
162 | 0 | } Unexecuted instantiation: dp-packet.c:ovsthread_once_start Unexecuted instantiation: flow.c:ovsthread_once_start Unexecuted instantiation: netdev.c:ovsthread_once_start Unexecuted instantiation: ofp-match.c:ovsthread_once_start Unexecuted instantiation: ofp-msgs.c:ovsthread_once_start Unexecuted instantiation: ofp-port.c:ovsthread_once_start Unexecuted instantiation: ofp-prop.c:ovsthread_once_start Unexecuted instantiation: ofp-protocol.c:ovsthread_once_start Unexecuted instantiation: ofp-queue.c:ovsthread_once_start Unexecuted instantiation: ofp-table.c:ovsthread_once_start Unexecuted instantiation: ofp-util.c:ovsthread_once_start Unexecuted instantiation: ovs-rcu.c:ovsthread_once_start Unexecuted instantiation: ovs-router.c:ovsthread_once_start Unexecuted instantiation: ovs-thread.c:ovsthread_once_start Unexecuted instantiation: packets.c:ovsthread_once_start Unexecuted instantiation: poll-loop.c:ovsthread_once_start Unexecuted instantiation: random.c:ovsthread_once_start Unexecuted instantiation: seq.c:ovsthread_once_start Unexecuted instantiation: socket-util.c:ovsthread_once_start Unexecuted instantiation: timeval.c:ovsthread_once_start Unexecuted instantiation: tnl-ports.c:ovsthread_once_start Unexecuted instantiation: unixctl.c:ovsthread_once_start Unexecuted instantiation: userspace-tso.c:ovsthread_once_start Unexecuted instantiation: util.c:ovsthread_once_start Unexecuted instantiation: uuid.c:ovsthread_once_start Unexecuted instantiation: vlog.c:ovsthread_once_start Unexecuted instantiation: socket-util-unix.c:ovsthread_once_start Unexecuted instantiation: netdev-linux.c:ovsthread_once_start Unexecuted instantiation: netdev-offload-tc.c:ovsthread_once_start Unexecuted instantiation: netlink-socket.c:ovsthread_once_start Unexecuted instantiation: route-table.c:ovsthread_once_start Unexecuted instantiation: tc.c:ovsthread_once_start Unexecuted instantiation: async-append-aio.c:ovsthread_once_start Unexecuted instantiation: dirs.c:ovsthread_once_start Unexecuted instantiation: backtrace.c:ovsthread_once_start Unexecuted instantiation: ccmap.c:ovsthread_once_start Unexecuted instantiation: cmap.c:ovsthread_once_start Unexecuted instantiation: command-line.c:ovsthread_once_start Unexecuted instantiation: connectivity.c:ovsthread_once_start Unexecuted instantiation: coverage.c:ovsthread_once_start Unexecuted instantiation: dp-packet-gso.c:ovsthread_once_start Unexecuted instantiation: dpif.c:ovsthread_once_start Unexecuted instantiation: entropy.c:ovsthread_once_start Unexecuted instantiation: fatal-signal.c:ovsthread_once_start Unexecuted instantiation: guarded-list.c:ovsthread_once_start Unexecuted instantiation: hmap.c:ovsthread_once_start Unexecuted instantiation: jsonrpc.c:ovsthread_once_start Unexecuted instantiation: meta-flow.c:ovsthread_once_start Unexecuted instantiation: netdev-offload.c:ovsthread_once_start Unexecuted instantiation: netdev-vport.c:ovsthread_once_start Unexecuted instantiation: netlink.c:ovsthread_once_start Unexecuted instantiation: nx-match.c:ovsthread_once_start Unexecuted instantiation: odp-execute.c:ovsthread_once_start Unexecuted instantiation: odp-execute-private.c:ovsthread_once_start Unexecuted instantiation: odp-util.c:ovsthread_once_start Unexecuted instantiation: ofp-actions.c:ovsthread_once_start Unexecuted instantiation: ofp-bundle.c:ovsthread_once_start Unexecuted instantiation: ofp-connection.c:ovsthread_once_start Unexecuted instantiation: ofp-ct.c:ovsthread_once_start Unexecuted instantiation: ofp-errors.c:ovsthread_once_start Unexecuted instantiation: ofp-flow.c:ovsthread_once_start Unexecuted instantiation: ofp-group.c:ovsthread_once_start Unexecuted instantiation: ofp-meter.c:ovsthread_once_start Unexecuted instantiation: ofp-monitor.c:ovsthread_once_start Unexecuted instantiation: ofp-packet.c:ovsthread_once_start Unexecuted instantiation: ovs-replay.c:ovsthread_once_start Unexecuted instantiation: ox-stat.c:ovsthread_once_start Unexecuted instantiation: reconnect.c:ovsthread_once_start Unexecuted instantiation: sha1.c:ovsthread_once_start Unexecuted instantiation: stream.c:ovsthread_once_start Unexecuted instantiation: svec.c:ovsthread_once_start Unexecuted instantiation: tnl-neigh-cache.c:ovsthread_once_start Unexecuted instantiation: netdev-native-tnl.c:ovsthread_once_start Unexecuted instantiation: daemon-unix.c:ovsthread_once_start Unexecuted instantiation: signals.c:ovsthread_once_start Unexecuted instantiation: stream-unix.c:ovsthread_once_start Unexecuted instantiation: dpif-netlink.c:ovsthread_once_start Unexecuted instantiation: dpif-netlink-rtnl.c:ovsthread_once_start Unexecuted instantiation: netlink-conntrack.c:ovsthread_once_start Unexecuted instantiation: netlink-notifier.c:ovsthread_once_start Unexecuted instantiation: stream-ssl.c:ovsthread_once_start Unexecuted instantiation: bundle.c:ovsthread_once_start Unexecuted instantiation: conntrack.c:ovsthread_once_start Unexecuted instantiation: cooperative-multitasking.c:ovsthread_once_start Unexecuted instantiation: ct-dpif.c:ovsthread_once_start Unexecuted instantiation: daemon.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-private-dfc.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-private-dpif.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-private-extract.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-perf.c:ovsthread_once_start Unexecuted instantiation: fat-rwlock.c:ovsthread_once_start Unexecuted instantiation: hindex.c:ovsthread_once_start Unexecuted instantiation: id-fpool.c:ovsthread_once_start Unexecuted instantiation: ipf.c:ovsthread_once_start Unexecuted instantiation: learn.c:ovsthread_once_start Unexecuted instantiation: lockfile.c:ovsthread_once_start Unexecuted instantiation: mpsc-queue.c:ovsthread_once_start Unexecuted instantiation: ovs-numa.c:ovsthread_once_start Unexecuted instantiation: process.c:ovsthread_once_start Unexecuted instantiation: stream-fd.c:ovsthread_once_start Unexecuted instantiation: stream-replay.c:ovsthread_once_start Unexecuted instantiation: stream-tcp.c:ovsthread_once_start Unexecuted instantiation: dpdk-stub.c:ovsthread_once_start Unexecuted instantiation: vswitch-idl.c:ovsthread_once_start Unexecuted instantiation: conntrack-icmp.c:ovsthread_once_start Unexecuted instantiation: conntrack-tcp.c:ovsthread_once_start Unexecuted instantiation: conntrack-tp.c:ovsthread_once_start Unexecuted instantiation: conntrack-other.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-extract-study.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-lookup.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-lookup-autovalidator.c:ovsthread_once_start Unexecuted instantiation: dpif-netdev-lookup-generic.c:ovsthread_once_start Unexecuted instantiation: ovsdb-data.c:ovsthread_once_start Unexecuted instantiation: ovsdb-error.c:ovsthread_once_start Unexecuted instantiation: ovsdb-idl.c:ovsthread_once_start Unexecuted instantiation: ovsdb-types.c:ovsthread_once_start Unexecuted instantiation: ovsdb-cs.c:ovsthread_once_start |
163 | | |
164 | | #ifdef __cplusplus |
165 | | } |
166 | | #endif |
167 | | |
168 | | #endif /* ovs-thread.h */ |