]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/seq.c
lldp: fix a buffer overflow when handling management address TLV
[mirror_ovs.git] / lib / seq.c
index 36e506570fe1270c66d0a588baa724a1b42a1934..6581cb06baa164123ffc15ba82842f14a6f9a327 100644 (file)
--- a/lib/seq.c
+++ b/lib/seq.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Nicira, Inc.
+ * Copyright (c) 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <stdbool.h>
 
+#include "coverage.h"
 #include "hash.h"
-#include "hmap.h"
+#include "openvswitch/hmap.h"
 #include "latch.h"
-#include "list.h"
+#include "openvswitch/list.h"
 #include "ovs-thread.h"
-#include "poll-loop.h"
+#include "openvswitch/poll-loop.h"
+
+COVERAGE_DEFINE(seq_change);
 
 /* A sequence number object. */
 struct seq {
@@ -35,24 +38,24 @@ struct seq {
 
 /* A thread waiting on a particular seq. */
 struct seq_waiter {
-    struct seq *seq OVS_GUARDED;            /* Seq being waited for. */
     struct hmap_node hmap_node OVS_GUARDED; /* In 'seq->waiters'. */
+    struct seq *seq OVS_GUARDED;            /* Seq being waited for. */
     unsigned int ovsthread_id OVS_GUARDED;  /* Key in 'waiters' hmap. */
 
-    struct seq_thread *thread OVS_GUARDED; /* Thread preparing to wait. */
-    struct list list_node OVS_GUARDED;     /* In 'thread->waiters'. */
+    struct seq_thread *thread OVS_GUARDED;  /* Thread preparing to wait. */
+    struct ovs_list list_node OVS_GUARDED;  /* In 'thread->waiters'. */
 
     uint64_t value OVS_GUARDED; /* seq->value we're waiting to change. */
 };
 
 /* A thread that might be waiting on one or more seqs. */
 struct seq_thread {
-    struct list waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
+    struct ovs_list waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
     struct latch latch OVS_GUARDED;  /* Wakeup latch for this thread. */
     bool waiting OVS_GUARDED;        /* True if latch_wait() already called. */
 };
 
-static struct ovs_mutex seq_mutex = OVS_ADAPTIVE_MUTEX_INITIALIZER;
+static struct ovs_mutex seq_mutex = OVS_MUTEX_INITIALIZER;
 
 static uint64_t seq_next OVS_GUARDED_BY(seq_mutex) = 1;
 
@@ -74,6 +77,9 @@ seq_create(void)
     seq_init();
 
     seq = xmalloc(sizeof *seq);
+
+    COVERAGE_INC(seq_change);
+
     ovs_mutex_lock(&seq_mutex);
     seq->value = seq_next++;
     hmap_init(&seq->waiters);
@@ -94,6 +100,38 @@ seq_destroy(struct seq *seq)
     ovs_mutex_unlock(&seq_mutex);
 }
 
+int
+seq_try_lock(void)
+{
+    return ovs_mutex_trylock(&seq_mutex);
+}
+
+void
+seq_lock(void)
+    OVS_ACQUIRES(seq_mutex)
+{
+    ovs_mutex_lock(&seq_mutex);
+}
+
+void
+seq_unlock(void)
+    OVS_RELEASES(seq_mutex)
+{
+    ovs_mutex_unlock(&seq_mutex);
+}
+
+/* Increments 'seq''s sequence number, waking up any threads that are waiting
+ * on 'seq'. */
+void
+seq_change_protected(struct seq *seq)
+    OVS_REQUIRES(seq_mutex)
+{
+    COVERAGE_INC(seq_change);
+
+    seq->value = seq_next++;
+    seq_wake_waiters(seq);
+}
+
 /* Increments 'seq''s sequence number, waking up any threads that are waiting
  * on 'seq'. */
 void
@@ -101,11 +139,22 @@ seq_change(struct seq *seq)
     OVS_EXCLUDED(seq_mutex)
 {
     ovs_mutex_lock(&seq_mutex);
-    seq->value = seq_next++;
-    seq_wake_waiters(seq);
+    seq_change_protected(seq);
     ovs_mutex_unlock(&seq_mutex);
 }
 
+/* Returns 'seq''s current sequence number (which could change immediately).
+ *
+ * seq_read() and seq_wait() can be used together to yield a race-free wakeup
+ * when an object changes, even without an ability to lock the object.  See
+ * Usage in seq.h for details. */
+uint64_t
+seq_read_protected(const struct seq *seq)
+    OVS_REQUIRES(seq_mutex)
+{
+    return seq->value;
+}
+
 /* Returns 'seq''s current sequence number (which could change immediately).
  *
  * seq_read() and seq_wait() can be used together to yield a race-free wakeup
@@ -118,14 +167,14 @@ seq_read(const struct seq *seq)
     uint64_t value;
 
     ovs_mutex_lock(&seq_mutex);
-    value = seq->value;
+    value = seq_read_protected(seq);
     ovs_mutex_unlock(&seq_mutex);
 
     return value;
 }
 
 static void
-seq_wait__(struct seq *seq, uint64_t value)
+seq_wait__(struct seq *seq, uint64_t value, const char *where)
     OVS_REQUIRES(seq_mutex)
 {
     unsigned int id = ovsthread_id_self();
@@ -137,7 +186,7 @@ seq_wait__(struct seq *seq, uint64_t value)
             if (waiter->value != value) {
                 /* The current value is different from the value we've already
                  * waited for, */
-                poll_immediate_wake();
+                poll_immediate_wake_at(where);
             } else {
                 /* Already waiting on 'value', nothing more to do. */
             }
@@ -148,12 +197,13 @@ seq_wait__(struct seq *seq, uint64_t value)
     waiter = xmalloc(sizeof *waiter);
     waiter->seq = seq;
     hmap_insert(&seq->waiters, &waiter->hmap_node, hash);
+    waiter->ovsthread_id = id;
     waiter->value = value;
     waiter->thread = seq_thread_get();
-    list_push_back(&waiter->thread->waiters, &waiter->list_node);
+    ovs_list_push_back(&waiter->thread->waiters, &waiter->list_node);
 
     if (!waiter->thread->waiting) {
-        latch_wait(&waiter->thread->latch);
+        latch_wait_at(&waiter->thread->latch, where);
         waiter->thread->waiting = true;
     }
 }
@@ -164,18 +214,22 @@ seq_wait__(struct seq *seq, uint64_t value)
  *
  * seq_read() and seq_wait() can be used together to yield a race-free wakeup
  * when an object changes, even without an ability to lock the object.  See
- * Usage in seq.h for details. */
+ * Usage in seq.h for details.
+ *
+ * ('where' is used in debug logging.  Commonly one would use seq_wait() to
+ * automatically provide the caller's source file and line number for
+ * 'where'.) */
 void
-seq_wait(const struct seq *seq_, uint64_t value)
+seq_wait_at(const struct seq *seq_, uint64_t value, const char *where)
     OVS_EXCLUDED(seq_mutex)
 {
     struct seq *seq = CONST_CAST(struct seq *, seq_);
 
     ovs_mutex_lock(&seq_mutex);
     if (value == seq->value) {
-        seq_wait__(seq, value);
+        seq_wait__(seq, value, where);
     } else {
-        poll_immediate_wake();
+        poll_immediate_wake_at(where);
     }
     ovs_mutex_unlock(&seq_mutex);
 }
@@ -217,7 +271,7 @@ seq_thread_get(void)
     struct seq_thread *thread = pthread_getspecific(seq_thread_key);
     if (!thread) {
         thread = xmalloc(sizeof *thread);
-        list_init(&thread->waiters);
+        ovs_list_init(&thread->waiters);
         latch_init(&thread->latch);
         thread->waiting = false;
 
@@ -257,7 +311,7 @@ seq_waiter_destroy(struct seq_waiter *waiter)
     OVS_REQUIRES(seq_mutex)
 {
     hmap_remove(&waiter->seq->waiters, &waiter->hmap_node);
-    list_remove(&waiter->list_node);
+    ovs_list_remove(&waiter->list_node);
     free(waiter);
 }