diff options
author | Sree Harsha Totakura <totakura@in.tum.de> | 2012-11-16 11:20:38 +0000 |
---|---|---|
committer | Sree Harsha Totakura <totakura@in.tum.de> | 2012-11-16 11:20:38 +0000 |
commit | 57dc1a4ec314043cfdbf6e5a0bcf3c4ca103ddec (patch) | |
tree | 33553c2e36c8db66de2df88ed144e5d46bda5b70 /src | |
parent | 27520ef39b732562a6c4ffa8640b44250ad72a4a (diff) | |
download | gnunet-57dc1a4ec314043cfdbf6e5a0bcf3c4ca103ddec.tar.gz gnunet-57dc1a4ec314043cfdbf6e5a0bcf3c4ca103ddec.zip |
dynamically adjustable operation queues
Diffstat (limited to 'src')
-rw-r--r-- | src/testbed/test_testbed_api_operations.c | 110 | ||||
-rw-r--r-- | src/testbed/testbed_api_operations.c | 54 | ||||
-rw-r--r-- | src/testbed/testbed_api_operations.h | 13 |
3 files changed, 150 insertions, 27 deletions
diff --git a/src/testbed/test_testbed_api_operations.c b/src/testbed/test_testbed_api_operations.c index 45f2db103..92bf12983 100644 --- a/src/testbed/test_testbed_api_operations.c +++ b/src/testbed/test_testbed_api_operations.c | |||
@@ -35,12 +35,14 @@ | |||
35 | GNUNET_log (kind, __VA_ARGS__) | 35 | GNUNET_log (kind, __VA_ARGS__) |
36 | 36 | ||
37 | /** | 37 | /** |
38 | * Queue A | 38 | * Queue A. Initially the max active is set to 2 and then reduced to 0 - this |
39 | * should block op2 even after op1 has finished. Later the max active is set to | ||
40 | * 1 and this should start op2 | ||
39 | */ | 41 | */ |
40 | struct OperationQueue *q1; | 42 | struct OperationQueue *q1; |
41 | 43 | ||
42 | /** | 44 | /** |
43 | * Queue B | 45 | * Queue B. Max active set to 1 |
44 | */ | 46 | */ |
45 | struct OperationQueue *q2; | 47 | struct OperationQueue *q2; |
46 | 48 | ||
@@ -54,6 +56,17 @@ struct GNUNET_TESTBED_Operation *op1; | |||
54 | */ | 56 | */ |
55 | struct GNUNET_TESTBED_Operation *op2; | 57 | struct GNUNET_TESTBED_Operation *op2; |
56 | 58 | ||
59 | /** | ||
60 | * This operation should go into both queues and should be started after op2 has | ||
61 | * been released. | ||
62 | */ | ||
63 | struct GNUNET_TESTBED_Operation *op3; | ||
64 | |||
65 | /** | ||
66 | * The delay task identifier | ||
67 | */ | ||
68 | GNUNET_SCHEDULER_TaskIdentifier step_task; | ||
69 | |||
57 | 70 | ||
58 | /** | 71 | /** |
59 | * Enumeration of test stages | 72 | * Enumeration of test stages |
@@ -83,7 +96,23 @@ enum Test | |||
83 | /** | 96 | /** |
84 | * op2 released | 97 | * op2 released |
85 | */ | 98 | */ |
86 | TEST_OP2_RELEASED | 99 | TEST_OP2_RELEASED, |
100 | |||
101 | /** | ||
102 | * Temporary pause where no operations should start as we set max active in q1 | ||
103 | * to 0 | ||
104 | */ | ||
105 | TEST_PAUSE, | ||
106 | |||
107 | /** | ||
108 | * op3 has started | ||
109 | */ | ||
110 | TEST_OP3_STARTED, | ||
111 | |||
112 | /** | ||
113 | * op3 has finished | ||
114 | */ | ||
115 | TEST_OP3_RELEASED | ||
87 | }; | 116 | }; |
88 | 117 | ||
89 | /** | 118 | /** |
@@ -93,6 +122,28 @@ enum Test result; | |||
93 | 122 | ||
94 | 123 | ||
95 | /** | 124 | /** |
125 | * Function to call to start an operation once all | ||
126 | * queues the operation is part of declare that the | ||
127 | * operation can be activated. | ||
128 | */ | ||
129 | static void | ||
130 | start_cb (void *cls); | ||
131 | |||
132 | |||
133 | /** | ||
134 | * Function to cancel an operation (release all associated resources). This can | ||
135 | * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the | ||
136 | * operation generated an event) or AFTER the operation generated an event due | ||
137 | * to a call to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that | ||
138 | * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'. | ||
139 | * Implementations of this function are expected to clean up whatever state is | ||
140 | * in 'cls' and release all resources associated with the operation. | ||
141 | */ | ||
142 | static void | ||
143 | release_cb (void *cls); | ||
144 | |||
145 | |||
146 | /** | ||
96 | * Task to simulate artificial delay and change the test stage | 147 | * Task to simulate artificial delay and change the test stage |
97 | * | 148 | * |
98 | * @param cls NULL | 149 | * @param cls NULL |
@@ -101,14 +152,28 @@ enum Test result; | |||
101 | static void | 152 | static void |
102 | step (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 153 | step (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
103 | { | 154 | { |
155 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != step_task); | ||
156 | step_task = GNUNET_SCHEDULER_NO_TASK; | ||
104 | switch (result) | 157 | switch (result) |
105 | { | 158 | { |
106 | case TEST_OP1_STARTED: | 159 | case TEST_OP1_STARTED: |
107 | GNUNET_TESTBED_operation_release_ (op1); | 160 | GNUNET_TESTBED_operation_release_ (op1); |
161 | GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 0); | ||
162 | op3 = GNUNET_TESTBED_operation_create_ (&op3, &start_cb, &release_cb); | ||
163 | GNUNET_TESTBED_operation_queue_insert_ (q1, op3); | ||
164 | GNUNET_TESTBED_operation_queue_insert_ (q2, op3); | ||
165 | GNUNET_TESTBED_operation_begin_wait_ (op3); | ||
108 | break; | 166 | break; |
109 | case TEST_OP2_STARTED: | 167 | case TEST_OP2_STARTED: |
110 | GNUNET_TESTBED_operation_release_ (op2); | 168 | GNUNET_TESTBED_operation_release_ (op2); |
111 | break; | 169 | break; |
170 | case TEST_OP2_RELEASED: | ||
171 | result = TEST_PAUSE; | ||
172 | GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 1); | ||
173 | break; | ||
174 | case TEST_OP3_STARTED: | ||
175 | GNUNET_TESTBED_operation_release_ (op3); | ||
176 | break; | ||
112 | default: | 177 | default: |
113 | GNUNET_assert (0); | 178 | GNUNET_assert (0); |
114 | } | 179 | } |
@@ -128,12 +193,20 @@ start_cb (void *cls) | |||
128 | case TEST_INIT: | 193 | case TEST_INIT: |
129 | GNUNET_assert (&op1 == cls); | 194 | GNUNET_assert (&op1 == cls); |
130 | result = TEST_OP1_STARTED; | 195 | result = TEST_OP1_STARTED; |
131 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL); | 196 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task); |
197 | step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL); | ||
132 | break; | 198 | break; |
133 | case TEST_OP1_RELEASED: | 199 | case TEST_OP1_RELEASED: |
134 | GNUNET_assert (&op2 == cls); | 200 | GNUNET_assert (&op2 == cls); |
135 | result = TEST_OP2_STARTED; | 201 | result = TEST_OP2_STARTED; |
136 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL); | 202 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task); |
203 | step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL); | ||
204 | break; | ||
205 | case TEST_PAUSE: | ||
206 | GNUNET_assert (&op3 == cls); | ||
207 | result = TEST_OP3_STARTED; | ||
208 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task); | ||
209 | step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL); | ||
137 | break; | 210 | break; |
138 | default: | 211 | default: |
139 | GNUNET_assert (0); | 212 | GNUNET_assert (0); |
@@ -142,15 +215,13 @@ start_cb (void *cls) | |||
142 | 215 | ||
143 | 216 | ||
144 | /** | 217 | /** |
145 | * Function to call to cancel an operation (release all associated | 218 | * Function to cancel an operation (release all associated resources). This can |
146 | * resources). This can be because of a call to | 219 | * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the |
147 | * "GNUNET_TESTBED_operation_cancel" (before the operation generated | 220 | * operation generated an event) or AFTER the operation generated an event due |
148 | * an event) or AFTER the operation generated an event due to a call | 221 | * to a call to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that |
149 | * to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that | 222 | * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'. |
150 | * a callback to the 'OperationStart' preceeds the call to | 223 | * Implementations of this function are expected to clean up whatever state is |
151 | * 'OperationRelease'. Implementations of this function are expected | 224 | * in 'cls' and release all resources associated with the operation. |
152 | * to clean up whatever state is in 'cls' and release all resources | ||
153 | * associated with the operation. | ||
154 | */ | 225 | */ |
155 | static void | 226 | static void |
156 | release_cb (void *cls) | 227 | release_cb (void *cls) |
@@ -160,10 +231,18 @@ release_cb (void *cls) | |||
160 | case TEST_OP1_STARTED: | 231 | case TEST_OP1_STARTED: |
161 | GNUNET_assert (&op1 == cls); | 232 | GNUNET_assert (&op1 == cls); |
162 | result = TEST_OP1_RELEASED; | 233 | result = TEST_OP1_RELEASED; |
234 | op1 = NULL; | ||
235 | //GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL); | ||
163 | break; | 236 | break; |
164 | case TEST_OP2_STARTED: | 237 | case TEST_OP2_STARTED: |
165 | GNUNET_assert (&op2 == cls); | 238 | GNUNET_assert (&op2 == cls); |
166 | result = TEST_OP2_RELEASED; | 239 | result = TEST_OP2_RELEASED; |
240 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task); | ||
241 | step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL); | ||
242 | break; | ||
243 | case TEST_OP3_STARTED: | ||
244 | GNUNET_assert (&op3 == cls); | ||
245 | result = TEST_OP3_RELEASED; | ||
167 | GNUNET_TESTBED_operation_queue_destroy_ (q1); | 246 | GNUNET_TESTBED_operation_queue_destroy_ (q1); |
168 | GNUNET_TESTBED_operation_queue_destroy_ (q2); | 247 | GNUNET_TESTBED_operation_queue_destroy_ (q2); |
169 | break; | 248 | break; |
@@ -217,10 +296,11 @@ main (int argc, char **argv) | |||
217 | GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, | 296 | GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, |
218 | "test_testbed_api_operations", "nohelp", options, | 297 | "test_testbed_api_operations", "nohelp", options, |
219 | &run, NULL); | 298 | &run, NULL); |
220 | if ((GNUNET_OK != ret) || (TEST_OP2_RELEASED != result)) | 299 | if ((GNUNET_OK != ret) || (TEST_OP3_RELEASED != result)) |
221 | return 1; | 300 | return 1; |
222 | op1 = NULL; | 301 | op1 = NULL; |
223 | op2 = NULL; | 302 | op2 = NULL; |
303 | op3 = NULL; | ||
224 | q1 = NULL; | 304 | q1 = NULL; |
225 | q2 = NULL; | 305 | q2 = NULL; |
226 | return 0; | 306 | return 0; |
diff --git a/src/testbed/testbed_api_operations.c b/src/testbed/testbed_api_operations.c index f609b1770..e657c8354 100644 --- a/src/testbed/testbed_api_operations.c +++ b/src/testbed/testbed_api_operations.c | |||
@@ -66,10 +66,15 @@ struct OperationQueue | |||
66 | struct QueueEntry *tail; | 66 | struct QueueEntry *tail; |
67 | 67 | ||
68 | /** | 68 | /** |
69 | * Number of operations that can be concurrently | 69 | * Number of operations that are currently active in this queue. |
70 | * active in this queue. | ||
71 | */ | 70 | */ |
72 | unsigned int active; | 71 | unsigned int active; |
72 | |||
73 | /** | ||
74 | * Max number of operations which can be active at any time in this queue | ||
75 | */ | ||
76 | unsigned int max_active; | ||
77 | |||
73 | }; | 78 | }; |
74 | 79 | ||
75 | 80 | ||
@@ -158,9 +163,7 @@ call_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
158 | op->start_task_id = GNUNET_SCHEDULER_NO_TASK; | 163 | op->start_task_id = GNUNET_SCHEDULER_NO_TASK; |
159 | op->state = OP_STATE_STARTED; | 164 | op->state = OP_STATE_STARTED; |
160 | if (NULL != op->start) | 165 | if (NULL != op->start) |
161 | { | ||
162 | op->start (op->cb_cls); | 166 | op->start (op->cb_cls); |
163 | } | ||
164 | } | 167 | } |
165 | 168 | ||
166 | 169 | ||
@@ -176,14 +179,10 @@ check_readiness (struct GNUNET_TESTBED_Operation *op) | |||
176 | 179 | ||
177 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == op->start_task_id); | 180 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == op->start_task_id); |
178 | for (i = 0; i < op->nqueues; i++) | 181 | for (i = 0; i < op->nqueues; i++) |
179 | { | 182 | if (op->queues[i]->active >= op->queues[i]->max_active) |
180 | if (0 == op->queues[i]->active) | ||
181 | return; | 183 | return; |
182 | } | ||
183 | for (i = 0; i < op->nqueues; i++) | 184 | for (i = 0; i < op->nqueues; i++) |
184 | { | 185 | op->queues[i]->active++; |
185 | op->queues[i]->active--; | ||
186 | } | ||
187 | op->state = OP_STATE_READY; | 186 | op->state = OP_STATE_READY; |
188 | op->start_task_id = GNUNET_SCHEDULER_add_now (&call_start, op); | 187 | op->start_task_id = GNUNET_SCHEDULER_add_now (&call_start, op); |
189 | } | 188 | } |
@@ -226,7 +225,7 @@ GNUNET_TESTBED_operation_queue_create_ (unsigned int max_active) | |||
226 | struct OperationQueue *queue; | 225 | struct OperationQueue *queue; |
227 | 226 | ||
228 | queue = GNUNET_malloc (sizeof (struct OperationQueue)); | 227 | queue = GNUNET_malloc (sizeof (struct OperationQueue)); |
229 | queue->active = max_active; | 228 | queue->max_active = max_active; |
230 | return queue; | 229 | return queue; |
231 | } | 230 | } |
232 | 231 | ||
@@ -247,6 +246,34 @@ GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue) | |||
247 | 246 | ||
248 | 247 | ||
249 | /** | 248 | /** |
249 | * Function to reset the maximum number of operations in the given queue. If | ||
250 | * max_active is lesser than the number of currently active operations, the | ||
251 | * active operations are not stopped immediately. | ||
252 | * | ||
253 | * @param queue the operation queue which has to be modified | ||
254 | * @param max_active the new maximum number of active operations | ||
255 | */ | ||
256 | void | ||
257 | GNUNET_TESTBED_operation_queue_reset_max_active_ (struct OperationQueue *queue, | ||
258 | unsigned int max_active) | ||
259 | { | ||
260 | struct QueueEntry *entry; | ||
261 | |||
262 | queue->max_active = max_active; | ||
263 | if (queue->active >= queue->max_active) | ||
264 | return; | ||
265 | entry = queue->head; | ||
266 | while ( (NULL != entry) && | ||
267 | (queue->active < queue->max_active) ) | ||
268 | { | ||
269 | if (OP_STATE_WAITING == entry->op->state) | ||
270 | check_readiness (entry->op); | ||
271 | entry = entry->next; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | |||
276 | /** | ||
250 | * Add an operation to a queue. An operation can be in multiple queues at | 277 | * Add an operation to a queue. An operation can be in multiple queues at |
251 | * once. Once the operation is inserted into all the queues | 278 | * once. Once the operation is inserted into all the queues |
252 | * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start | 279 | * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start |
@@ -314,7 +341,10 @@ GNUNET_TESTBED_operation_queue_remove_ (struct OperationQueue *queue, | |||
314 | break; | 341 | break; |
315 | GNUNET_assert (NULL != entry); | 342 | GNUNET_assert (NULL != entry); |
316 | if (OP_STATE_STARTED == operation->state) | 343 | if (OP_STATE_STARTED == operation->state) |
317 | queue->active++; | 344 | { |
345 | GNUNET_assert (0 != queue->active); | ||
346 | queue->active--; | ||
347 | } | ||
318 | entry2 = entry->next; | 348 | entry2 = entry->next; |
319 | GNUNET_CONTAINER_DLL_remove (queue->head, queue->tail, entry); | 349 | GNUNET_CONTAINER_DLL_remove (queue->head, queue->tail, entry); |
320 | GNUNET_free (entry); | 350 | GNUNET_free (entry); |
diff --git a/src/testbed/testbed_api_operations.h b/src/testbed/testbed_api_operations.h index e78ed0fcc..d5a918f0e 100644 --- a/src/testbed/testbed_api_operations.h +++ b/src/testbed/testbed_api_operations.h | |||
@@ -59,6 +59,19 @@ GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue); | |||
59 | 59 | ||
60 | 60 | ||
61 | /** | 61 | /** |
62 | * Function to reset the maximum number of operations in the given queue. If | ||
63 | * max_active is lesser than the number of currently active operations, the | ||
64 | * active operations are not stopped immediately. | ||
65 | * | ||
66 | * @param queue the operation queue which has to be modified | ||
67 | * @param max_active the new maximum number of active operations | ||
68 | */ | ||
69 | void | ||
70 | GNUNET_TESTBED_operation_queue_reset_max_active_ (struct OperationQueue *queue, | ||
71 | unsigned int max_active); | ||
72 | |||
73 | |||
74 | /** | ||
62 | * Add an operation to a queue. An operation can be in multiple queues at | 75 | * Add an operation to a queue. An operation can be in multiple queues at |
63 | * once. Once the operation is inserted into all the queues | 76 | * once. Once the operation is inserted into all the queues |
64 | * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start | 77 | * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start |