[ovs-dev] [thread 02/15] ovs-thread: Add support for globally visible per-thread data.

Ethan Jackson ethan at nicira.com
Thu Aug 8 19:58:21 UTC 2013


From: Ben Pfaff <blp at nicira.com>

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 <blp at nicira.com>
---
 lib/ovs-thread.h |   94 ++++++++++++++++++++++++++++++++++++++++++++----------
 lib/random.c     |    2 +-
 lib/timeval.c    |    2 +-
 lib/util.c       |    4 ++-
 lib/vlog.c       |    2 +-
 5 files changed, 84 insertions(+), 20 deletions(-)

diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h
index 0d54a43..abe479a 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 da29fd0..d6f7d9d 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 05da99e..faf8e7b 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 1751c6f..76c33cd 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 26d0e6c..ac229b4 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.
  *
-- 
1.7.9.5




More information about the dev mailing list