X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fovs-rcu.c;h=7aed6dbe599fa665583341bac6815e7d98eef8a5;hb=0d593ee424de4bb9e3d4dbe7d81c126a4efaa267;hp=269f51b537ccb29cd5ce0ccf51ced2fa05a18861;hpb=882470607bdbaec5a1252f34cf97f4b4ef000d21;p=sliver-openvswitch.git diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c index 269f51b53..7aed6dbe5 100644 --- a/lib/ovs-rcu.c +++ b/lib/ovs-rcu.c @@ -21,6 +21,10 @@ #include "ovs-thread.h" #include "poll-loop.h" #include "seq.h" +#include "timeval.h" +#include "vlog.h" + +VLOG_DEFINE_THIS_MODULE(ovs_rcu); struct ovsrcu_cb { void (*function)(void *aux); @@ -34,11 +38,12 @@ struct ovsrcu_cbset { }; struct ovsrcu_perthread { - struct list list_node; /* In global list. */ + struct list list_node; /* In global list. */ struct ovs_mutex mutex; uint64_t seqno; struct ovsrcu_cbset *cbset; + char name[16]; /* This thread's name. */ }; static struct seq *global_seqno; @@ -66,10 +71,14 @@ ovsrcu_perthread_get(void) perthread = pthread_getspecific(perthread_key); if (!perthread) { + const char *name = get_subprogram_name(); + perthread = xmalloc(sizeof *perthread); ovs_mutex_init(&perthread->mutex); perthread->seqno = seq_read(global_seqno); perthread->cbset = NULL; + ovs_strlcpy(perthread->name, name[0] ? name : "main", + sizeof perthread->name); ovs_mutex_lock(&ovsrcu_threads_mutex); list_push_back(&ovsrcu_threads, &perthread->list_node); @@ -99,7 +108,7 @@ ovsrcu_quiesced(void) } else { static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; if (ovsthread_once_start(&once)) { - xpthread_create(NULL, NULL, ovsrcu_postpone_thread, NULL); + ovs_thread_create("urcu", ovsrcu_postpone_thread, NULL); ovsthread_once_done(&once); } } @@ -134,10 +143,19 @@ ovsrcu_quiesce(void) ovsrcu_quiesced(); } +bool +ovsrcu_is_quiescent(void) +{ + ovsrcu_init(); + return pthread_getspecific(perthread_key) == NULL; +} + static void ovsrcu_synchronize(void) { + unsigned int warning_threshold = 1000; uint64_t target_seqno; + long long int start; if (single_threaded()) { return; @@ -145,15 +163,20 @@ ovsrcu_synchronize(void) target_seqno = seq_read(global_seqno); ovsrcu_quiesce_start(); + start = time_msec(); for (;;) { uint64_t cur_seqno = seq_read(global_seqno); struct ovsrcu_perthread *perthread; + char stalled_thread[16]; + unsigned int elapsed; bool done = true; ovs_mutex_lock(&ovsrcu_threads_mutex); LIST_FOR_EACH (perthread, list_node, &ovsrcu_threads) { if (perthread->seqno <= target_seqno) { + ovs_strlcpy(stalled_thread, perthread->name, + sizeof stalled_thread); done = false; break; } @@ -164,6 +187,14 @@ ovsrcu_synchronize(void) break; } + elapsed = time_msec() - start; + if (elapsed >= warning_threshold) { + VLOG_WARN("blocked %u ms waiting for %s to quiesce", + elapsed, stalled_thread); + warning_threshold *= 2; + } + poll_timer_wait_until(start + warning_threshold); + seq_wait(global_seqno, cur_seqno); poll_block(); } @@ -227,7 +258,6 @@ ovsrcu_call_postponed(void) static void * ovsrcu_postpone_thread(void *arg OVS_UNUSED) { - set_subprogram_name("urcu"); pthread_detach(pthread_self()); for (;;) {