aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/testbed/testbed_api_operations.c128
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 */
116struct 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 */
116struct GNUNET_TESTBED_Operation 138struct 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 */
188struct ReadyQueueEntry *rq_head;
189
190/**
191 * DLL tail for the ready queue
192 */
193struct ReadyQueueEntry *rq_tail;
194
195/**
196 * The id of the task to process the ready queue
197 */
198GNUNET_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 */
169static void 207static void
170call_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 208rq_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 */
231static void
232process_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 */
253static void
254rq_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
396GNUNET_TESTBED_operation_begin_wait_ (struct GNUNET_TESTBED_Operation 477GNUNET_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);