@@ -85,5 +85,209 @@ void xpthread_cond_wait(pthread_cond_t *, pthread_mutex_t *mutex)
8585void xpthread_key_create (pthread_key_t * , void (* destructor )(void * ));
8686
8787void xpthread_create (pthread_t * , pthread_attr_t * , void * (* )(void * ), void * );
88+
89+ /* Per-thread data.
90+ *
91+ * Multiple forms of per-thread data exist, each with its own pluses and
92+ * minuses:
93+ *
94+ * - POSIX per-thread data via pthread_key_t is portable to any pthreads
95+ * implementation, and allows a destructor function to be defined. It
96+ * only (directly) supports per-thread pointers, which are always
97+ * initialized to NULL. It requires once-only allocation of a
98+ * pthread_key_t value. It is relatively slow.
99+ *
100+ * - The thread_local feature newly defined in C11 <threads.h> works with
101+ * any data type and initializer, and it is fast. thread_local does not
102+ * require once-only initialization like pthread_key_t. C11 does not
103+ * define what happens if one attempts to access a thread_local object
104+ * from a thread other than the one to which that object belongs. There
105+ * is no provision to call a user-specified destructor when a thread
106+ * ends.
107+ *
108+ * - The __thread keyword is a GCC extension similar to thread_local but
109+ * with a longer history. __thread is not portable to every GCC version
110+ * or environment. __thread does not restrict the use of a thread-local
111+ * object outside its own thread.
112+ *
113+ * Here's a handy summary:
114+ *
115+ * pthread_key_t thread_local __thread
116+ * ------------- ------------ -------------
117+ * portability high low medium
118+ * speed low high high
119+ * supports destructors? yes no no
120+ * needs key allocation? yes no no
121+ * arbitrary initializer? no yes yes
122+ * cross-thread access? yes no yes
123+ */
124+
125+ /* DEFINE_PER_THREAD_DATA(TYPE, NAME, INITIALIZER).
126+ *
127+ * One should prefer to use POSIX per-thread data, via pthread_key_t, when its
128+ * performance is acceptable, because of its portability (see the table above).
129+ * This macro is an alternatives that takes advantage of thread_local (and
130+ * __thread), for its performance, when it is available, and falls back to
131+ * POSIX per-thread data otherwise.
132+ *
133+ * Defines per-thread variable NAME with the given TYPE, initialized to
134+ * INITIALIZER (which must be valid as an initializer for a variable with
135+ * static lifetime).
136+ *
137+ * The public interface to the variable is:
138+ *
139+ * TYPE *NAME_get(void)
140+ * TYPE *NAME_get_unsafe(void)
141+ *
142+ * Returns the address of this thread's instance of NAME.
143+ *
144+ * Use NAME_get() in a context where this might be the first use of the
145+ * per-thread variable in the program. Use NAME_get_unsafe(), which
146+ * avoids a conditional test and is thus slightly faster, in a context
147+ * where one knows that NAME_get() has already been called previously.
148+ *
149+ * There is no "NAME_set()" (or "NAME_set_unsafe()") function. To set the
150+ * value of the per-thread variable, dereference the pointer returned by
151+ * TYPE_get() or TYPE_get_unsafe(), e.g. *TYPE_get() = 0.
152+ */
153+ #if HAVE_THREAD_LOCAL || HAVE___THREAD
154+
155+ #if HAVE_THREAD_LOCAL
156+ #include <threads.h>
157+ #elif HAVE___THREAD
158+ #define thread_local __thread
159+ #else
160+ #error
161+ #endif
162+
163+ #define DEFINE_PER_THREAD_DATA (TYPE , NAME , ...) \
164+ typedef TYPE NAME##_type; \
165+ static thread_local NAME##_type NAME##_var = __VA_ARGS__; \
166+ \
167+ static NAME##_type * \
168+ NAME##_get_unsafe(void) \
169+ { \
170+ return &NAME##_var; \
171+ } \
172+ \
173+ static NAME##_type * \
174+ NAME##_get(void) \
175+ { \
176+ return NAME##_get_unsafe(); \
177+ }
178+ #else /* no C implementation support for thread-local storage */
179+ #define DEFINE_PER_THREAD_DATA (TYPE , NAME , ...) \
180+ typedef TYPE NAME##_type; \
181+ static pthread_key_t NAME##_key; \
182+ \
183+ static NAME##_type * \
184+ NAME##_get_unsafe(void) \
185+ { \
186+ return pthread_getspecific(NAME##_key); \
187+ } \
188+ \
189+ static void \
190+ NAME##_once_init(void) \
191+ { \
192+ if (pthread_key_create(&NAME##_key, free)) { \
193+ abort(); \
194+ } \
195+ } \
196+ \
197+ static NAME##_type * \
198+ NAME##_get(void) \
199+ { \
200+ static pthread_once_t once = PTHREAD_ONCE_INIT; \
201+ NAME##_type *value; \
202+ \
203+ pthread_once(&once, NAME##_once_init); \
204+ value = NAME##_get_unsafe(); \
205+ if (!value) { \
206+ static const NAME##_type initial_value = __VA_ARGS__; \
207+ \
208+ value = xmalloc(sizeof *value); \
209+ *value = initial_value; \
210+ pthread_setspecific(NAME##_key, value); \
211+ } \
212+ return value; \
213+ }
214+ #endif
215+
216+ /* DEFINE_PER_THREAD_MALLOCED_DATA(TYPE, NAME).
217+ *
218+ * This is a simple wrapper around POSIX per-thread data primitives. It
219+ * defines per-thread variable NAME with the given TYPE, which must be a
220+ * pointer type. In each thread, the per-thread variable is initialized to
221+ * NULL. When a thread terminates, the variable is freed with free().
222+ *
223+ * The public interface to the variable is:
224+ *
225+ * TYPE NAME_get(void)
226+ * TYPE NAME_get_unsafe(void)
227+ *
228+ * Returns the value of per-thread variable NAME in this thread.
229+ *
230+ * Use NAME_get() in a context where this might be the first use of the
231+ * per-thread variable in the program. Use NAME_get_unsafe(), which
232+ * avoids a conditional test and is thus slightly faster, in a context
233+ * where one knows that NAME_get() has already been called previously.
234+ *
235+ * TYPE NAME_set(TYPE new_value)
236+ * TYPE NAME_set_unsafe(TYPE new_value)
237+ *
238+ * Sets the value of per-thread variable NAME to 'new_value' in this
239+ * thread, and returns its previous value.
240+ *
241+ * Use NAME_set() in a context where this might be the first use of the
242+ * per-thread variable in the program. Use NAME_set_unsafe(), which
243+ * avoids a conditional test and is thus slightly faster, in a context
244+ * where one knows that NAME_set() has already been called previously.
245+ */
246+ #define DEFINE_PER_THREAD_MALLOCED_DATA (TYPE , NAME ) \
247+ static pthread_key_t NAME##_key; \
248+ \
249+ static void \
250+ NAME##_once_init(void) \
251+ { \
252+ if (pthread_key_create(&NAME##_key, free)) { \
253+ abort(); \
254+ } \
255+ } \
256+ \
257+ static void \
258+ NAME##_init(void) \
259+ { \
260+ static pthread_once_t once = PTHREAD_ONCE_INIT; \
261+ pthread_once(&once, NAME##_once_init); \
262+ } \
263+ \
264+ static TYPE \
265+ NAME##_get_unsafe(void) \
266+ { \
267+ return pthread_getspecific(NAME##_key); \
268+ } \
269+ \
270+ static OVS_UNUSED TYPE \
271+ NAME##_get(void) \
272+ { \
273+ NAME##_init(); \
274+ return NAME##_get_unsafe(); \
275+ } \
276+ \
277+ static TYPE \
278+ NAME##_set_unsafe(TYPE value) \
279+ { \
280+ TYPE old_value = NAME##_get_unsafe(); \
281+ pthread_setspecific(NAME##_key, value); \
282+ return old_value; \
283+ } \
284+ \
285+ static OVS_UNUSED TYPE \
286+ NAME##_set(TYPE value) \
287+ { \
288+ NAME##_init(); \
289+ return NAME##_set_unsafe(value); \
290+ }
291+
88292
89293#endif /* ovs-thread.h */
0 commit comments