[Click] NotifierQueue on multi-threaded Click problem.

Joonwoo Park joonwpark81 at gmail.com
Fri Sep 7 05:01:34 EDT 2007


Hi Eddie,

2007/9/7, Eddie Kohler <kohler at cs.ucla.edu>:
> Hi Joonwoo,
>
> I'm really glad that we are making progress!!
>
> Now, for the Queue.  I agree that a simple test should be sufficient to
> test race conditions.
>
> Can you verify that in your configuration, there are *never* two threads
> pushing into a Queue at the same time, and there are *never* two threads
> pulling from a Queue at the same time?  NotifierQueue and FullNoteQueue
> are designed for *at most one* pushing thread and *at most one* pulling
> thread at a time.  The pushing thread can be different from the pulling
> thread, but NotifierQueue and FullNoteQueue don't support multiple
> threads pushing at once (or pulling at once).  Send your configuration
> to the list for us to check.

I posted it already, please check the link.
https://pdos.csail.mit.edu/pipermail/click/attachments/20070708/8b2abbd9/infinitereply.obj

>
> If you are sure that there aren't multiple pushing threads (or pulling
> threads), then take a look at the code.  What do you think the race
> condition is?  Locking the full bodies of those push and pull functions
> is not required.  Can you help me figure it out?

I think the enq() and deq() has problem.
As you said, one enq() and one deq() can be run concurrently.
But operation of the code, '_tail = next' of enq() and '_head =
next_i(_head)' is not atomic (I mean the equalizer)
because of _tail and _head is INT.
Therefore the code 'if (next != _head) {' of push() and 'if (_head !=
_tail)' of pull() cannot be worked correctly.
So I think these are should be atomic.
I am attaching patch and It made another process on my test.

-
Signed-off-by: Joonwoo Park <joonwpark81 at gmail.com>

diff --git a/elements/standard/simplequeue.hh b/elements/standard/simplequeue.hh
index 975c062..bee9e1c 100644
--- a/elements/standard/simplequeue.hh
+++ b/elements/standard/simplequeue.hh
@@ -119,6 +119,7 @@ SimpleQueue::enq(Packet *p)
     int next = next_i(_tail);
     if (next != _head) {
 	_q[_tail] = p;
+	// While doing '_tail = X' pull() can see polluted _tail if it is not atomic
 	_tail = next;
 	int s = size();
 	if (s > _highwater_length)
@@ -150,6 +151,7 @@ SimpleQueue::deq()
     if (_head != _tail) {
 	Packet *p = _q[_head];
 	assert(p);
+	// While doing '_head = X' push() can see polluted _head if it is not atomic
 	_head = next_i(_head);
 	return p;
     } else
diff --git a/include/click/standard/storage.hh
b/include/click/standard/storage.hh
index 9b05a08..70da9c6 100644
--- a/include/click/standard/storage.hh
+++ b/include/click/standard/storage.hh
@@ -1,11 +1,12 @@
 // -*- c-basic-offset: 4 -*-
  #ifndef CLICK_STORAGE_HH
 #define CLICK_STORAGE_HH
+#include <click/atomic.hh>
 CLICK_DECLS

 class Storage { public:

-    Storage()				: _head(0), _tail(0) { }
+    Storage()	{ }

     operator bool() const		{ return _head != _tail; }
     bool empty() const			{ return _head == _tail; }
@@ -26,8 +27,8 @@ class Storage { public:
   protected:

     int _capacity;
-    int _head;
-    int _tail;
+    atomic_uint32_t _head;
+    atomic_uint32_t _tail;

 };

-

Jason Park (Joonwoo Park)

>
> Eddie
>
>


More information about the click mailing list