diff options
-rw-r--r-- | src/testbed/testbed_api_operations.c | 128 |
1 files changed, 103 insertions, 25 deletions
diff --git a/src/testbed/testbed_api_operations.c b/src/testbed/testbed_api_operations.c index a60ecfd97..515367d8e 100644 --- a/src/testbed/testbed_api_operations.c +++ b/src/testbed/testbed_api_operations.c | |||
@@ -111,6 +111,28 @@ enum OperationState | |||
111 | 111 | ||
112 | 112 | ||
113 | /** | 113 | /** |
114 | * An entry in the ready queue (implemented as DLL) | ||
115 | */ | ||
116 | struct ReadyQueueEntry | ||
117 | { | ||
118 | /** | ||
119 | * next ptr for DLL | ||
120 | */ | ||
121 | struct ReadyQueueEntry *next; | ||
122 | |||
123 | /** | ||
124 | * prev ptr for DLL | ||
125 | */ | ||
126 | struct ReadyQueueEntry *prev; | ||
127 | |||
128 | /** | ||
129 | * The operation associated with this entry | ||
130 | */ | ||
131 | struct GNUNET_TESTBED_Operation *op; | ||
132 | }; | ||
133 | |||
134 | |||
135 | /** | ||
114 | * Opaque handle to an abstract operation to be executed by the testing framework. | 136 | * Opaque handle to an abstract operation to be executed by the testing framework. |
115 | */ | 137 | */ |
116 | struct GNUNET_TESTBED_Operation | 138 | struct GNUNET_TESTBED_Operation |
@@ -137,15 +159,16 @@ struct GNUNET_TESTBED_Operation | |||
137 | struct OperationQueue **queues; | 159 | struct OperationQueue **queues; |
138 | 160 | ||
139 | /** | 161 | /** |
140 | * Array of number resources an operation need from each queue. This numbers | 162 | * Array of number of resources an operation need from each queue. The numbers |
141 | * in this array should correspond to the queues array | 163 | * in this array should correspond to the queues array |
142 | */ | 164 | */ |
143 | unsigned int *nres; | 165 | unsigned int *nres; |
144 | 166 | ||
145 | /** | 167 | /** |
146 | * The id of the task which calls OperationStart for this operation | 168 | * Entry corresponding to this operation in ready queue. Will be NULL if the |
169 | * operation is not marked as READY | ||
147 | */ | 170 | */ |
148 | GNUNET_SCHEDULER_TaskIdentifier start_task_id; | 171 | struct ReadyQueueEntry *rq_entry; |
149 | 172 | ||
150 | /** | 173 | /** |
151 | * Number of queues in the operation queues array | 174 | * Number of queues in the operation queues array |
@@ -159,22 +182,86 @@ struct GNUNET_TESTBED_Operation | |||
159 | 182 | ||
160 | }; | 183 | }; |
161 | 184 | ||
185 | /** | ||
186 | * DLL head for the ready queue | ||
187 | */ | ||
188 | struct ReadyQueueEntry *rq_head; | ||
189 | |||
190 | /** | ||
191 | * DLL tail for the ready queue | ||
192 | */ | ||
193 | struct ReadyQueueEntry *rq_tail; | ||
194 | |||
195 | /** | ||
196 | * The id of the task to process the ready queue | ||
197 | */ | ||
198 | GNUNET_SCHEDULER_TaskIdentifier process_rq_task_id; | ||
199 | |||
162 | 200 | ||
163 | /** | 201 | /** |
164 | * Task for calling OperationStart on operation | 202 | * Removes an operation from the ready queue. Also stops the 'process_rq_task' |
203 | * if the given operation is the last one in the queue. | ||
165 | * | 204 | * |
166 | * @param cls the Operation | 205 | * @param op the operation to be removed |
167 | * @param tc the TaskContext from scheduler | ||
168 | */ | 206 | */ |
169 | static void | 207 | static void |
170 | call_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 208 | rq_remove (struct GNUNET_TESTBED_Operation *op) |
209 | { | ||
210 | GNUNET_assert (NULL != op->rq_entry); | ||
211 | GNUNET_CONTAINER_DLL_remove (rq_head, rq_tail, op->rq_entry); | ||
212 | GNUNET_free (op->rq_entry); | ||
213 | op->rq_entry = NULL; | ||
214 | if ( (NULL == rq_head) && (GNUNET_SCHEDULER_NO_TASK != process_rq_task_id) ) | ||
215 | { | ||
216 | GNUNET_SCHEDULER_cancel (process_rq_task_id); | ||
217 | process_rq_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | |||
222 | /** | ||
223 | * Processes the ready queue by calling the operation start callback of the | ||
224 | * operation at the head. The operation is then removed from the queue. The | ||
225 | * task is scheduled to run again immediately until no more operations are in | ||
226 | * the ready queue. | ||
227 | * | ||
228 | * @param cls NULL | ||
229 | * @param tc scheduler task context. Not used. | ||
230 | */ | ||
231 | static void | ||
232 | process_rq_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
171 | { | 233 | { |
172 | struct GNUNET_TESTBED_Operation *op = cls; | 234 | struct GNUNET_TESTBED_Operation *op; |
173 | 235 | ||
174 | op->start_task_id = GNUNET_SCHEDULER_NO_TASK; | 236 | process_rq_task_id = GNUNET_SCHEDULER_NO_TASK; |
237 | GNUNET_assert (NULL != rq_head); | ||
238 | GNUNET_assert (NULL != (op = rq_head->op)); | ||
239 | rq_remove (op); | ||
240 | if (NULL != rq_head) | ||
241 | process_rq_task_id = GNUNET_SCHEDULER_add_now (&process_rq_task, NULL); | ||
175 | op->state = OP_STATE_STARTED; | 242 | op->state = OP_STATE_STARTED; |
176 | if (NULL != op->start) | 243 | if (NULL != op->start) |
177 | op->start (op->cb_cls); | 244 | op->start (op->cb_cls); |
245 | } | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Adds the operation to the ready queue and starts the 'process_rq_task' | ||
250 | * | ||
251 | * @param op the operation to be queued | ||
252 | */ | ||
253 | static void | ||
254 | rq_add (struct GNUNET_TESTBED_Operation *op) | ||
255 | { | ||
256 | struct ReadyQueueEntry *rq_entry; | ||
257 | |||
258 | GNUNET_assert (NULL == op->rq_entry); | ||
259 | rq_entry = GNUNET_malloc (sizeof (struct ReadyQueueEntry)); | ||
260 | rq_entry->op = op; | ||
261 | GNUNET_CONTAINER_DLL_insert_tail (rq_head, rq_tail, rq_entry); | ||
262 | op->rq_entry = rq_entry; | ||
263 | if (GNUNET_SCHEDULER_NO_TASK == process_rq_task_id) | ||
264 | process_rq_task_id = GNUNET_SCHEDULER_add_now (&process_rq_task, NULL); | ||
178 | } | 265 | } |
179 | 266 | ||
180 | 267 | ||
@@ -188,7 +275,7 @@ check_readiness (struct GNUNET_TESTBED_Operation *op) | |||
188 | { | 275 | { |
189 | unsigned int i; | 276 | unsigned int i; |
190 | 277 | ||
191 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == op->start_task_id); | 278 | GNUNET_assert (NULL == op->rq_entry); |
192 | for (i = 0; i < op->nqueues; i++) | 279 | for (i = 0; i < op->nqueues; i++) |
193 | { | 280 | { |
194 | GNUNET_assert (0 < op->nres[i]); | 281 | GNUNET_assert (0 < op->nres[i]); |
@@ -198,7 +285,7 @@ check_readiness (struct GNUNET_TESTBED_Operation *op) | |||
198 | for (i = 0; i < op->nqueues; i++) | 285 | for (i = 0; i < op->nqueues; i++) |
199 | op->queues[i]->active += op->nres[i]; | 286 | op->queues[i]->active += op->nres[i]; |
200 | op->state = OP_STATE_READY; | 287 | op->state = OP_STATE_READY; |
201 | op->start_task_id = GNUNET_SCHEDULER_add_now (&call_start, op); | 288 | rq_add (op); |
202 | } | 289 | } |
203 | 290 | ||
204 | 291 | ||
@@ -213,9 +300,7 @@ defer (struct GNUNET_TESTBED_Operation *op) | |||
213 | unsigned int i; | 300 | unsigned int i; |
214 | 301 | ||
215 | GNUNET_assert (OP_STATE_READY == op->state); | 302 | GNUNET_assert (OP_STATE_READY == op->state); |
216 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != op->start_task_id); | 303 | rq_remove (op); |
217 | GNUNET_SCHEDULER_cancel (op->start_task_id); | ||
218 | op->start_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
219 | for (i = 0; i < op->nqueues; i++) | 304 | for (i = 0; i < op->nqueues; i++) |
220 | op->queues[i]->active--; | 305 | op->queues[i]->active--; |
221 | op->state = OP_STATE_WAITING; | 306 | op->state = OP_STATE_WAITING; |
@@ -241,7 +326,6 @@ GNUNET_TESTBED_operation_create_ (void *cls, OperationStart start, | |||
241 | op->state = OP_STATE_INIT; | 326 | op->state = OP_STATE_INIT; |
242 | op->release = release; | 327 | op->release = release; |
243 | op->cb_cls = cls; | 328 | op->cb_cls = cls; |
244 | op->start_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
245 | return op; | 329 | return op; |
246 | } | 330 | } |
247 | 331 | ||
@@ -311,9 +395,6 @@ GNUNET_TESTBED_operation_queue_reset_max_active_ (struct OperationQueue *queue, | |||
311 | struct QueueEntry *entry; | 395 | struct QueueEntry *entry; |
312 | 396 | ||
313 | queue->max_active = max_active; | 397 | queue->max_active = max_active; |
314 | /* if (queue->active >= queue->max_active) */ | ||
315 | /* return; */ | ||
316 | |||
317 | entry = queue->head; | 398 | entry = queue->head; |
318 | while ((queue->active > queue->max_active) && (NULL != entry)) | 399 | while ((queue->active > queue->max_active) && (NULL != entry)) |
319 | { | 400 | { |
@@ -396,7 +477,7 @@ void | |||
396 | GNUNET_TESTBED_operation_begin_wait_ (struct GNUNET_TESTBED_Operation | 477 | GNUNET_TESTBED_operation_begin_wait_ (struct GNUNET_TESTBED_Operation |
397 | *operation) | 478 | *operation) |
398 | { | 479 | { |
399 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == operation->start_task_id); | 480 | GNUNET_assert (NULL == operation->rq_entry); |
400 | operation->state = OP_STATE_WAITING; | 481 | operation->state = OP_STATE_WAITING; |
401 | check_readiness (operation); | 482 | check_readiness (operation); |
402 | } | 483 | } |
@@ -459,11 +540,8 @@ GNUNET_TESTBED_operation_release_ (struct GNUNET_TESTBED_Operation *operation) | |||
459 | { | 540 | { |
460 | unsigned int i; | 541 | unsigned int i; |
461 | 542 | ||
462 | if (GNUNET_SCHEDULER_NO_TASK != operation->start_task_id) | 543 | if (OP_STATE_READY == operation->state) |
463 | { | 544 | rq_remove (operation); |
464 | GNUNET_SCHEDULER_cancel (operation->start_task_id); | ||
465 | operation->start_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
466 | } | ||
467 | for (i = 0; i < operation->nqueues; i++) | 545 | for (i = 0; i < operation->nqueues; i++) |
468 | GNUNET_TESTBED_operation_queue_remove_ (operation->queues[i], operation); | 546 | GNUNET_TESTBED_operation_queue_remove_ (operation->queues[i], operation); |
469 | GNUNET_free (operation->queues); | 547 | GNUNET_free (operation->queues); |