From: Ben Pfaff Date: Tue, 6 Aug 2013 21:40:25 +0000 (-0700) Subject: ovs-thread: Add support for globally visible per-thread data. X-Git-Tag: sliver-openvswitch-2.0.90-1~32^2~20 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=2ba4f163d9ea84aa8b8e9d8678371a70af766b5e;p=sliver-openvswitch.git ovs-thread: Add support for globally visible per-thread data. DEFINE_PER_THREAD_DATA always declared its data item as "static", meaning that it was only directly visible within a single translation unit. This commit adds additional forms of per-thread data that allow the data to be accessible from multiple translation units. Signed-off-by: Ben Pfaff --- diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h index 0d54a43fb..abe479ae6 100644 --- a/lib/ovs-thread.h +++ b/lib/ovs-thread.h @@ -193,7 +193,15 @@ void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *); * cross-thread access? yes no yes */ -/* DEFINE_PER_THREAD_DATA(TYPE, NAME, INITIALIZER). +/* For static data, use this macro in a source file: + * + * DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, INITIALIZER). + * + * For global data, "declare" the data in the header and "define" it in + * the source file, with: + * + * DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME). + * DEFINE_EXTERN_PER_THREAD_DATA(NAME, INITIALIZER). * * One should prefer to use POSIX per-thread data, via pthread_key_t, when its * performance is acceptable, because of its portability (see the table above). @@ -231,23 +239,40 @@ void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *); #error #endif -#define DEFINE_PER_THREAD_DATA(TYPE, NAME, ...) \ - typedef TYPE NAME##_type; \ - static thread_local NAME##_type NAME##_var = __VA_ARGS__; \ - \ - static NAME##_type * \ - NAME##_get_unsafe(void) \ - { \ - return &NAME##_var; \ - } \ - \ - static NAME##_type * \ - NAME##_get(void) \ - { \ - return NAME##_get_unsafe(); \ +#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...) \ + typedef TYPE NAME##_type; \ + \ + static NAME##_type * \ + NAME##_get_unsafe(void) \ + { \ + static thread_local NAME##_type var = __VA_ARGS__; \ + return &var; \ + } \ + \ + static NAME##_type * \ + NAME##_get(void) \ + { \ + return NAME##_get_unsafe(); \ } +#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME) \ + typedef TYPE NAME##_type; \ + extern thread_local NAME##_type NAME##_var; \ + \ + static inline NAME##_type * \ + NAME##_get_unsafe(void) \ + { \ + return &NAME##_var; \ + } \ + \ + static inline NAME##_type * \ + NAME##_get(void) \ + { \ + return NAME##_get_unsafe(); \ + } +#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...) \ + thread_local NAME##_type NAME##_var = __VA_ARGS__; #else /* no C implementation support for thread-local storage */ -#define DEFINE_PER_THREAD_DATA(TYPE, NAME, ...) \ +#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...) \ typedef TYPE NAME##_type; \ static pthread_key_t NAME##_key; \ \ @@ -282,6 +307,43 @@ void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *); } \ return value; \ } +#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME) \ + typedef TYPE NAME##_type; \ + static pthread_key_t NAME##_key; \ + \ + static inline NAME##_type * \ + NAME##_get_unsafe(void) \ + { \ + return pthread_getspecific(NAME##_key); \ + } \ + \ + NAME##_type *NAME##_get(void); +#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...) \ + static void \ + NAME##_once_init(void) \ + { \ + if (pthread_key_create(&NAME##_key, free)) { \ + abort(); \ + } \ + } \ + \ + NAME##_type * \ + NAME##_get(void) \ + { \ + static pthread_once_t once = PTHREAD_ONCE_INIT; \ + NAME##_type *value; \ + \ + pthread_once(&once, NAME##_once_init); \ + value = NAME##_get_unsafe(); \ + if (!value) { \ + static const NAME##_type initial_value = __VA_ARGS__; \ + \ + value = xmalloc(sizeof *value); \ + *value = initial_value; \ + xpthread_setspecific(NAME##_key, value); \ + } \ + return value; \ + } #endif /* DEFINE_PER_THREAD_MALLOCED_DATA(TYPE, NAME). diff --git a/lib/random.c b/lib/random.c index da29fd0cf..d6f7d9d62 100644 --- a/lib/random.c +++ b/lib/random.c @@ -39,7 +39,7 @@ * cryptographic-quality randomness. */ /* Current random state. */ -DEFINE_PER_THREAD_DATA(uint32_t, seed, 0); +DEFINE_STATIC_PER_THREAD_DATA(uint32_t, seed, 0); static uint32_t random_next(void); diff --git a/lib/timeval.c b/lib/timeval.c index 05da99e56..faf8e7bc8 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -65,7 +65,7 @@ static long long int deadline = LLONG_MAX; /* Monotonic time, in milliseconds, at which the last call to time_poll() woke * up. */ -DEFINE_PER_THREAD_DATA(long long int, last_wakeup, 0); +DEFINE_STATIC_PER_THREAD_DATA(long long int, last_wakeup, 0); static void set_up_timer(void); static void set_up_signal(int flags); diff --git a/lib/util.c b/lib/util.c index 1751c6f41..76c33cd7c 100644 --- a/lib/util.c +++ b/lib/util.c @@ -46,7 +46,9 @@ DEFINE_PER_THREAD_MALLOCED_DATA(char *, subprogram_name); static char *program_version; /* Buffer used by ovs_strerror(). */ -DEFINE_PER_THREAD_DATA(struct { char s[128]; }, strerror_buffer, { "" }); +DEFINE_STATIC_PER_THREAD_DATA(struct { char s[128]; }, + strerror_buffer, + { "" }); void ovs_assert_failure(const char *where, const char *function, diff --git a/lib/vlog.c b/lib/vlog.c index 26d0e6cd1..ac229b4ee 100644 --- a/lib/vlog.c +++ b/lib/vlog.c @@ -100,7 +100,7 @@ static struct facility facilities[VLF_N_FACILITIES] = { }; /* Sequence number for the message currently being composed. */ -DEFINE_PER_THREAD_DATA(unsigned int, msg_num, 0); +DEFINE_STATIC_PER_THREAD_DATA(unsigned int, msg_num, 0); /* VLF_FILE configuration. *