ovs-thread: New function ovsthread_id_self().
authorBen Pfaff <blp@nicira.com>
Tue, 6 Aug 2013 21:57:19 +0000 (14:57 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 8 Aug 2013 20:18:10 +0000 (13:18 -0700)
I foresee a need for possibly large numbers of instances of "struct
seq" (which is introduced in an upcoming patch).  Each struct seq
needs some per-thread data.  POSIX has pthread_key_t for this, but
the number of keys can be fairly limited, to as few as 128.  It is
reasonable to work around this by using a hash table indexed on the
current thread.  That only works if one can get a thread identifier
that is hashable (pthread_t is not).  This patch introduces a
hashable thread identifier.

Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/ovs-thread.c
lib/ovs-thread.h

index d0ec9ec..055d66a 100644 (file)
@@ -169,18 +169,49 @@ ovs_mutex_cond_wait(pthread_cond_t *cond, const struct ovs_mutex *mutex_)
         ovs_abort(error, "pthread_cond_wait failed");
     }
 }
+\f
+DEFINE_EXTERN_PER_THREAD_DATA(ovsthread_id, 0);
+
+struct ovsthread_aux {
+    void *(*start)(void *);
+    void *arg;
+};
+
+static void *
+ovsthread_wrapper(void *aux_)
+{
+    static atomic_uint next_id = ATOMIC_VAR_INIT(1);
+
+    struct ovsthread_aux *auxp = aux_;
+    struct ovsthread_aux aux;
+    unsigned int id;
+
+    atomic_add(&next_id, 1, &id);
+    *ovsthread_id_get() = id;
+
+    aux = *auxp;
+    free(auxp);
+
+    return aux.start(aux.arg);
+}
 
 void
 xpthread_create(pthread_t *threadp, pthread_attr_t *attr,
                 void *(*start)(void *), void *arg)
 {
+    struct ovsthread_aux *aux;
     pthread_t thread;
     int error;
 
     forbid_forking("multiple threads exist");
     multithreaded = true;
 
-    error = pthread_create(threadp ? threadp : &thread, attr, start, arg);
+    aux = xmalloc(sizeof *aux);
+    aux->start = start;
+    aux->arg = arg;
+
+    error = pthread_create(threadp ? threadp : &thread, attr,
+                           ovsthread_wrapper, aux);
     if (error) {
         ovs_abort(error, "pthread_create failed");
     }
index abe479a..e644832 100644 (file)
@@ -501,6 +501,23 @@ ovsthread_once_start(struct ovsthread_once *once)
     ((ONCE)->done ? false : ({ OVS_MACRO_LOCK((&ONCE->mutex)); true; }))
 #endif
 \f
+/* Thread ID.
+ *
+ * pthread_t isn't so nice for some purposes.  Its size and representation are
+ * implementation dependent, which means that there is no way to hash it.
+ * This thread ID avoids the problem.
+ */
+
+DECLARE_EXTERN_PER_THREAD_DATA(unsigned int, ovsthread_id);
+
+/* Returns a per-thread identifier unique within the lifetime of the
+ * process. */
+static inline unsigned int
+ovsthread_id_self(void)
+{
+    return *ovsthread_id_get();
+}
+\f
 void assert_single_threaded_at(const char *where);
 #define assert_single_threaded() assert_single_threaded_at(SOURCE_LOCATOR)