Browse code

b/f: race condition timers

Fixes a race condition that caused a timer to be removed from the wheel before it has been inserted.

Raphael Coeffic authored on 11/03/2011 22:56:10
Showing 2 changed files
... ...
@@ -54,17 +54,17 @@ _wheeltimer::~_wheeltimer()
54 54
 void _wheeltimer::insert_timer(timer* t)
55 55
 {
56 56
     //add new timer to user request list
57
-    utimer_add_m.lock();
58
-    utimer_add.push_back(t);
59
-    utimer_add_m.unlock();
57
+    reqs_m.lock();
58
+    reqs_backlog.push_back(timer_req(t,true));
59
+    reqs_m.unlock();
60 60
 }
61 61
 
62 62
 void _wheeltimer::remove_timer(timer* t)
63 63
 {
64 64
     //add timer to remove to user request list
65
-    utimer_rem_m.lock();
66
-    utimer_rem.push_back(t);
67
-    utimer_rem_m.unlock();
65
+    reqs_m.lock();
66
+    reqs_backlog.push_back(timer_req(t,false));
67
+    reqs_m.unlock();
68 68
 }
69 69
 
70 70
 void _wheeltimer::run()
... ...
@@ -144,28 +144,21 @@ void _wheeltimer::turn_wheel()
144 144
     // Update existing timer entries
145 145
     update_wheel(i);
146 146
 	
147
-    // Check for timer insertion requests
148
-    utimer_add_m.lock();
149
-    std::vector<timer*> utimer_add_cp = utimer_add;
150
-    utimer_add.clear();
151
-    utimer_add_m.unlock();
152
-
153
-    for (std::vector<timer*>::iterator it=
154
-	     utimer_add_cp.begin(); it != 
155
-	     utimer_add_cp.end(); it++) {
156
-	place_timer(*it);
157
-    }
158
-	
159
-    // Check for timer deletion requests
160
-    utimer_rem_m.lock();
161
-    std::vector<timer*> utimer_rem_cp = utimer_rem;
162
-    utimer_rem.clear();
163
-    utimer_rem_m.unlock();
164
-
165
-    for (std::vector<timer*>::iterator it=
166
-	     utimer_rem_cp.begin(); it != 
167
-	     utimer_rem_cp.end(); it++) {
168
-	delete_timer(*it);
147
+    // Swap the lists for timer insertion/deletion requests
148
+    reqs_m.lock();
149
+    reqs_process.swap(reqs_backlog);
150
+    reqs_m.unlock();
151
+
152
+    while(!reqs_process.empty()) {
153
+	timer_req rq = reqs_process.front();
154
+	reqs_process.pop_front();
155
+
156
+	if(rq.insert) {
157
+	    place_timer(rq.t);
158
+	}
159
+	else {
160
+	    delete_timer(rq.t);
161
+	}
169 162
     }
170 163
 	
171 164
     //check for expired timer to process
... ...
@@ -32,7 +32,7 @@
32 32
 
33 33
 #include "../AmThread.h"
34 34
 
35
-#include <queue>
35
+#include <deque>
36 36
 
37 37
 #define BITS_PER_WHEEL 8
38 38
 #define ELMTS_PER_WHEEL (1 << BITS_PER_WHEEL)
... ...
@@ -88,23 +88,23 @@ public:
88 88
 class _wheeltimer:
89 89
     public AmThread
90 90
 {
91
-    //the timer wheel
92
-    base_timer wheels[WHEELS][ELMTS_PER_WHEEL];
93
-
94
-    // utimer remove lock
95
-    AmMutex    utimer_add_m;
91
+    struct timer_req {
96 92
 
97
-    //list with timer insertions requests
98
-    std::vector<timer*> utimer_add;
93
+	timer* t;
94
+	bool   insert; // false -> remove
95
+	
96
+	timer_req(timer* t, bool insert)
97
+	    : t(t), insert(insert)
98
+	{}
99
+    };
99 100
 
100
-    // utimer remove lock
101
-    AmMutex    utimer_rem_m;
102
-
103
-    //list with timer deletions requests
104
-    std::vector<timer*> utimer_rem;
101
+    //the timer wheel
102
+    base_timer wheels[WHEELS][ELMTS_PER_WHEEL];
105 103
 
106
-    //list with expired timers
107
-    base_timer utimer_expired;
104
+    // request backlog lock (insert/remove)
105
+    AmMutex               reqs_m;
106
+    std::deque<timer_req> reqs_backlog;
107
+    std::deque<timer_req> reqs_process;
108 108
 
109 109
     void turn_wheel();
110 110
     void update_wheel(int wheel);