diff options
author | lurchi <lurchi@strangeplace.net> | 2017-12-30 21:32:59 +0100 |
---|---|---|
committer | lurchi <lurchi@strangeplace.net> | 2017-12-30 21:32:59 +0100 |
commit | dca8eb9c44dbdfa3fc572dde40c1e0927cfee8db (patch) | |
tree | e0b2a09e6d4777308bb9b30511815b4d5f756891 | |
parent | 5c8feda7faa01365a1fb6983595ceb65dfe4fb11 (diff) | |
parent | 11f78ccd0b66e08b8d1084cc335daac99d3f6a7e (diff) | |
download | gnunet-dca8eb9c44dbdfa3fc572dde40c1e0927cfee8db.tar.gz gnunet-dca8eb9c44dbdfa3fc572dde40c1e0927cfee8db.zip |
merge branch 'refactoring-scheduler'
-rw-r--r-- | src/fs/test_fs_download_persistence.c | 1 | ||||
-rw-r--r-- | src/fs/test_fs_publish_persistence.c | 1 | ||||
-rw-r--r-- | src/include/gnunet_common.h | 15 | ||||
-rw-r--r-- | src/include/gnunet_network_lib.h | 6 | ||||
-rw-r--r-- | src/include/gnunet_scheduler_lib.h | 44 | ||||
-rw-r--r-- | src/util/network.c | 6 | ||||
-rw-r--r-- | src/util/program.c | 12 | ||||
-rw-r--r-- | src/util/scheduler.c | 1535 |
8 files changed, 947 insertions, 673 deletions
diff --git a/src/fs/test_fs_download_persistence.c b/src/fs/test_fs_download_persistence.c index 76a1ea911..8f27e82af 100644 --- a/src/fs/test_fs_download_persistence.c +++ b/src/fs/test_fs_download_persistence.c | |||
@@ -179,7 +179,6 @@ progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) | |||
179 | GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL); | 179 | GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL); |
180 | break; | 180 | break; |
181 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | 181 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: |
182 | consider_restart (event->status); | ||
183 | printf ("Download complete, %llu kbps.\n", | 182 | printf ("Download complete, %llu kbps.\n", |
184 | (unsigned long long) (FILESIZE * 1000000LL / | 183 | (unsigned long long) (FILESIZE * 1000000LL / |
185 | (1 + | 184 | (1 + |
diff --git a/src/fs/test_fs_publish_persistence.c b/src/fs/test_fs_publish_persistence.c index be9006d42..103ca01b8 100644 --- a/src/fs/test_fs_publish_persistence.c +++ b/src/fs/test_fs_publish_persistence.c | |||
@@ -134,7 +134,6 @@ progress_cb (void *cls, | |||
134 | switch (event->status) | 134 | switch (event->status) |
135 | { | 135 | { |
136 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: | 136 | case GNUNET_FS_STATUS_PUBLISH_COMPLETED: |
137 | consider_restart (event->status); | ||
138 | ret = event->value.publish.cctx; | 137 | ret = event->value.publish.cctx; |
139 | printf ("Publish complete, %llu kbps.\n", | 138 | printf ("Publish complete, %llu kbps.\n", |
140 | (unsigned long long) (FILESIZE * 1000000LL / | 139 | (unsigned long long) (FILESIZE * 1000000LL / |
diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h index d7f7b76ff..7d23e6f9b 100644 --- a/src/include/gnunet_common.h +++ b/src/include/gnunet_common.h | |||
@@ -988,7 +988,8 @@ GNUNET_ntoh_double (double d); | |||
988 | * arr is important since size is the number of elements and | 988 | * arr is important since size is the number of elements and |
989 | * not the size in bytes | 989 | * not the size in bytes |
990 | * @param size the number of elements in the existing vector (number | 990 | * @param size the number of elements in the existing vector (number |
991 | * of elements to copy over) | 991 | * of elements to copy over), will be updated with the new |
992 | * array size | ||
992 | * @param tsize the target size for the resulting vector, use 0 to | 993 | * @param tsize the target size for the resulting vector, use 0 to |
993 | * free the vector (then, arr will be NULL afterwards). | 994 | * free the vector (then, arr will be NULL afterwards). |
994 | */ | 995 | */ |
@@ -996,8 +997,16 @@ GNUNET_ntoh_double (double d); | |||
996 | 997 | ||
997 | /** | 998 | /** |
998 | * @ingroup memory | 999 | * @ingroup memory |
999 | * Append an element to a list (growing the | 1000 | * Append an element to a list (growing the list by one). |
1000 | * list by one). | 1001 | * |
1002 | * @param arr base-pointer of the vector, may be NULL if size is 0; | ||
1003 | * will be updated to reflect the new address. The TYPE of | ||
1004 | * arr is important since size is the number of elements and | ||
1005 | * not the size in bytes | ||
1006 | * @param size the number of elements in the existing vector (number | ||
1007 | * of elements to copy over), will be updated with the new | ||
1008 | * array size | ||
1009 | * @param element the element that will be appended to the array | ||
1001 | */ | 1010 | */ |
1002 | #define GNUNET_array_append(arr,size,element) do { GNUNET_array_grow(arr,size,size+1); arr[size-1] = element; } while(0) | 1011 | #define GNUNET_array_append(arr,size,element) do { GNUNET_array_grow(arr,size,size+1); arr[size-1] = element; } while(0) |
1003 | 1012 | ||
diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h index d9d3d90e7..9e692bbbf 100644 --- a/src/include/gnunet_network_lib.h +++ b/src/include/gnunet_network_lib.h | |||
@@ -464,7 +464,7 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, | |||
464 | * @return POSIX file descriptor | 464 | * @return POSIX file descriptor |
465 | */ | 465 | */ |
466 | int | 466 | int |
467 | GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc); | 467 | GNUNET_NETWORK_get_fd (const struct GNUNET_NETWORK_Handle *desc); |
468 | 468 | ||
469 | 469 | ||
470 | /** | 470 | /** |
@@ -474,7 +474,7 @@ GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc); | |||
474 | * @return POSIX file descriptor | 474 | * @return POSIX file descriptor |
475 | */ | 475 | */ |
476 | struct sockaddr* | 476 | struct sockaddr* |
477 | GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc); | 477 | GNUNET_NETWORK_get_addr (const struct GNUNET_NETWORK_Handle *desc); |
478 | 478 | ||
479 | 479 | ||
480 | /** | 480 | /** |
@@ -484,7 +484,7 @@ GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc); | |||
484 | * @return socklen_t for sockaddr | 484 | * @return socklen_t for sockaddr |
485 | */ | 485 | */ |
486 | socklen_t | 486 | socklen_t |
487 | GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc); | 487 | GNUNET_NETWORK_get_addrlen (const struct GNUNET_NETWORK_Handle *desc); |
488 | 488 | ||
489 | 489 | ||
490 | /** | 490 | /** |
diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h index a855ab8ab..d2805a685 100644 --- a/src/include/gnunet_scheduler_lib.h +++ b/src/include/gnunet_scheduler_lib.h | |||
@@ -152,14 +152,14 @@ struct GNUNET_SCHEDULER_FdInfo | |||
152 | * NULL if this is about a file handle or if no network | 152 | * NULL if this is about a file handle or if no network |
153 | * handle was given to the scheduler originally. | 153 | * handle was given to the scheduler originally. |
154 | */ | 154 | */ |
155 | struct GNUNET_NETWORK_Handle *fd; | 155 | const struct GNUNET_NETWORK_Handle *fd; |
156 | 156 | ||
157 | /** | 157 | /** |
158 | * GNUnet file handle the event is about, matches @a sock, | 158 | * GNUnet file handle the event is about, matches @a sock, |
159 | * NULL if this is about a network socket or if no network | 159 | * NULL if this is about a network socket or if no network |
160 | * handle was given to the scheduler originally. | 160 | * handle was given to the scheduler originally. |
161 | */ | 161 | */ |
162 | struct GNUNET_DISK_FileHandle *fh; | 162 | const struct GNUNET_DISK_FileHandle *fh; |
163 | 163 | ||
164 | /** | 164 | /** |
165 | * Type of the event that was generated related to @e sock. | 165 | * Type of the event that was generated related to @e sock. |
@@ -216,17 +216,18 @@ struct GNUNET_SCHEDULER_TaskContext | |||
216 | 216 | ||
217 | /** | 217 | /** |
218 | * Function used by event-loop implementations to signal the scheduler | 218 | * Function used by event-loop implementations to signal the scheduler |
219 | * that a particular @a task is ready due to an event of type @a et. | 219 | * that a particular @a task is ready due to an event specified in the |
220 | * et field of @a fdi. | ||
220 | * | 221 | * |
221 | * This function will then queue the task to notify the application | 222 | * This function will then queue the task to notify the application |
222 | * that the task is ready (with the respective priority). | 223 | * that the task is ready (with the respective priority). |
223 | * | 224 | * |
224 | * @param task the task that is ready | 225 | * @param task the task that is ready |
225 | * @param et information about why the task is ready | 226 | * @param fdi information about the related FD |
226 | */ | 227 | */ |
227 | void | 228 | void |
228 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | 229 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, |
229 | enum GNUNET_SCHEDULER_EventType et); | 230 | struct GNUNET_SCHEDULER_FdInfo *fdi); |
230 | 231 | ||
231 | 232 | ||
232 | /** | 233 | /** |
@@ -241,15 +242,16 @@ struct GNUNET_SCHEDULER_Handle; | |||
241 | * there are tasks left to run just to give other tasks a chance as | 242 | * there are tasks left to run just to give other tasks a chance as |
242 | * well. If we return #GNUNET_YES, the driver should call this | 243 | * well. If we return #GNUNET_YES, the driver should call this |
243 | * function again as soon as possible, while if we return #GNUNET_NO | 244 | * function again as soon as possible, while if we return #GNUNET_NO |
244 | * it must block until the operating system has more work as the | 245 | * it must block until either the operating system has more work (the |
245 | * scheduler has no more work to do right now. | 246 | * scheduler has no more work to do right now) or the timeout set by |
247 | * the scheduler (using the set_wakeup callback) is reached. | ||
246 | * | 248 | * |
247 | * @param sh scheduler handle that was given to the `loop` | 249 | * @param sh scheduler handle that was given to the `loop` |
248 | * @return #GNUNET_OK if there are more tasks that are ready, | 250 | * @return #GNUNET_OK if there are more tasks that are ready, |
249 | * and thus we would like to run more (yield to avoid | 251 | * and thus we would like to run more (yield to avoid |
250 | * blocking other activities for too long) | 252 | * blocking other activities for too long) |
251 | * #GNUNET_NO if we are done running tasks (yield to block) | 253 | * #GNUNET_NO if we are done running tasks (yield to block) |
252 | * #GNUNET_SYSERR on error | 254 | * #GNUNET_SYSERR on error, e.g. no tasks were ready |
253 | */ | 255 | */ |
254 | int | 256 | int |
255 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh); | 257 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh); |
@@ -268,8 +270,11 @@ struct GNUNET_SCHEDULER_Driver | |||
268 | void *cls; | 270 | void *cls; |
269 | 271 | ||
270 | /** | 272 | /** |
271 | * Add a @a task to be run if the conditions given | 273 | * Add a @a task to be run if the conditions specified in the |
272 | * in @a fdi are satisfied. | 274 | * et field of the given @a fdi are satisfied. The et field will |
275 | * be cleared after this call and the driver is expected to set | ||
276 | * the type of the actual event before passing @a fdi to | ||
277 | * #GNUNET_SCHEDULER_task_ready. | ||
273 | * | 278 | * |
274 | * @param cls closure | 279 | * @param cls closure |
275 | * @param task task to add | 280 | * @param task task to add |
@@ -280,21 +285,21 @@ struct GNUNET_SCHEDULER_Driver | |||
280 | int | 285 | int |
281 | (*add)(void *cls, | 286 | (*add)(void *cls, |
282 | struct GNUNET_SCHEDULER_Task *task, | 287 | struct GNUNET_SCHEDULER_Task *task, |
283 | struct GNUNET_SCHEDULER_FdInfo *fdi); | 288 | struct GNUNET_SCHEDULER_FdInfo *fdi); |
284 | 289 | ||
285 | /** | 290 | /** |
286 | * Delete a @a task from the set of tasks to be run. | 291 | * Delete a @a task from the set of tasks to be run. A task may |
292 | * comprise multiple FdInfo entries previously added with the add | ||
293 | * function. The driver is expected to delete them all. | ||
287 | * | 294 | * |
288 | * @param cls closure | 295 | * @param cls closure |
289 | * @param task task to delete | 296 | * @param task task to delete |
290 | * @param fdi conditions to watch for (must match @e add call) | ||
291 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | 297 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure |
292 | * (i.e. @a task or @a fdi do not match prior @e add call) | 298 | * (i.e. @a task does not match prior @e add call) |
293 | */ | 299 | */ |
294 | int | 300 | int |
295 | (*del)(void *cls, | 301 | (*del)(void *cls, |
296 | struct GNUNET_SCHEDULER_Task *task, | 302 | struct GNUNET_SCHEDULER_Task *task); |
297 | const struct GNUNET_SCHEDULER_FdInfo *fdi); | ||
298 | 303 | ||
299 | /** | 304 | /** |
300 | * Set time at which we definitively want to get a wakeup call. | 305 | * Set time at which we definitively want to get a wakeup call. |
@@ -309,7 +314,10 @@ struct GNUNET_SCHEDULER_Driver | |||
309 | /** | 314 | /** |
310 | * Event loop's "main" function, to be called from | 315 | * Event loop's "main" function, to be called from |
311 | * #GNUNET_SCHEDULER_run_with_driver() to actually | 316 | * #GNUNET_SCHEDULER_run_with_driver() to actually |
312 | * launch the loop. | 317 | * launch the loop. The loop should run as long as |
318 | * tasks (added by the add callback) are available | ||
319 | * OR the wakeup time (added by the set_wakeup | ||
320 | * callback) is not FOREVER. | ||
313 | * | 321 | * |
314 | * @param cls closure | 322 | * @param cls closure |
315 | * @param sh scheduler handle to pass to | 323 | * @param sh scheduler handle to pass to |
@@ -359,7 +367,7 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
359 | * | 367 | * |
360 | * @return NULL on error | 368 | * @return NULL on error |
361 | */ | 369 | */ |
362 | const struct GNUNET_SCHEDULER_Driver * | 370 | struct GNUNET_SCHEDULER_Driver * |
363 | GNUNET_SCHEDULER_driver_select (void); | 371 | GNUNET_SCHEDULER_driver_select (void); |
364 | 372 | ||
365 | 373 | ||
diff --git a/src/util/network.c b/src/util/network.c index 942288613..cf5ef3e00 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -1223,7 +1223,7 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, | |||
1223 | * @return POSIX file descriptor | 1223 | * @return POSIX file descriptor |
1224 | */ | 1224 | */ |
1225 | int | 1225 | int |
1226 | GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) | 1226 | GNUNET_NETWORK_get_fd (const struct GNUNET_NETWORK_Handle *desc) |
1227 | { | 1227 | { |
1228 | return desc->fd; | 1228 | return desc->fd; |
1229 | } | 1229 | } |
@@ -1236,7 +1236,7 @@ GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) | |||
1236 | * @return sockaddr | 1236 | * @return sockaddr |
1237 | */ | 1237 | */ |
1238 | struct sockaddr* | 1238 | struct sockaddr* |
1239 | GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc) | 1239 | GNUNET_NETWORK_get_addr (const struct GNUNET_NETWORK_Handle *desc) |
1240 | { | 1240 | { |
1241 | return desc->addr; | 1241 | return desc->addr; |
1242 | } | 1242 | } |
@@ -1249,7 +1249,7 @@ GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc) | |||
1249 | * @return socklen_t for sockaddr | 1249 | * @return socklen_t for sockaddr |
1250 | */ | 1250 | */ |
1251 | socklen_t | 1251 | socklen_t |
1252 | GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc) | 1252 | GNUNET_NETWORK_get_addrlen (const struct GNUNET_NETWORK_Handle *desc) |
1253 | { | 1253 | { |
1254 | return desc->addrlen; | 1254 | return desc->addrlen; |
1255 | } | 1255 | } |
diff --git a/src/util/program.c b/src/util/program.c index 92a9750f3..233792387 100644 --- a/src/util/program.c +++ b/src/util/program.c | |||
@@ -69,6 +69,16 @@ struct CommandContext | |||
69 | 69 | ||
70 | 70 | ||
71 | /** | 71 | /** |
72 | * task run when the scheduler shuts down | ||
73 | */ | ||
74 | static void | ||
75 | shutdown_task (void *cls) | ||
76 | { | ||
77 | GNUNET_SPEEDUP_stop_ (); | ||
78 | } | ||
79 | |||
80 | |||
81 | /** | ||
72 | * Initial task called by the scheduler for each | 82 | * Initial task called by the scheduler for each |
73 | * program. Runs the program-specific main task. | 83 | * program. Runs the program-specific main task. |
74 | */ | 84 | */ |
@@ -78,6 +88,7 @@ program_main (void *cls) | |||
78 | struct CommandContext *cc = cls; | 88 | struct CommandContext *cc = cls; |
79 | 89 | ||
80 | GNUNET_SPEEDUP_start_(cc->cfg); | 90 | GNUNET_SPEEDUP_start_(cc->cfg); |
91 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
81 | GNUNET_RESOLVER_connect (cc->cfg); | 92 | GNUNET_RESOLVER_connect (cc->cfg); |
82 | cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg); | 93 | cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg); |
83 | } | 94 | } |
@@ -306,7 +317,6 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName, | |||
306 | } | 317 | } |
307 | ret = GNUNET_OK; | 318 | ret = GNUNET_OK; |
308 | cleanup: | 319 | cleanup: |
309 | GNUNET_SPEEDUP_stop_ (); | ||
310 | GNUNET_CONFIGURATION_destroy (cfg); | 320 | GNUNET_CONFIGURATION_destroy (cfg); |
311 | GNUNET_free_non_null (cc.cfgfile); | 321 | GNUNET_free_non_null (cc.cfgfile); |
312 | GNUNET_free (cfg_fn); | 322 | GNUNET_free (cfg_fn); |
diff --git a/src/util/scheduler.c b/src/util/scheduler.c index 4615ecee9..9bd776517 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c | |||
@@ -89,12 +89,6 @@ struct GNUNET_SCHEDULER_Handle | |||
89 | * @deprecated | 89 | * @deprecated |
90 | */ | 90 | */ |
91 | struct GNUNET_NETWORK_FDSet *ws; | 91 | struct GNUNET_NETWORK_FDSet *ws; |
92 | |||
93 | /** | ||
94 | * Driver we used for the event loop. | ||
95 | */ | ||
96 | const struct GNUNET_SCHEDULER_Driver *driver; | ||
97 | |||
98 | }; | 92 | }; |
99 | 93 | ||
100 | 94 | ||
@@ -124,36 +118,40 @@ struct GNUNET_SCHEDULER_Task | |||
124 | void *callback_cls; | 118 | void *callback_cls; |
125 | 119 | ||
126 | /** | 120 | /** |
127 | * Handle to the scheduler's state. | 121 | * Information about which FDs are ready for this task (and why). |
128 | */ | 122 | */ |
129 | const struct GNUNET_SCHEDULER_Handle *sh; | 123 | struct GNUNET_SCHEDULER_FdInfo *fds; |
130 | 124 | ||
131 | /** | 125 | /** |
132 | * Set of file descriptors this task is waiting | 126 | * Storage location used for @e fds if we want to avoid |
133 | * for for reading. Once ready, this is updated | 127 | * a separate malloc() call in the common case that this |
134 | * to reflect the set of file descriptors ready | 128 | * task is only about a single FD. |
135 | * for operation. | ||
136 | */ | 129 | */ |
137 | struct GNUNET_NETWORK_FDSet *read_set; | 130 | struct GNUNET_SCHEDULER_FdInfo fdx; |
138 | 131 | ||
139 | /** | 132 | /** |
140 | * Set of file descriptors this task is waiting for for writing. | 133 | * Size of the @e fds array. |
141 | * Once ready, this is updated to reflect the set of file | ||
142 | * descriptors ready for operation. | ||
143 | */ | 134 | */ |
144 | struct GNUNET_NETWORK_FDSet *write_set; | 135 | unsigned int fds_len; |
145 | 136 | ||
146 | /** | 137 | /** |
147 | * Information about which FDs are ready for this task (and why). | 138 | * if this task is related to multiple FDs this array contains |
139 | * all FdInfo structs that were marked as ready by calling | ||
140 | * #GNUNET_SCHEDULER_task_ready | ||
148 | */ | 141 | */ |
149 | const struct GNUNET_SCHEDULER_FdInfo *fds; | 142 | struct GNUNET_SCHEDULER_FdInfo *ready_fds; |
150 | 143 | ||
151 | /** | 144 | /** |
152 | * Storage location used for @e fds if we want to avoid | 145 | * Size of the @e ready_fds array |
153 | * a separate malloc() call in the common case that this | ||
154 | * task is only about a single FD. | ||
155 | */ | 146 | */ |
156 | struct GNUNET_SCHEDULER_FdInfo fdx; | 147 | unsigned int ready_fds_len; |
148 | |||
149 | /** | ||
150 | * Do we own the network and file handles referenced by the FdInfo | ||
151 | * structs in the fds array. This will only be GNUNET_YES if the | ||
152 | * task was created by the #GNUNET_SCHEDULER_add_select function. | ||
153 | */ | ||
154 | int own_handles; | ||
157 | 155 | ||
158 | /** | 156 | /** |
159 | * Absolute timeout value for the task, or | 157 | * Absolute timeout value for the task, or |
@@ -169,11 +167,6 @@ struct GNUNET_SCHEDULER_Task | |||
169 | #endif | 167 | #endif |
170 | 168 | ||
171 | /** | 169 | /** |
172 | * Size of the @e fds array. | ||
173 | */ | ||
174 | unsigned int fds_len; | ||
175 | |||
176 | /** | ||
177 | * Why is the task ready? Set after task is added to ready queue. | 170 | * Why is the task ready? Set after task is added to ready queue. |
178 | * Initially set to zero. All reasons that have already been | 171 | * Initially set to zero. All reasons that have already been |
179 | * satisfied (i.e. read or write ready) will be set over time. | 172 | * satisfied (i.e. read or write ready) will be set over time. |
@@ -224,11 +217,72 @@ struct GNUNET_SCHEDULER_Task | |||
224 | int num_backtrace_strings; | 217 | int num_backtrace_strings; |
225 | #endif | 218 | #endif |
226 | 219 | ||
220 | }; | ||
221 | |||
227 | 222 | ||
223 | /** | ||
224 | * A struct representing an event the select driver is waiting for | ||
225 | */ | ||
226 | struct Scheduled | ||
227 | { | ||
228 | struct Scheduled *prev; | ||
229 | |||
230 | struct Scheduled *next; | ||
231 | |||
232 | /** | ||
233 | * the task, the event is related to | ||
234 | */ | ||
235 | struct GNUNET_SCHEDULER_Task *task; | ||
236 | |||
237 | /** | ||
238 | * information about the network socket / file descriptor where | ||
239 | * the event is expected to occur | ||
240 | */ | ||
241 | struct GNUNET_SCHEDULER_FdInfo *fdi; | ||
242 | |||
243 | /** | ||
244 | * the event types (multiple event types can be ORed) the select | ||
245 | * driver is expected to wait for | ||
246 | */ | ||
247 | enum GNUNET_SCHEDULER_EventType et; | ||
228 | }; | 248 | }; |
229 | 249 | ||
230 | 250 | ||
231 | /** | 251 | /** |
252 | * Driver context used by GNUNET_SCHEDULER_run | ||
253 | */ | ||
254 | struct DriverContext | ||
255 | { | ||
256 | /** | ||
257 | * the head of a DLL containing information about the events the | ||
258 | * select driver is waiting for | ||
259 | */ | ||
260 | struct Scheduled *scheduled_head; | ||
261 | |||
262 | /** | ||
263 | * the tail of a DLL containing information about the events the | ||
264 | * select driver is waiting for | ||
265 | */ | ||
266 | struct Scheduled *scheduled_tail; | ||
267 | |||
268 | /** | ||
269 | * the time until the select driver will wake up again (after | ||
270 | * calling select) | ||
271 | */ | ||
272 | struct GNUNET_TIME_Relative timeout; | ||
273 | }; | ||
274 | |||
275 | |||
276 | /** | ||
277 | * The driver used for the event loop. Will be handed over to | ||
278 | * the scheduler in #GNUNET_SCHEDULER_run_from_driver(), peristed | ||
279 | * there in this variable for later use in functions like | ||
280 | * #GNUNET_SCHEDULER_add_select(), #add_without_sets() and | ||
281 | * #GNUNET_SCHEDULER_cancel(). | ||
282 | */ | ||
283 | static const struct GNUNET_SCHEDULER_Driver *scheduler_driver; | ||
284 | |||
285 | /** | ||
232 | * Head of list of tasks waiting for an event. | 286 | * Head of list of tasks waiting for an event. |
233 | */ | 287 | */ |
234 | static struct GNUNET_SCHEDULER_Task *pending_head; | 288 | static struct GNUNET_SCHEDULER_Task *pending_head; |
@@ -330,6 +384,11 @@ static struct GNUNET_SCHEDULER_TaskContext tc; | |||
330 | */ | 384 | */ |
331 | static void *scheduler_select_cls; | 385 | static void *scheduler_select_cls; |
332 | 386 | ||
387 | /** | ||
388 | * Scheduler handle used for the driver functions | ||
389 | */ | ||
390 | static struct GNUNET_SCHEDULER_Handle sh; | ||
391 | |||
333 | 392 | ||
334 | /** | 393 | /** |
335 | * Sets the select function to use in the scheduler (scheduler_select). | 394 | * Sets the select function to use in the scheduler (scheduler_select). |
@@ -364,115 +423,44 @@ check_priority (enum GNUNET_SCHEDULER_Priority p) | |||
364 | 423 | ||
365 | 424 | ||
366 | /** | 425 | /** |
367 | * Update all sets and timeout for select. | 426 | * chooses the nearest timeout from all pending tasks, to be used |
368 | * | 427 | * to tell the driver the next wakeup time (using its set_wakeup |
369 | * @param rs read-set, set to all FDs we would like to read (updated) | 428 | * callback) |
370 | * @param ws write-set, set to all FDs we would like to write (updated) | ||
371 | * @param timeout next timeout (updated) | ||
372 | */ | 429 | */ |
373 | static void | 430 | struct GNUNET_TIME_Absolute |
374 | update_sets (struct GNUNET_NETWORK_FDSet *rs, | 431 | get_timeout () |
375 | struct GNUNET_NETWORK_FDSet *ws, | ||
376 | struct GNUNET_TIME_Relative *timeout) | ||
377 | { | 432 | { |
378 | struct GNUNET_SCHEDULER_Task *pos; | 433 | struct GNUNET_SCHEDULER_Task *pos; |
379 | struct GNUNET_TIME_Absolute now; | 434 | struct GNUNET_TIME_Absolute now; |
380 | struct GNUNET_TIME_Relative to; | 435 | struct GNUNET_TIME_Absolute timeout; |
381 | 436 | ||
382 | now = GNUNET_TIME_absolute_get (); | ||
383 | pos = pending_timeout_head; | 437 | pos = pending_timeout_head; |
438 | now = GNUNET_TIME_absolute_get (); | ||
439 | timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
384 | if (NULL != pos) | 440 | if (NULL != pos) |
385 | { | 441 | { |
386 | to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); | ||
387 | if (timeout->rel_value_us > to.rel_value_us) | ||
388 | *timeout = to; | ||
389 | if (0 != pos->reason) | 442 | if (0 != pos->reason) |
390 | *timeout = GNUNET_TIME_UNIT_ZERO; | 443 | { |
444 | timeout = now; | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | timeout = pos->timeout; | ||
449 | } | ||
391 | } | 450 | } |
392 | for (pos = pending_head; NULL != pos; pos = pos->next) | 451 | for (pos = pending_head; NULL != pos; pos = pos->next) |
393 | { | 452 | { |
394 | if (pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) | 453 | if (0 != pos->reason) |
395 | { | 454 | { |
396 | to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); | 455 | timeout = now; |
397 | if (timeout->rel_value_us > to.rel_value_us) | 456 | } |
398 | *timeout = to; | 457 | else if ((pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) && |
458 | (timeout.abs_value_us > pos->timeout.abs_value_us)) | ||
459 | { | ||
460 | timeout = pos->timeout; | ||
399 | } | 461 | } |
400 | if (-1 != pos->read_fd) | ||
401 | GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); | ||
402 | if (-1 != pos->write_fd) | ||
403 | GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); | ||
404 | if (NULL != pos->read_set) | ||
405 | GNUNET_NETWORK_fdset_add (rs, pos->read_set); | ||
406 | if (NULL != pos->write_set) | ||
407 | GNUNET_NETWORK_fdset_add (ws, pos->write_set); | ||
408 | if (0 != pos->reason) | ||
409 | *timeout = GNUNET_TIME_UNIT_ZERO; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | |||
414 | /** | ||
415 | * Check if the ready set overlaps with the set we want to have ready. | ||
416 | * If so, update the want set (set all FDs that are ready). If not, | ||
417 | * return #GNUNET_NO. | ||
418 | * | ||
419 | * @param ready set that is ready | ||
420 | * @param want set that we want to be ready | ||
421 | * @return #GNUNET_YES if there was some overlap | ||
422 | */ | ||
423 | static int | ||
424 | set_overlaps (const struct GNUNET_NETWORK_FDSet *ready, | ||
425 | struct GNUNET_NETWORK_FDSet *want) | ||
426 | { | ||
427 | if ((NULL == want) || (NULL == ready)) | ||
428 | return GNUNET_NO; | ||
429 | if (GNUNET_NETWORK_fdset_overlap (ready, want)) | ||
430 | { | ||
431 | /* copy all over (yes, there maybe unrelated bits, | ||
432 | * but this should not hurt well-written clients) */ | ||
433 | GNUNET_NETWORK_fdset_copy (want, ready); | ||
434 | return GNUNET_YES; | ||
435 | } | 462 | } |
436 | return GNUNET_NO; | 463 | return timeout; |
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
441 | * Check if the given task is eligible to run now. | ||
442 | * Also set the reason why it is eligible. | ||
443 | * | ||
444 | * @param task task to check if it is ready | ||
445 | * @param now the current time | ||
446 | * @param rs set of FDs ready for reading | ||
447 | * @param ws set of FDs ready for writing | ||
448 | * @return #GNUNET_YES if we can run it, #GNUNET_NO if not. | ||
449 | */ | ||
450 | static int | ||
451 | is_ready (struct GNUNET_SCHEDULER_Task *task, | ||
452 | struct GNUNET_TIME_Absolute now, | ||
453 | const struct GNUNET_NETWORK_FDSet *rs, | ||
454 | const struct GNUNET_NETWORK_FDSet *ws) | ||
455 | { | ||
456 | enum GNUNET_SCHEDULER_Reason reason; | ||
457 | |||
458 | reason = task->reason; | ||
459 | if (now.abs_value_us >= task->timeout.abs_value_us) | ||
460 | reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | ||
461 | if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && | ||
462 | (((task->read_fd != -1) && | ||
463 | (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, task->read_fd))) || | ||
464 | (set_overlaps (rs, task->read_set)))) | ||
465 | reason |= GNUNET_SCHEDULER_REASON_READ_READY; | ||
466 | if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | ||
467 | (((task->write_fd != -1) && | ||
468 | (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, task->write_fd))) | ||
469 | || (set_overlaps (ws, task->write_set)))) | ||
470 | reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; | ||
471 | if (0 == reason) | ||
472 | return GNUNET_NO; /* not ready */ | ||
473 | reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; | ||
474 | task->reason = reason; | ||
475 | return GNUNET_YES; | ||
476 | } | 464 | } |
477 | 465 | ||
478 | 466 | ||
@@ -495,51 +483,6 @@ queue_ready_task (struct GNUNET_SCHEDULER_Task *task) | |||
495 | 483 | ||
496 | 484 | ||
497 | /** | 485 | /** |
498 | * Check which tasks are ready and move them | ||
499 | * to the respective ready queue. | ||
500 | * | ||
501 | * @param rs FDs ready for reading | ||
502 | * @param ws FDs ready for writing | ||
503 | */ | ||
504 | static void | ||
505 | check_ready (const struct GNUNET_NETWORK_FDSet *rs, | ||
506 | const struct GNUNET_NETWORK_FDSet *ws) | ||
507 | { | ||
508 | struct GNUNET_SCHEDULER_Task *pos; | ||
509 | struct GNUNET_SCHEDULER_Task *next; | ||
510 | struct GNUNET_TIME_Absolute now; | ||
511 | |||
512 | now = GNUNET_TIME_absolute_get (); | ||
513 | while (NULL != (pos = pending_timeout_head)) | ||
514 | { | ||
515 | if (now.abs_value_us >= pos->timeout.abs_value_us) | ||
516 | pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | ||
517 | if (0 == pos->reason) | ||
518 | break; | ||
519 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
520 | pending_timeout_tail, | ||
521 | pos); | ||
522 | if (pending_timeout_last == pos) | ||
523 | pending_timeout_last = NULL; | ||
524 | queue_ready_task (pos); | ||
525 | } | ||
526 | pos = pending_head; | ||
527 | while (NULL != pos) | ||
528 | { | ||
529 | next = pos->next; | ||
530 | if (GNUNET_YES == is_ready (pos, now, rs, ws)) | ||
531 | { | ||
532 | GNUNET_CONTAINER_DLL_remove (pending_head, | ||
533 | pending_tail, | ||
534 | pos); | ||
535 | queue_ready_task (pos); | ||
536 | } | ||
537 | pos = next; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | |||
542 | /** | ||
543 | * Request the shutdown of a scheduler. Marks all tasks | 486 | * Request the shutdown of a scheduler. Marks all tasks |
544 | * awaiting shutdown as ready. Note that tasks | 487 | * awaiting shutdown as ready. Note that tasks |
545 | * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call | 488 | * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call |
@@ -562,25 +505,6 @@ GNUNET_SCHEDULER_shutdown () | |||
562 | 505 | ||
563 | 506 | ||
564 | /** | 507 | /** |
565 | * Destroy a task (release associated resources) | ||
566 | * | ||
567 | * @param t task to destroy | ||
568 | */ | ||
569 | static void | ||
570 | destroy_task (struct GNUNET_SCHEDULER_Task *t) | ||
571 | { | ||
572 | if (NULL != t->read_set) | ||
573 | GNUNET_NETWORK_fdset_destroy (t->read_set); | ||
574 | if (NULL != t->write_set) | ||
575 | GNUNET_NETWORK_fdset_destroy (t->write_set); | ||
576 | #if EXECINFO | ||
577 | GNUNET_free (t->backtrace_strings); | ||
578 | #endif | ||
579 | GNUNET_free (t); | ||
580 | } | ||
581 | |||
582 | |||
583 | /** | ||
584 | * Output stack trace of task @a t. | 508 | * Output stack trace of task @a t. |
585 | * | 509 | * |
586 | * @param t task to dump stack trace of | 510 | * @param t task to dump stack trace of |
@@ -589,89 +513,62 @@ static void | |||
589 | dump_backtrace (struct GNUNET_SCHEDULER_Task *t) | 513 | dump_backtrace (struct GNUNET_SCHEDULER_Task *t) |
590 | { | 514 | { |
591 | #if EXECINFO | 515 | #if EXECINFO |
592 | for (unsigned int i = 0; i < t->num_backtrace_strings; i++) | 516 | unsigned int i; |
593 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 517 | |
594 | "Task %p trace %u: %s\n", | 518 | for (i = 0; i < t->num_backtrace_strings; i++) |
595 | t, | 519 | LOG (GNUNET_ERROR_TYPE_WARNING, |
596 | i, | 520 | "Task %p trace %u: %s\n", |
597 | t->backtrace_strings[i]); | 521 | t, |
522 | i, | ||
523 | t->backtrace_strings[i]); | ||
598 | #endif | 524 | #endif |
599 | } | 525 | } |
600 | 526 | ||
601 | 527 | ||
602 | /** | 528 | /** |
603 | * Run at least one task in the highest-priority queue that is not | 529 | * Destroy a task (release associated resources) |
604 | * empty. Keep running tasks until we are either no longer running | ||
605 | * "URGENT" tasks or until we have at least one "pending" task (which | ||
606 | * may become ready, hence we should select on it). Naturally, if | ||
607 | * there are no more ready tasks, we also return. | ||
608 | * | 530 | * |
609 | * @param rs FDs ready for reading | 531 | * @param t task to destroy |
610 | * @param ws FDs ready for writing | ||
611 | */ | 532 | */ |
612 | static void | 533 | static void |
613 | run_ready (struct GNUNET_NETWORK_FDSet *rs, | 534 | destroy_task (struct GNUNET_SCHEDULER_Task *t) |
614 | struct GNUNET_NETWORK_FDSet *ws) | ||
615 | { | 535 | { |
616 | enum GNUNET_SCHEDULER_Priority p; | 536 | unsigned int i; |
617 | struct GNUNET_SCHEDULER_Task *pos; | ||
618 | 537 | ||
619 | max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; | 538 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
620 | do | 539 | "destroying task %p\n", |
540 | t); | ||
541 | |||
542 | if (GNUNET_YES == t->own_handles) | ||
621 | { | 543 | { |
622 | if (0 == ready_count) | 544 | for (i = 0; i != t->fds_len; ++i) |
623 | return; | ||
624 | GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]); | ||
625 | /* yes, p>0 is correct, 0 is "KEEP" which should | ||
626 | * always be an empty queue (see assertion)! */ | ||
627 | for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) | ||
628 | { | ||
629 | pos = ready_head[p]; | ||
630 | if (NULL != pos) | ||
631 | break; | ||
632 | } | ||
633 | GNUNET_assert (NULL != pos); /* ready_count wrong? */ | ||
634 | GNUNET_CONTAINER_DLL_remove (ready_head[p], | ||
635 | ready_tail[p], | ||
636 | pos); | ||
637 | ready_count--; | ||
638 | current_priority = pos->priority; | ||
639 | current_lifeness = pos->lifeness; | ||
640 | active_task = pos; | ||
641 | #if PROFILE_DELAYS | ||
642 | if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > | ||
643 | DELAY_THRESHOLD.rel_value_us) | ||
644 | { | 545 | { |
645 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 546 | const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd; |
646 | "Task %p took %s to be scheduled\n", | 547 | const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh; |
647 | pos, | 548 | if (fd) |
648 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), | 549 | { |
649 | GNUNET_YES)); | 550 | GNUNET_NETWORK_socket_free_memory_only_ ((struct GNUNET_NETWORK_Handle *) fd); |
551 | } | ||
552 | if (fh) | ||
553 | { | ||
554 | // FIXME: on WIN32 this is not enough! A function | ||
555 | // GNUNET_DISK_file_free_memory_only would be nice | ||
556 | GNUNET_free ((void *) fh); | ||
557 | } | ||
650 | } | 558 | } |
651 | #endif | ||
652 | tc.reason = pos->reason; | ||
653 | tc.read_ready = (NULL == pos->read_set) ? rs : pos->read_set; | ||
654 | if ((-1 != pos->read_fd) && | ||
655 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY))) | ||
656 | GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); | ||
657 | tc.write_ready = (NULL == pos->write_set) ? ws : pos->write_set; | ||
658 | if ((-1 != pos->write_fd) && | ||
659 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) | ||
660 | GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); | ||
661 | if ((0 != (tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | ||
662 | (-1 != pos->write_fd) && | ||
663 | (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd))) | ||
664 | GNUNET_assert (0); // added to ready in previous select loop! | ||
665 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
666 | "Running task: %p\n", | ||
667 | pos); | ||
668 | pos->callback (pos->callback_cls); | ||
669 | dump_backtrace (pos); | ||
670 | active_task = NULL; | ||
671 | destroy_task (pos); | ||
672 | tasks_run++; | ||
673 | } | 559 | } |
674 | while ((NULL == pending_head) || (p >= max_priority_added)); | 560 | if (t->fds_len > 1) |
561 | { | ||
562 | GNUNET_array_grow (t->fds, t->fds_len, 0); | ||
563 | } | ||
564 | if (t->ready_fds_len > 0) | ||
565 | { | ||
566 | GNUNET_array_grow (t->ready_fds, t->ready_fds_len, 0); | ||
567 | } | ||
568 | #if EXECINFO | ||
569 | GNUNET_free (t->backtrace_strings); | ||
570 | #endif | ||
571 | GNUNET_free (t); | ||
675 | } | 572 | } |
676 | 573 | ||
677 | 574 | ||
@@ -698,22 +595,22 @@ sighandler_pipe () | |||
698 | #endif | 595 | #endif |
699 | 596 | ||
700 | 597 | ||
701 | /** | 598 | ///** |
702 | * Wait for a short time. | 599 | // * Wait for a short time. |
703 | * Sleeps for @a ms ms (as that should be long enough for virtually all | 600 | // * Sleeps for @a ms ms (as that should be long enough for virtually all |
704 | * modern systems to context switch and allow another process to do | 601 | // * modern systems to context switch and allow another process to do |
705 | * some 'real' work). | 602 | // * some 'real' work). |
706 | * | 603 | // * |
707 | * @param ms how many ms to wait | 604 | // * @param ms how many ms to wait |
708 | */ | 605 | // */ |
709 | static void | 606 | //static void |
710 | short_wait (unsigned int ms) | 607 | //short_wait (unsigned int ms) |
711 | { | 608 | //{ |
712 | struct GNUNET_TIME_Relative timeout; | 609 | // struct GNUNET_TIME_Relative timeout; |
713 | 610 | // | |
714 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms); | 611 | // timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms); |
715 | (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout); | 612 | // (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout); |
716 | } | 613 | //} |
717 | 614 | ||
718 | 615 | ||
719 | /** | 616 | /** |
@@ -735,35 +632,31 @@ sighandler_shutdown () | |||
735 | } | 632 | } |
736 | 633 | ||
737 | 634 | ||
738 | /** | 635 | void |
739 | * Check if the system is still alive. Trigger shutdown if we | 636 | shutdown_if_no_lifeness () |
740 | * have tasks, but none of them give us lifeness. | ||
741 | * | ||
742 | * @return #GNUNET_OK to continue the main loop, | ||
743 | * #GNUNET_NO to exit | ||
744 | */ | ||
745 | static int | ||
746 | check_lifeness () | ||
747 | { | 637 | { |
748 | struct GNUNET_SCHEDULER_Task *t; | 638 | struct GNUNET_SCHEDULER_Task *t; |
749 | 639 | ||
750 | if (ready_count > 0) | 640 | if (ready_count > 0) |
751 | return GNUNET_OK; | 641 | return; |
752 | for (t = pending_head; NULL != t; t = t->next) | 642 | for (t = pending_head; NULL != t; t = t->next) |
753 | if (t->lifeness == GNUNET_YES) | 643 | if (GNUNET_YES == t->lifeness) |
754 | return GNUNET_OK; | 644 | return; |
755 | for (t = shutdown_head; NULL != t; t = t->next) | 645 | for (t = shutdown_head; NULL != t; t = t->next) |
756 | if (t->lifeness == GNUNET_YES) | 646 | if (GNUNET_YES == t->lifeness) |
757 | return GNUNET_OK; | 647 | return; |
758 | for (t = pending_timeout_head; NULL != t; t = t->next) | 648 | for (t = pending_timeout_head; NULL != t; t = t->next) |
759 | if (t->lifeness == GNUNET_YES) | 649 | if (GNUNET_YES == t->lifeness) |
760 | return GNUNET_OK; | 650 | return; |
761 | if (NULL != shutdown_head) | 651 | /* No lifeness! Cancel all pending tasks the driver knows about and shutdown */ |
652 | t = pending_head; | ||
653 | while (NULL != t) | ||
762 | { | 654 | { |
763 | GNUNET_SCHEDULER_shutdown (); | 655 | struct GNUNET_SCHEDULER_Task *next = t->next; |
764 | return GNUNET_OK; | 656 | GNUNET_SCHEDULER_cancel (t); |
657 | t = next; | ||
765 | } | 658 | } |
766 | return GNUNET_NO; | 659 | GNUNET_SCHEDULER_shutdown (); |
767 | } | 660 | } |
768 | 661 | ||
769 | 662 | ||
@@ -785,204 +678,17 @@ void | |||
785 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, | 678 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, |
786 | void *task_cls) | 679 | void *task_cls) |
787 | { | 680 | { |
788 | GNUNET_SCHEDULER_run_with_optional_signals(GNUNET_YES, task, task_cls); | 681 | struct GNUNET_SCHEDULER_Driver *driver; |
789 | } | 682 | struct DriverContext context = {.scheduled_head = NULL, |
790 | 683 | .scheduled_tail = NULL, | |
791 | void | 684 | .timeout = GNUNET_TIME_UNIT_FOREVER_REL}; |
792 | GNUNET_SCHEDULER_run_with_optional_signals (int install_signals, | 685 | |
793 | GNUNET_SCHEDULER_TaskCallback task, | 686 | driver = GNUNET_SCHEDULER_driver_select (); |
794 | void *task_cls) | 687 | driver->cls = &context; |
795 | { | 688 | |
796 | struct GNUNET_NETWORK_FDSet *rs; | 689 | GNUNET_SCHEDULER_run_with_driver (driver, task, task_cls); |
797 | struct GNUNET_NETWORK_FDSet *ws; | 690 | |
798 | struct GNUNET_TIME_Relative timeout; | 691 | GNUNET_free (driver); |
799 | int ret; | ||
800 | struct GNUNET_SIGNAL_Context *shc_int; | ||
801 | struct GNUNET_SIGNAL_Context *shc_term; | ||
802 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
803 | struct GNUNET_SIGNAL_Context *shc_gterm; | ||
804 | #endif | ||
805 | |||
806 | #ifndef MINGW | ||
807 | struct GNUNET_SIGNAL_Context *shc_quit; | ||
808 | struct GNUNET_SIGNAL_Context *shc_hup; | ||
809 | struct GNUNET_SIGNAL_Context *shc_pipe; | ||
810 | #endif | ||
811 | unsigned long long last_tr; | ||
812 | unsigned int busy_wait_warning; | ||
813 | const struct GNUNET_DISK_FileHandle *pr; | ||
814 | char c; | ||
815 | |||
816 | GNUNET_assert (NULL == active_task); | ||
817 | rs = GNUNET_NETWORK_fdset_create (); | ||
818 | ws = GNUNET_NETWORK_fdset_create (); | ||
819 | GNUNET_assert (NULL == shutdown_pipe_handle); | ||
820 | shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, | ||
821 | GNUNET_NO, | ||
822 | GNUNET_NO, | ||
823 | GNUNET_NO); | ||
824 | GNUNET_assert (NULL != shutdown_pipe_handle); | ||
825 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | ||
826 | GNUNET_DISK_PIPE_END_READ); | ||
827 | GNUNET_assert (NULL != pr); | ||
828 | my_pid = getpid (); | ||
829 | |||
830 | if (GNUNET_YES == install_signals) | ||
831 | { | ||
832 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
833 | "Registering signal handlers\n"); | ||
834 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, | ||
835 | &sighandler_shutdown); | ||
836 | shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, | ||
837 | &sighandler_shutdown); | ||
838 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
839 | shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, | ||
840 | &sighandler_shutdown); | ||
841 | #endif | ||
842 | #ifndef MINGW | ||
843 | shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, | ||
844 | &sighandler_pipe); | ||
845 | shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, | ||
846 | &sighandler_shutdown); | ||
847 | shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, | ||
848 | &sighandler_shutdown); | ||
849 | #endif | ||
850 | } | ||
851 | |||
852 | current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; | ||
853 | current_lifeness = GNUNET_YES; | ||
854 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, | ||
855 | task_cls, | ||
856 | GNUNET_SCHEDULER_REASON_STARTUP, | ||
857 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); | ||
858 | active_task = (void *) (long) -1; /* force passing of sanity check */ | ||
859 | GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, | ||
860 | &GNUNET_OS_install_parent_control_handler, | ||
861 | NULL); | ||
862 | active_task = NULL; | ||
863 | last_tr = 0; | ||
864 | busy_wait_warning = 0; | ||
865 | while (GNUNET_OK == check_lifeness ()) | ||
866 | { | ||
867 | GNUNET_NETWORK_fdset_zero (rs); | ||
868 | GNUNET_NETWORK_fdset_zero (ws); | ||
869 | timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
870 | update_sets (rs, ws, &timeout); | ||
871 | GNUNET_NETWORK_fdset_handle_set (rs, pr); | ||
872 | if (ready_count > 0) | ||
873 | { | ||
874 | /* no blocking, more work already ready! */ | ||
875 | timeout = GNUNET_TIME_UNIT_ZERO; | ||
876 | } | ||
877 | if (NULL == scheduler_select) | ||
878 | ret = GNUNET_NETWORK_socket_select (rs, | ||
879 | ws, | ||
880 | NULL, | ||
881 | timeout); | ||
882 | else | ||
883 | ret = scheduler_select (scheduler_select_cls, | ||
884 | rs, | ||
885 | ws, | ||
886 | NULL, | ||
887 | timeout); | ||
888 | if (ret == GNUNET_SYSERR) | ||
889 | { | ||
890 | if (errno == EINTR) | ||
891 | continue; | ||
892 | |||
893 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); | ||
894 | #ifndef MINGW | ||
895 | #if USE_LSOF | ||
896 | char lsof[512]; | ||
897 | |||
898 | snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); | ||
899 | (void) close (1); | ||
900 | (void) dup2 (2, 1); | ||
901 | if (0 != system (lsof)) | ||
902 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
903 | "system"); | ||
904 | #endif | ||
905 | #endif | ||
906 | #if DEBUG_FDS | ||
907 | struct GNUNET_SCHEDULER_Task *t; | ||
908 | |||
909 | for (t = pending_head; NULL != t; t = t->next) | ||
910 | { | ||
911 | if (-1 != t->read_fd) | ||
912 | { | ||
913 | int flags = fcntl (t->read_fd, F_GETFD); | ||
914 | if ((flags == -1) && (errno == EBADF)) | ||
915 | { | ||
916 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
917 | "Got invalid file descriptor %d!\n", | ||
918 | t->read_fd); | ||
919 | dump_backtrace (t); | ||
920 | } | ||
921 | } | ||
922 | if (-1 != t->write_fd) | ||
923 | { | ||
924 | int flags = fcntl (t->write_fd, F_GETFD); | ||
925 | if ((flags == -1) && (errno == EBADF)) | ||
926 | { | ||
927 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
928 | "Got invalid file descriptor %d!\n", | ||
929 | t->write_fd); | ||
930 | dump_backtrace (t); | ||
931 | } | ||
932 | } | ||
933 | } | ||
934 | #endif | ||
935 | GNUNET_assert (0); | ||
936 | break; | ||
937 | } | ||
938 | |||
939 | if ( (0 == ret) && | ||
940 | (0 == timeout.rel_value_us) && | ||
941 | (busy_wait_warning > 16) ) | ||
942 | { | ||
943 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
944 | "Looks like we're busy waiting...\n"); | ||
945 | short_wait (100); /* mitigate */ | ||
946 | } | ||
947 | check_ready (rs, ws); | ||
948 | run_ready (rs, ws); | ||
949 | if (GNUNET_NETWORK_fdset_handle_isset (rs, pr)) | ||
950 | { | ||
951 | /* consume the signal */ | ||
952 | GNUNET_DISK_file_read (pr, &c, sizeof (c)); | ||
953 | /* mark all active tasks as ready due to shutdown */ | ||
954 | GNUNET_SCHEDULER_shutdown (); | ||
955 | } | ||
956 | if (last_tr == tasks_run) | ||
957 | { | ||
958 | short_wait (1); | ||
959 | busy_wait_warning++; | ||
960 | } | ||
961 | else | ||
962 | { | ||
963 | last_tr = tasks_run; | ||
964 | busy_wait_warning = 0; | ||
965 | } | ||
966 | } | ||
967 | |||
968 | if (GNUNET_YES == install_signals) | ||
969 | { | ||
970 | GNUNET_SIGNAL_handler_uninstall (shc_int); | ||
971 | GNUNET_SIGNAL_handler_uninstall (shc_term); | ||
972 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
973 | GNUNET_SIGNAL_handler_uninstall (shc_gterm); | ||
974 | #endif | ||
975 | #ifndef MINGW | ||
976 | GNUNET_SIGNAL_handler_uninstall (shc_pipe); | ||
977 | GNUNET_SIGNAL_handler_uninstall (shc_quit); | ||
978 | GNUNET_SIGNAL_handler_uninstall (shc_hup); | ||
979 | #endif | ||
980 | } | ||
981 | |||
982 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); | ||
983 | shutdown_pipe_handle = NULL; | ||
984 | GNUNET_NETWORK_fdset_destroy (rs); | ||
985 | GNUNET_NETWORK_fdset_destroy (ws); | ||
986 | } | 692 | } |
987 | 693 | ||
988 | 694 | ||
@@ -1027,9 +733,164 @@ GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p) | |||
1027 | } | 733 | } |
1028 | 734 | ||
1029 | 735 | ||
736 | void | ||
737 | init_fd_info (struct GNUNET_SCHEDULER_Task *t, | ||
738 | const struct GNUNET_NETWORK_Handle *const *read_nh, | ||
739 | unsigned int read_nh_len, | ||
740 | const struct GNUNET_NETWORK_Handle *const *write_nh, | ||
741 | unsigned int write_nh_len, | ||
742 | const struct GNUNET_DISK_FileHandle *const *read_fh, | ||
743 | unsigned int read_fh_len, | ||
744 | const struct GNUNET_DISK_FileHandle *const *write_fh, | ||
745 | unsigned int write_fh_len) | ||
746 | { | ||
747 | // FIXME: if we have exactly two network handles / exactly two file handles | ||
748 | // and they are equal, we can make one FdInfo with both | ||
749 | // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set. | ||
750 | struct GNUNET_SCHEDULER_FdInfo *fdi; | ||
751 | |||
752 | t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len; | ||
753 | if (1 == t->fds_len) | ||
754 | { | ||
755 | fdi = &t->fdx; | ||
756 | t->fds = fdi; | ||
757 | if (1 == read_nh_len) | ||
758 | { | ||
759 | fdi->fd = *read_nh; | ||
760 | GNUNET_assert (NULL != fdi->fd); | ||
761 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
762 | fdi->sock = GNUNET_NETWORK_get_fd (*read_nh); | ||
763 | t->read_fd = fdi->sock; | ||
764 | t->write_fd = -1; | ||
765 | } | ||
766 | else if (1 == write_nh_len) | ||
767 | { | ||
768 | fdi->fd = *write_nh; | ||
769 | GNUNET_assert (NULL != fdi->fd); | ||
770 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
771 | fdi->sock = GNUNET_NETWORK_get_fd (*write_nh); | ||
772 | t->read_fd = -1; | ||
773 | t->write_fd = fdi->sock; | ||
774 | } | ||
775 | else if (1 == read_fh_len) | ||
776 | { | ||
777 | fdi->fh = *read_fh; | ||
778 | GNUNET_assert (NULL != fdi->fh); | ||
779 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
780 | fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32 | ||
781 | t->read_fd = fdi->sock; | ||
782 | t->write_fd = -1; | ||
783 | } | ||
784 | else | ||
785 | { | ||
786 | fdi->fh = *write_fh; | ||
787 | GNUNET_assert (NULL != fdi->fh); | ||
788 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
789 | fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32 | ||
790 | t->read_fd = -1; | ||
791 | t->write_fd = fdi->sock; | ||
792 | } | ||
793 | } | ||
794 | else | ||
795 | { | ||
796 | fdi = GNUNET_new_array (t->fds_len, struct GNUNET_SCHEDULER_FdInfo); | ||
797 | t->fds = fdi; | ||
798 | t->read_fd = -1; | ||
799 | t->write_fd = -1; | ||
800 | unsigned int i; | ||
801 | for (i = 0; i != read_nh_len; ++i) | ||
802 | { | ||
803 | fdi->fd = read_nh[i]; | ||
804 | GNUNET_assert (NULL != fdi->fd); | ||
805 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
806 | fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]); | ||
807 | ++fdi; | ||
808 | } | ||
809 | for (i = 0; i != write_nh_len; ++i) | ||
810 | { | ||
811 | fdi->fd = write_nh[i]; | ||
812 | GNUNET_assert (NULL != fdi->fd); | ||
813 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
814 | fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]); | ||
815 | ++fdi; | ||
816 | } | ||
817 | for (i = 0; i != read_fh_len; ++i) | ||
818 | { | ||
819 | fdi->fh = read_fh[i]; | ||
820 | GNUNET_assert (NULL != fdi->fh); | ||
821 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
822 | fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32 | ||
823 | ++fdi; | ||
824 | } | ||
825 | for (i = 0; i != write_fh_len; ++i) | ||
826 | { | ||
827 | fdi->fh = write_fh[i]; | ||
828 | GNUNET_assert (NULL != fdi->fh); | ||
829 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
830 | fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32 | ||
831 | ++fdi; | ||
832 | } | ||
833 | } | ||
834 | } | ||
835 | |||
836 | |||
837 | /** | ||
838 | * calls the given function @a func on each FdInfo related to @a t. | ||
839 | * Optionally updates the event type field in each FdInfo after calling | ||
840 | * @a func. | ||
841 | * | ||
842 | * @param t the task | ||
843 | * @param driver_func the function to call with each FdInfo contained in | ||
844 | * in @a t | ||
845 | * @param if_not_ready only call @a driver_func on FdInfos that are not | ||
846 | * ready | ||
847 | * @param et the event type to be set in each FdInfo after calling | ||
848 | * @a driver_func on it, or -1 if no updating not desired. | ||
849 | */ | ||
850 | void driver_add_multiple (struct GNUNET_SCHEDULER_Task *t, | ||
851 | enum GNUNET_SCHEDULER_EventType et) | ||
852 | { | ||
853 | struct GNUNET_SCHEDULER_FdInfo *fdi; | ||
854 | int success = GNUNET_YES; | ||
855 | |||
856 | for (int i = 0; i != t->fds_len; ++i) | ||
857 | { | ||
858 | fdi = &t->fds[i]; | ||
859 | success = scheduler_driver->add (scheduler_driver->cls, t, fdi) && success; | ||
860 | if (et != -1) | ||
861 | { | ||
862 | fdi->et = et; | ||
863 | } | ||
864 | } | ||
865 | if (GNUNET_YES != success) | ||
866 | { | ||
867 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
868 | "driver could not add task\n"); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | |||
873 | void | ||
874 | shutdown_cb (void *cls) | ||
875 | { | ||
876 | char c; | ||
877 | const struct GNUNET_DISK_FileHandle *pr; | ||
878 | |||
879 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | ||
880 | GNUNET_DISK_PIPE_END_READ); | ||
881 | GNUNET_assert (! GNUNET_DISK_handle_invalid (pr)); | ||
882 | /* consume the signal */ | ||
883 | GNUNET_DISK_file_read (pr, &c, sizeof (c)); | ||
884 | /* mark all active tasks as ready due to shutdown */ | ||
885 | GNUNET_SCHEDULER_shutdown (); | ||
886 | } | ||
887 | |||
888 | |||
1030 | /** | 889 | /** |
1031 | * Cancel the task with the specified identifier. | 890 | * Cancel the task with the specified identifier. |
1032 | * The task must not yet have run. | 891 | * The task must not yet have run. Only allowed to be called as long as the |
892 | * scheduler is running (#GNUNET_SCHEDULER_run or | ||
893 | * #GNUNET_SCHEDULER_run_with_driver has been called and has not returned yet). | ||
1033 | * | 894 | * |
1034 | * @param task id of the task to cancel | 895 | * @param task id of the task to cancel |
1035 | * @return original closure of the task | 896 | * @return original closure of the task |
@@ -1038,34 +899,50 @@ void * | |||
1038 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) | 899 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) |
1039 | { | 900 | { |
1040 | enum GNUNET_SCHEDULER_Priority p; | 901 | enum GNUNET_SCHEDULER_Priority p; |
902 | int is_fd_task; | ||
1041 | void *ret; | 903 | void *ret; |
1042 | 904 | ||
905 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
906 | "canceling task %p\n", | ||
907 | task); | ||
908 | |||
909 | /* scheduler must be running */ | ||
910 | GNUNET_assert (NULL != scheduler_driver); | ||
1043 | GNUNET_assert ( (NULL != active_task) || | 911 | GNUNET_assert ( (NULL != active_task) || |
1044 | (GNUNET_NO == task->lifeness) ); | 912 | (GNUNET_NO == task->lifeness) ); |
1045 | if (! task->in_ready_list) | 913 | is_fd_task = (NULL != task->fds); |
914 | if (is_fd_task) | ||
1046 | { | 915 | { |
1047 | if ( (-1 == task->read_fd) && | 916 | int del_result = scheduler_driver->del (scheduler_driver->cls, task); |
1048 | (-1 == task->write_fd) && | 917 | if (GNUNET_OK != del_result) |
1049 | (NULL == task->read_set) && | ||
1050 | (NULL == task->write_set) ) | ||
1051 | { | 918 | { |
1052 | if (GNUNET_YES == task->on_shutdown) | 919 | LOG (GNUNET_ERROR_TYPE_ERROR, |
1053 | GNUNET_CONTAINER_DLL_remove (shutdown_head, | 920 | "driver could not delete task\n"); |
1054 | shutdown_tail, | 921 | GNUNET_assert (0); |
1055 | task); | ||
1056 | else | ||
1057 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
1058 | pending_timeout_tail, | ||
1059 | task); | ||
1060 | if (task == pending_timeout_last) | ||
1061 | pending_timeout_last = NULL; | ||
1062 | } | 922 | } |
1063 | else | 923 | } |
924 | if (! task->in_ready_list) | ||
925 | { | ||
926 | if (is_fd_task) | ||
1064 | { | 927 | { |
1065 | GNUNET_CONTAINER_DLL_remove (pending_head, | 928 | GNUNET_CONTAINER_DLL_remove (pending_head, |
1066 | pending_tail, | 929 | pending_tail, |
1067 | task); | 930 | task); |
1068 | } | 931 | } |
932 | else if (GNUNET_YES == task->on_shutdown) | ||
933 | { | ||
934 | GNUNET_CONTAINER_DLL_remove (shutdown_head, | ||
935 | shutdown_tail, | ||
936 | task); | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
941 | pending_timeout_tail, | ||
942 | task); | ||
943 | if (pending_timeout_last == task) | ||
944 | pending_timeout_last = NULL; | ||
945 | } | ||
1069 | } | 946 | } |
1070 | else | 947 | else |
1071 | { | 948 | { |
@@ -1076,9 +953,6 @@ GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) | |||
1076 | ready_count--; | 953 | ready_count--; |
1077 | } | 954 | } |
1078 | ret = task->callback_cls; | 955 | ret = task->callback_cls; |
1079 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1080 | "Canceling task %p\n", | ||
1081 | task); | ||
1082 | destroy_task (task); | 956 | destroy_task (task); |
1083 | return ret; | 957 | return ret; |
1084 | } | 958 | } |
@@ -1099,7 +973,7 @@ init_backtrace (struct GNUNET_SCHEDULER_Task *t) | |||
1099 | = backtrace (backtrace_array, MAX_TRACE_DEPTH); | 973 | = backtrace (backtrace_array, MAX_TRACE_DEPTH); |
1100 | t->backtrace_strings = | 974 | t->backtrace_strings = |
1101 | backtrace_symbols (backtrace_array, | 975 | backtrace_symbols (backtrace_array, |
1102 | t->num_backtrace_strings); | 976 | t->num_backtrace_strings); |
1103 | dump_backtrace (t); | 977 | dump_backtrace (t); |
1104 | #endif | 978 | #endif |
1105 | } | 979 | } |
@@ -1216,7 +1090,7 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at, | |||
1216 | pending_timeout_last = t; | 1090 | pending_timeout_last = t; |
1217 | 1091 | ||
1218 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1092 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1219 | "Adding task: %p\n", | 1093 | "Adding task %p\n", |
1220 | t); | 1094 | t); |
1221 | init_backtrace (t); | 1095 | init_backtrace (t); |
1222 | return t; | 1096 | return t; |
@@ -1236,8 +1110,8 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at, | |||
1236 | */ | 1110 | */ |
1237 | struct GNUNET_SCHEDULER_Task * | 1111 | struct GNUNET_SCHEDULER_Task * |
1238 | GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, | 1112 | GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, |
1239 | enum GNUNET_SCHEDULER_Priority priority, | 1113 | enum GNUNET_SCHEDULER_Priority priority, |
1240 | GNUNET_SCHEDULER_TaskCallback task, | 1114 | GNUNET_SCHEDULER_TaskCallback task, |
1241 | void *task_cls) | 1115 | void *task_cls) |
1242 | { | 1116 | { |
1243 | return GNUNET_SCHEDULER_add_at_with_priority (GNUNET_TIME_relative_to_absolute (delay), | 1117 | return GNUNET_SCHEDULER_add_at_with_priority (GNUNET_TIME_relative_to_absolute (delay), |
@@ -1305,12 +1179,12 @@ GNUNET_SCHEDULER_add_at (struct GNUNET_TIME_Absolute at, | |||
1305 | struct GNUNET_SCHEDULER_Task * | 1179 | struct GNUNET_SCHEDULER_Task * |
1306 | GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, | 1180 | GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, |
1307 | GNUNET_SCHEDULER_TaskCallback task, | 1181 | GNUNET_SCHEDULER_TaskCallback task, |
1308 | void *task_cls) | 1182 | void *task_cls) |
1309 | { | 1183 | { |
1310 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, | 1184 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, |
1311 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, | 1185 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, |
1312 | task, | 1186 | task, |
1313 | task_cls); | 1187 | task_cls); |
1314 | } | 1188 | } |
1315 | 1189 | ||
1316 | 1190 | ||
@@ -1331,11 +1205,11 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, | |||
1331 | */ | 1205 | */ |
1332 | struct GNUNET_SCHEDULER_Task * | 1206 | struct GNUNET_SCHEDULER_Task * |
1333 | GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, | 1207 | GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, |
1334 | void *task_cls) | 1208 | void *task_cls) |
1335 | { | 1209 | { |
1336 | return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, | 1210 | return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, |
1337 | task, | 1211 | task, |
1338 | task_cls); | 1212 | task_cls); |
1339 | } | 1213 | } |
1340 | 1214 | ||
1341 | 1215 | ||
@@ -1351,7 +1225,7 @@ GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, | |||
1351 | */ | 1225 | */ |
1352 | struct GNUNET_SCHEDULER_Task * | 1226 | struct GNUNET_SCHEDULER_Task * |
1353 | GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, | 1227 | GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, |
1354 | void *task_cls) | 1228 | void *task_cls) |
1355 | { | 1229 | { |
1356 | struct GNUNET_SCHEDULER_Task *t; | 1230 | struct GNUNET_SCHEDULER_Task *t; |
1357 | 1231 | ||
@@ -1368,12 +1242,12 @@ GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, | |||
1368 | t->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | 1242 | t->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; |
1369 | t->priority = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN; | 1243 | t->priority = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN; |
1370 | t->on_shutdown = GNUNET_YES; | 1244 | t->on_shutdown = GNUNET_YES; |
1371 | t->lifeness = GNUNET_YES; | 1245 | t->lifeness = GNUNET_NO; |
1372 | GNUNET_CONTAINER_DLL_insert (shutdown_head, | 1246 | GNUNET_CONTAINER_DLL_insert (shutdown_head, |
1373 | shutdown_tail, | 1247 | shutdown_tail, |
1374 | t); | 1248 | t); |
1375 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1249 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1376 | "Adding task: %p\n", | 1250 | "Adding shutdown task %p\n", |
1377 | t); | 1251 | t); |
1378 | init_backtrace (t); | 1252 | init_backtrace (t); |
1379 | return t; | 1253 | return t; |
@@ -1407,6 +1281,33 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, | |||
1407 | } | 1281 | } |
1408 | 1282 | ||
1409 | 1283 | ||
1284 | #if DEBUG_FDS | ||
1285 | /** | ||
1286 | * check a raw file descriptor and abort if it is bad (for debugging purposes) | ||
1287 | * | ||
1288 | * @param t the task related to the file descriptor | ||
1289 | * @param raw_fd the raw file descriptor to check | ||
1290 | */ | ||
1291 | void | ||
1292 | check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd) | ||
1293 | { | ||
1294 | if (-1 != raw_fd) | ||
1295 | { | ||
1296 | int flags = fcntl (raw_fd, F_GETFD); | ||
1297 | |||
1298 | if ((flags == -1) && (errno == EBADF)) | ||
1299 | { | ||
1300 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1301 | "Got invalid file descriptor %d!\n", | ||
1302 | raw_fd); | ||
1303 | init_backtrace (t); | ||
1304 | GNUNET_assert (0); | ||
1305 | } | ||
1306 | } | ||
1307 | } | ||
1308 | #endif | ||
1309 | |||
1310 | |||
1410 | /** | 1311 | /** |
1411 | * Schedule a new task to be run with a specified delay or when any of | 1312 | * Schedule a new task to be run with a specified delay or when any of |
1412 | * the specified file descriptor sets is ready. The delay can be used | 1313 | * the specified file descriptor sets is ready. The delay can be used |
@@ -1435,9 +1336,11 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, | |||
1435 | #ifndef MINGW | 1336 | #ifndef MINGW |
1436 | static struct GNUNET_SCHEDULER_Task * | 1337 | static struct GNUNET_SCHEDULER_Task * |
1437 | add_without_sets (struct GNUNET_TIME_Relative delay, | 1338 | add_without_sets (struct GNUNET_TIME_Relative delay, |
1438 | enum GNUNET_SCHEDULER_Priority priority, | 1339 | enum GNUNET_SCHEDULER_Priority priority, |
1439 | int rfd, | 1340 | const struct GNUNET_NETWORK_Handle *read_nh, |
1440 | int wfd, | 1341 | const struct GNUNET_NETWORK_Handle *write_nh, |
1342 | const struct GNUNET_DISK_FileHandle *read_fh, | ||
1343 | const struct GNUNET_DISK_FileHandle *write_fh, | ||
1441 | GNUNET_SCHEDULER_TaskCallback task, | 1344 | GNUNET_SCHEDULER_TaskCallback task, |
1442 | void *task_cls) | 1345 | void *task_cls) |
1443 | { | 1346 | { |
@@ -1446,39 +1349,23 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1446 | GNUNET_assert (NULL != active_task); | 1349 | GNUNET_assert (NULL != active_task); |
1447 | GNUNET_assert (NULL != task); | 1350 | GNUNET_assert (NULL != task); |
1448 | t = GNUNET_new (struct GNUNET_SCHEDULER_Task); | 1351 | t = GNUNET_new (struct GNUNET_SCHEDULER_Task); |
1352 | init_fd_info (t, | ||
1353 | &read_nh, | ||
1354 | read_nh ? 1 : 0, | ||
1355 | &write_nh, | ||
1356 | write_nh ? 1 : 0, | ||
1357 | &read_fh, | ||
1358 | read_fh ? 1 : 0, | ||
1359 | &write_fh, | ||
1360 | write_fh ? 1 : 0); | ||
1449 | t->callback = task; | 1361 | t->callback = task; |
1450 | t->callback_cls = task_cls; | 1362 | t->callback_cls = task_cls; |
1451 | #if DEBUG_FDS | 1363 | #if DEBUG_FDS |
1452 | if (-1 != rfd) | 1364 | check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1); |
1453 | { | 1365 | check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1); |
1454 | int flags = fcntl (rfd, F_GETFD); | 1366 | check_fd (t, NULL != read_fh ? read_fh->fd : -1); |
1455 | 1367 | check_fd (t, NULL != write_fh ? write_fh->fd : -1); | |
1456 | if ((flags == -1) && (errno == EBADF)) | ||
1457 | { | ||
1458 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1459 | "Got invalid file descriptor %d!\n", | ||
1460 | rfd); | ||
1461 | init_backtrace (t); | ||
1462 | GNUNET_assert (0); | ||
1463 | } | ||
1464 | } | ||
1465 | if (-1 != wfd) | ||
1466 | { | ||
1467 | int flags = fcntl (wfd, F_GETFD); | ||
1468 | |||
1469 | if (flags == -1 && errno == EBADF) | ||
1470 | { | ||
1471 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1472 | "Got invalid file descriptor %d!\n", | ||
1473 | wfd); | ||
1474 | init_backtrace (t); | ||
1475 | GNUNET_assert (0); | ||
1476 | } | ||
1477 | } | ||
1478 | #endif | 1368 | #endif |
1479 | t->read_fd = rfd; | ||
1480 | GNUNET_assert (wfd >= -1); | ||
1481 | t->write_fd = wfd; | ||
1482 | #if PROFILE_DELAYS | 1369 | #if PROFILE_DELAYS |
1483 | t->start_time = GNUNET_TIME_absolute_get (); | 1370 | t->start_time = GNUNET_TIME_absolute_get (); |
1484 | #endif | 1371 | #endif |
@@ -1488,11 +1375,9 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1488 | GNUNET_CONTAINER_DLL_insert (pending_head, | 1375 | GNUNET_CONTAINER_DLL_insert (pending_head, |
1489 | pending_tail, | 1376 | pending_tail, |
1490 | t); | 1377 | t); |
1378 | driver_add_multiple (t, GNUNET_SCHEDULER_ET_NONE); | ||
1491 | max_priority_added = GNUNET_MAX (max_priority_added, | 1379 | max_priority_added = GNUNET_MAX (max_priority_added, |
1492 | t->priority); | 1380 | t->priority); |
1493 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1494 | "Adding task %p\n", | ||
1495 | t); | ||
1496 | init_backtrace (t); | 1381 | init_backtrace (t); |
1497 | return t; | 1382 | return t; |
1498 | } | 1383 | } |
@@ -1505,6 +1390,9 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1505 | * used as a timeout on the socket being ready. The task will be | 1390 | * used as a timeout on the socket being ready. The task will be |
1506 | * scheduled for execution once either the delay has expired or the | 1391 | * scheduled for execution once either the delay has expired or the |
1507 | * socket operation is ready. It will be run with the DEFAULT priority. | 1392 | * socket operation is ready. It will be run with the DEFAULT priority. |
1393 | * Only allowed to be called as long as the scheduler is running | ||
1394 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1395 | * called and has not returned yet). | ||
1508 | * | 1396 | * |
1509 | * @param delay when should this operation time out? | 1397 | * @param delay when should this operation time out? |
1510 | * @param rfd read file-descriptor | 1398 | * @param rfd read file-descriptor |
@@ -1520,8 +1408,8 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
1520 | void *task_cls) | 1408 | void *task_cls) |
1521 | { | 1409 | { |
1522 | return GNUNET_SCHEDULER_add_read_net_with_priority (delay, | 1410 | return GNUNET_SCHEDULER_add_read_net_with_priority (delay, |
1523 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, | 1411 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, |
1524 | rfd, task, task_cls); | 1412 | rfd, task, task_cls); |
1525 | } | 1413 | } |
1526 | 1414 | ||
1527 | 1415 | ||
@@ -1532,6 +1420,9 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
1532 | * socket being ready. The task will be scheduled for execution once | 1420 | * socket being ready. The task will be scheduled for execution once |
1533 | * either the delay has expired or the socket operation is ready. It | 1421 | * either the delay has expired or the socket operation is ready. It |
1534 | * will be run with the DEFAULT priority. | 1422 | * will be run with the DEFAULT priority. |
1423 | * Only allowed to be called as long as the scheduler is running | ||
1424 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1425 | * called and has not returned yet). | ||
1535 | * | 1426 | * |
1536 | * @param delay when should this operation time out? | 1427 | * @param delay when should this operation time out? |
1537 | * @param priority priority to use for the task | 1428 | * @param priority priority to use for the task |
@@ -1543,9 +1434,9 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
1543 | */ | 1434 | */ |
1544 | struct GNUNET_SCHEDULER_Task * | 1435 | struct GNUNET_SCHEDULER_Task * |
1545 | GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, | 1436 | GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, |
1546 | enum GNUNET_SCHEDULER_Priority priority, | 1437 | enum GNUNET_SCHEDULER_Priority priority, |
1547 | struct GNUNET_NETWORK_Handle *rfd, | 1438 | struct GNUNET_NETWORK_Handle *rfd, |
1548 | GNUNET_SCHEDULER_TaskCallback task, | 1439 | GNUNET_SCHEDULER_TaskCallback task, |
1549 | void *task_cls) | 1440 | void *task_cls) |
1550 | { | 1441 | { |
1551 | return GNUNET_SCHEDULER_add_net_with_priority (delay, priority, | 1442 | return GNUNET_SCHEDULER_add_net_with_priority (delay, priority, |
@@ -1563,6 +1454,9 @@ GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1563 | * scheduled for execution once either the delay has expired or the | 1454 | * scheduled for execution once either the delay has expired or the |
1564 | * socket operation is ready. It will be run with the priority of | 1455 | * socket operation is ready. It will be run with the priority of |
1565 | * the calling task. | 1456 | * the calling task. |
1457 | * Only allowed to be called as long as the scheduler is running | ||
1458 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1459 | * called and has not returned yet). | ||
1566 | * | 1460 | * |
1567 | * @param delay when should this operation time out? | 1461 | * @param delay when should this operation time out? |
1568 | * @param wfd write file-descriptor | 1462 | * @param wfd write file-descriptor |
@@ -1590,6 +1484,9 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, | |||
1590 | * used as a timeout on the socket being ready. The task will be | 1484 | * used as a timeout on the socket being ready. The task will be |
1591 | * scheduled for execution once either the delay has expired or the | 1485 | * scheduled for execution once either the delay has expired or the |
1592 | * socket operation is ready. | 1486 | * socket operation is ready. |
1487 | * Only allowed to be called as long as the scheduler is running | ||
1488 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1489 | * called and has not returned yet). | ||
1593 | * | 1490 | * |
1594 | * @param delay when should this operation time out? | 1491 | * @param delay when should this operation time out? |
1595 | * @param priority priority of the task | 1492 | * @param priority priority of the task |
@@ -1610,6 +1507,9 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1610 | GNUNET_SCHEDULER_TaskCallback task, | 1507 | GNUNET_SCHEDULER_TaskCallback task, |
1611 | void *task_cls) | 1508 | void *task_cls) |
1612 | { | 1509 | { |
1510 | /* scheduler must be running */ | ||
1511 | GNUNET_assert (NULL != scheduler_driver); | ||
1512 | |||
1613 | #if MINGW | 1513 | #if MINGW |
1614 | struct GNUNET_NETWORK_FDSet *s; | 1514 | struct GNUNET_NETWORK_FDSet *s; |
1615 | struct GNUNET_SCHEDULER_Task * ret; | 1515 | struct GNUNET_SCHEDULER_Task * ret; |
@@ -1625,10 +1525,13 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1625 | GNUNET_NETWORK_fdset_destroy (s); | 1525 | GNUNET_NETWORK_fdset_destroy (s); |
1626 | return ret; | 1526 | return ret; |
1627 | #else | 1527 | #else |
1528 | GNUNET_assert (on_read || on_write); | ||
1628 | GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0); | 1529 | GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0); |
1629 | return add_without_sets (delay, priority, | 1530 | return add_without_sets (delay, priority, |
1630 | on_read ? GNUNET_NETWORK_get_fd (fd) : -1, | 1531 | on_read ? fd : NULL, |
1631 | on_write ? GNUNET_NETWORK_get_fd (fd) : -1, | 1532 | on_write ? fd : NULL, |
1533 | NULL, | ||
1534 | NULL, | ||
1632 | task, task_cls); | 1535 | task, task_cls); |
1633 | #endif | 1536 | #endif |
1634 | } | 1537 | } |
@@ -1640,6 +1543,9 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1640 | * used as a timeout on the socket being ready. The task will be | 1543 | * used as a timeout on the socket being ready. The task will be |
1641 | * scheduled for execution once either the delay has expired or the | 1544 | * scheduled for execution once either the delay has expired or the |
1642 | * socket operation is ready. It will be run with the DEFAULT priority. | 1545 | * socket operation is ready. It will be run with the DEFAULT priority. |
1546 | * Only allowed to be called as long as the scheduler is running | ||
1547 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1548 | * called and has not returned yet). | ||
1643 | * | 1549 | * |
1644 | * @param delay when should this operation time out? | 1550 | * @param delay when should this operation time out? |
1645 | * @param rfd read file-descriptor | 1551 | * @param rfd read file-descriptor |
@@ -1666,6 +1572,9 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, | |||
1666 | * used as a timeout on the socket being ready. The task will be | 1572 | * used as a timeout on the socket being ready. The task will be |
1667 | * scheduled for execution once either the delay has expired or the | 1573 | * scheduled for execution once either the delay has expired or the |
1668 | * socket operation is ready. It will be run with the DEFAULT priority. | 1574 | * socket operation is ready. It will be run with the DEFAULT priority. |
1575 | * Only allowed to be called as long as the scheduler is running | ||
1576 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1577 | * called and has not returned yet). | ||
1669 | * | 1578 | * |
1670 | * @param delay when should this operation time out? | 1579 | * @param delay when should this operation time out? |
1671 | * @param wfd write file-descriptor | 1580 | * @param wfd write file-descriptor |
@@ -1692,6 +1601,9 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, | |||
1692 | * used as a timeout on the socket being ready. The task will be | 1601 | * used as a timeout on the socket being ready. The task will be |
1693 | * scheduled for execution once either the delay has expired or the | 1602 | * scheduled for execution once either the delay has expired or the |
1694 | * socket operation is ready. | 1603 | * socket operation is ready. |
1604 | * Only allowed to be called as long as the scheduler is running | ||
1605 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1606 | * called and has not returned yet). | ||
1695 | * | 1607 | * |
1696 | * @param delay when should this operation time out? | 1608 | * @param delay when should this operation time out? |
1697 | * @param priority priority of the task | 1609 | * @param priority priority of the task |
@@ -1710,6 +1622,9 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
1710 | int on_read, int on_write, | 1622 | int on_read, int on_write, |
1711 | GNUNET_SCHEDULER_TaskCallback task, void *task_cls) | 1623 | GNUNET_SCHEDULER_TaskCallback task, void *task_cls) |
1712 | { | 1624 | { |
1625 | /* scheduler must be running */ | ||
1626 | GNUNET_assert (NULL != scheduler_driver); | ||
1627 | |||
1713 | #if MINGW | 1628 | #if MINGW |
1714 | struct GNUNET_NETWORK_FDSet *s; | 1629 | struct GNUNET_NETWORK_FDSet *s; |
1715 | struct GNUNET_SCHEDULER_Task * ret; | 1630 | struct GNUNET_SCHEDULER_Task * ret; |
@@ -1725,19 +1640,70 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
1725 | GNUNET_NETWORK_fdset_destroy (s); | 1640 | GNUNET_NETWORK_fdset_destroy (s); |
1726 | return ret; | 1641 | return ret; |
1727 | #else | 1642 | #else |
1728 | int real_fd; | 1643 | GNUNET_assert (on_read || on_write); |
1729 | 1644 | GNUNET_assert (fd->fd >= 0); | |
1730 | GNUNET_DISK_internal_file_handle_ (fd, &real_fd, sizeof (int)); | 1645 | return add_without_sets (delay, priority, |
1731 | GNUNET_assert (real_fd >= 0); | 1646 | NULL, |
1732 | return add_without_sets ( | 1647 | NULL, |
1733 | delay, priority, | 1648 | on_read ? fd : NULL, |
1734 | on_read ? real_fd : -1, | 1649 | on_write ? fd : NULL, |
1735 | on_write ? real_fd : -1, | 1650 | task, task_cls); |
1736 | task, task_cls); | ||
1737 | #endif | 1651 | #endif |
1738 | } | 1652 | } |
1739 | 1653 | ||
1740 | 1654 | ||
1655 | void | ||
1656 | extract_handles (struct GNUNET_SCHEDULER_Task *t, | ||
1657 | const struct GNUNET_NETWORK_FDSet *fdset, | ||
1658 | const struct GNUNET_NETWORK_Handle ***ntarget, | ||
1659 | unsigned int *extracted_nhandles, | ||
1660 | const struct GNUNET_DISK_FileHandle ***ftarget, | ||
1661 | unsigned int *extracted_fhandles) | ||
1662 | { | ||
1663 | // FIXME: this implementation only works for unix, for WIN32 the file handles | ||
1664 | // in fdset must be handled separately | ||
1665 | const struct GNUNET_NETWORK_Handle **nhandles; | ||
1666 | const struct GNUNET_DISK_FileHandle **fhandles; | ||
1667 | unsigned int nhandles_len, fhandles_len; | ||
1668 | int sock; | ||
1669 | |||
1670 | nhandles = NULL; | ||
1671 | fhandles = NULL; | ||
1672 | nhandles_len = 0; | ||
1673 | fhandles_len = 0; | ||
1674 | for (sock = 0; sock != fdset->nsds; ++sock) | ||
1675 | { | ||
1676 | if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock)) | ||
1677 | { | ||
1678 | struct GNUNET_NETWORK_Handle *nhandle; | ||
1679 | struct GNUNET_DISK_FileHandle *fhandle; | ||
1680 | |||
1681 | nhandle = GNUNET_NETWORK_socket_box_native (sock); | ||
1682 | if (NULL != nhandle) | ||
1683 | { | ||
1684 | GNUNET_array_append (nhandles, nhandles_len, nhandle); | ||
1685 | } | ||
1686 | else | ||
1687 | { | ||
1688 | fhandle = GNUNET_DISK_get_handle_from_int_fd (sock); | ||
1689 | if (NULL != fhandle) | ||
1690 | { | ||
1691 | GNUNET_array_append (fhandles, fhandles_len, fhandle); | ||
1692 | } | ||
1693 | else | ||
1694 | { | ||
1695 | GNUNET_assert (0); | ||
1696 | } | ||
1697 | } | ||
1698 | } | ||
1699 | } | ||
1700 | *ntarget = nhandles_len > 0 ? nhandles : NULL; | ||
1701 | *ftarget = fhandles_len > 0 ? fhandles : NULL; | ||
1702 | *extracted_nhandles = nhandles_len; | ||
1703 | *extracted_fhandles = fhandles_len; | ||
1704 | } | ||
1705 | |||
1706 | |||
1741 | /** | 1707 | /** |
1742 | * Schedule a new task to be run with a specified delay or when any of | 1708 | * Schedule a new task to be run with a specified delay or when any of |
1743 | * the specified file descriptor sets is ready. The delay can be used | 1709 | * the specified file descriptor sets is ready. The delay can be used |
@@ -1753,6 +1719,9 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
1753 | * || any-rs-ready | 1719 | * || any-rs-ready |
1754 | * || any-ws-ready) ) | 1720 | * || any-ws-ready) ) |
1755 | * </code> | 1721 | * </code> |
1722 | * Only allowed to be called as long as the scheduler is running | ||
1723 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | ||
1724 | * called and has not returned yet). | ||
1756 | * | 1725 | * |
1757 | * @param prio how important is this task? | 1726 | * @param prio how important is this task? |
1758 | * @param delay how long should we wait? | 1727 | * @param delay how long should we wait? |
@@ -1772,13 +1741,20 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1772 | void *task_cls) | 1741 | void *task_cls) |
1773 | { | 1742 | { |
1774 | struct GNUNET_SCHEDULER_Task *t; | 1743 | struct GNUNET_SCHEDULER_Task *t; |
1775 | 1744 | const struct GNUNET_NETWORK_Handle **read_nhandles; | |
1776 | if ( (NULL == rs) && | 1745 | const struct GNUNET_NETWORK_Handle **write_nhandles; |
1777 | (NULL == ws) ) | 1746 | const struct GNUNET_DISK_FileHandle **read_fhandles; |
1747 | const struct GNUNET_DISK_FileHandle **write_fhandles; | ||
1748 | unsigned int read_nhandles_len, write_nhandles_len, | ||
1749 | read_fhandles_len, write_fhandles_len; | ||
1750 | |||
1751 | if (((NULL == rs) && (NULL == ws)) || ((0 == rs->nsds) && (0 == ws->nsds))) | ||
1778 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, | 1752 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, |
1779 | prio, | 1753 | prio, |
1780 | task, | 1754 | task, |
1781 | task_cls); | 1755 | task_cls); |
1756 | /* scheduler must be running */ | ||
1757 | GNUNET_assert (NULL != scheduler_driver); | ||
1782 | GNUNET_assert (NULL != active_task); | 1758 | GNUNET_assert (NULL != active_task); |
1783 | GNUNET_assert (NULL != task); | 1759 | GNUNET_assert (NULL != task); |
1784 | t = GNUNET_new (struct GNUNET_SCHEDULER_Task); | 1760 | t = GNUNET_new (struct GNUNET_SCHEDULER_Task); |
@@ -1786,16 +1762,48 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1786 | t->callback_cls = task_cls; | 1762 | t->callback_cls = task_cls; |
1787 | t->read_fd = -1; | 1763 | t->read_fd = -1; |
1788 | t->write_fd = -1; | 1764 | t->write_fd = -1; |
1765 | t->own_handles = GNUNET_YES; | ||
1766 | read_nhandles = NULL; | ||
1767 | write_nhandles = NULL; | ||
1768 | read_fhandles = NULL; | ||
1769 | write_fhandles = NULL; | ||
1770 | read_nhandles_len = 0; | ||
1771 | write_nhandles_len = 0; | ||
1772 | read_fhandles_len = 0; | ||
1773 | write_fhandles_len = 0; | ||
1789 | if (NULL != rs) | 1774 | if (NULL != rs) |
1790 | { | 1775 | { |
1791 | t->read_set = GNUNET_NETWORK_fdset_create (); | 1776 | extract_handles (t, |
1792 | GNUNET_NETWORK_fdset_copy (t->read_set, rs); | 1777 | rs, |
1778 | &read_nhandles, | ||
1779 | &read_nhandles_len, | ||
1780 | &read_fhandles, | ||
1781 | &read_fhandles_len); | ||
1793 | } | 1782 | } |
1794 | if (NULL != ws) | 1783 | if (NULL != ws) |
1795 | { | 1784 | { |
1796 | t->write_set = GNUNET_NETWORK_fdset_create (); | 1785 | extract_handles (t, |
1797 | GNUNET_NETWORK_fdset_copy (t->write_set, ws); | 1786 | ws, |
1787 | &write_nhandles, | ||
1788 | &write_nhandles_len, | ||
1789 | &write_fhandles, | ||
1790 | &write_fhandles_len); | ||
1798 | } | 1791 | } |
1792 | init_fd_info (t, | ||
1793 | read_nhandles, | ||
1794 | read_nhandles_len, | ||
1795 | write_nhandles, | ||
1796 | write_nhandles_len, | ||
1797 | read_fhandles, | ||
1798 | read_fhandles_len, | ||
1799 | write_fhandles, | ||
1800 | write_fhandles_len); | ||
1801 | /* free the arrays of pointers to network / file handles, the actual | ||
1802 | * handles will be freed in destroy_task */ | ||
1803 | GNUNET_array_grow (read_nhandles, read_nhandles_len, 0); | ||
1804 | GNUNET_array_grow (write_nhandles, write_nhandles_len, 0); | ||
1805 | GNUNET_array_grow (read_fhandles, read_fhandles_len, 0); | ||
1806 | GNUNET_array_grow (write_fhandles, write_fhandles_len, 0); | ||
1799 | #if PROFILE_DELAYS | 1807 | #if PROFILE_DELAYS |
1800 | t->start_time = GNUNET_TIME_absolute_get (); | 1808 | t->start_time = GNUNET_TIME_absolute_get (); |
1801 | #endif | 1809 | #endif |
@@ -1808,8 +1816,9 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1808 | GNUNET_CONTAINER_DLL_insert (pending_head, | 1816 | GNUNET_CONTAINER_DLL_insert (pending_head, |
1809 | pending_tail, | 1817 | pending_tail, |
1810 | t); | 1818 | t); |
1819 | driver_add_multiple (t, GNUNET_SCHEDULER_ET_NONE); | ||
1811 | max_priority_added = GNUNET_MAX (max_priority_added, | 1820 | max_priority_added = GNUNET_MAX (max_priority_added, |
1812 | t->priority); | 1821 | t->priority); |
1813 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1822 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1814 | "Adding task %p\n", | 1823 | "Adding task %p\n", |
1815 | t); | 1824 | t); |
@@ -1820,17 +1829,18 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1820 | 1829 | ||
1821 | /** | 1830 | /** |
1822 | * Function used by event-loop implementations to signal the scheduler | 1831 | * Function used by event-loop implementations to signal the scheduler |
1823 | * that a particular @a task is ready due to an event of type @a et. | 1832 | * that a particular @a task is ready due to an event specified in the |
1833 | * et field of @a fdi. | ||
1824 | * | 1834 | * |
1825 | * This function will then queue the task to notify the application | 1835 | * This function will then queue the task to notify the application |
1826 | * that the task is ready (with the respective priority). | 1836 | * that the task is ready (with the respective priority). |
1827 | * | 1837 | * |
1828 | * @param task the task that is ready, NULL for wake up calls | 1838 | * @param task the task that is ready |
1829 | * @param et information about why the task is ready | 1839 | * @param fdi information about the related FD |
1830 | */ | 1840 | */ |
1831 | void | 1841 | void |
1832 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | 1842 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, |
1833 | enum GNUNET_SCHEDULER_EventType et) | 1843 | struct GNUNET_SCHEDULER_FdInfo *fdi) |
1834 | { | 1844 | { |
1835 | enum GNUNET_SCHEDULER_Reason reason; | 1845 | enum GNUNET_SCHEDULER_Reason reason; |
1836 | struct GNUNET_TIME_Absolute now; | 1846 | struct GNUNET_TIME_Absolute now; |
@@ -1840,17 +1850,20 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | |||
1840 | if (now.abs_value_us >= task->timeout.abs_value_us) | 1850 | if (now.abs_value_us >= task->timeout.abs_value_us) |
1841 | reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | 1851 | reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; |
1842 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && | 1852 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && |
1843 | (0 != (GNUNET_SCHEDULER_ET_IN & et)) ) | 1853 | (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) ) |
1844 | reason |= GNUNET_SCHEDULER_REASON_READ_READY; | 1854 | reason |= GNUNET_SCHEDULER_REASON_READ_READY; |
1845 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | 1855 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && |
1846 | (0 != (GNUNET_SCHEDULER_ET_OUT & et)) ) | 1856 | (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) ) |
1847 | reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; | 1857 | reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; |
1848 | reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; | 1858 | reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; |
1849 | task->reason = reason; | 1859 | task->reason = reason; |
1850 | task->fds = &task->fdx; | 1860 | if (GNUNET_NO == task->in_ready_list) |
1851 | task->fdx.et = et; | 1861 | { |
1852 | task->fds_len = 1; | 1862 | GNUNET_CONTAINER_DLL_remove (pending_head, |
1853 | queue_ready_task (task); | 1863 | pending_tail, |
1864 | task); | ||
1865 | queue_ready_task (task); | ||
1866 | } | ||
1854 | } | 1867 | } |
1855 | 1868 | ||
1856 | 1869 | ||
@@ -1860,15 +1873,16 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | |||
1860 | * there are tasks left to run just to give other tasks a chance as | 1873 | * there are tasks left to run just to give other tasks a chance as |
1861 | * well. If we return #GNUNET_YES, the driver should call this | 1874 | * well. If we return #GNUNET_YES, the driver should call this |
1862 | * function again as soon as possible, while if we return #GNUNET_NO | 1875 | * function again as soon as possible, while if we return #GNUNET_NO |
1863 | * it must block until the operating system has more work as the | 1876 | * it must block until either the operating system has more work (the |
1864 | * scheduler has no more work to do right now. | 1877 | * scheduler has no more work to do right now) or the timeout set by |
1878 | * the scheduler (using the set_wakeup callback) is reached. | ||
1865 | * | 1879 | * |
1866 | * @param sh scheduler handle that was given to the `loop` | 1880 | * @param sh scheduler handle that was given to the `loop` |
1867 | * @return #GNUNET_OK if there are more tasks that are ready, | 1881 | * @return #GNUNET_OK if there are more tasks that are ready, |
1868 | * and thus we would like to run more (yield to avoid | 1882 | * and thus we would like to run more (yield to avoid |
1869 | * blocking other activities for too long) | 1883 | * blocking other activities for too long) |
1870 | * #GNUNET_NO if we are done running tasks (yield to block) | 1884 | * #GNUNET_NO if we are done running tasks (yield to block) |
1871 | * #GNUNET_SYSERR on error | 1885 | * #GNUNET_SYSERR on error, e.g. no tasks were ready |
1872 | */ | 1886 | */ |
1873 | int | 1887 | int |
1874 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | 1888 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) |
@@ -1892,9 +1906,27 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1892 | pending_timeout_last = NULL; | 1906 | pending_timeout_last = NULL; |
1893 | queue_ready_task (pos); | 1907 | queue_ready_task (pos); |
1894 | } | 1908 | } |
1909 | pos = pending_head; | ||
1910 | while (NULL != pos) | ||
1911 | { | ||
1912 | struct GNUNET_SCHEDULER_Task *next = pos->next; | ||
1913 | if (now.abs_value_us >= pos->timeout.abs_value_us) | ||
1914 | { | ||
1915 | pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | ||
1916 | GNUNET_CONTAINER_DLL_remove (pending_head, | ||
1917 | pending_tail, | ||
1918 | pos); | ||
1919 | queue_ready_task (pos); | ||
1920 | } | ||
1921 | pos = next; | ||
1922 | } | ||
1895 | 1923 | ||
1896 | if (0 == ready_count) | 1924 | if (0 == ready_count) |
1897 | return GNUNET_NO; | 1925 | { |
1926 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1927 | "GNUNET_SCHEDULER_run_from_driver was called, but no tasks are ready!\n"); | ||
1928 | return GNUNET_SYSERR; | ||
1929 | } | ||
1898 | 1930 | ||
1899 | /* find out which task priority level we are going to | 1931 | /* find out which task priority level we are going to |
1900 | process this time */ | 1932 | process this time */ |
@@ -1914,49 +1946,74 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1914 | while (NULL != (pos = ready_head[p])) | 1946 | while (NULL != (pos = ready_head[p])) |
1915 | { | 1947 | { |
1916 | GNUNET_CONTAINER_DLL_remove (ready_head[p], | 1948 | GNUNET_CONTAINER_DLL_remove (ready_head[p], |
1917 | ready_tail[p], | 1949 | ready_tail[p], |
1918 | pos); | 1950 | pos); |
1919 | ready_count--; | 1951 | ready_count--; |
1920 | current_priority = pos->priority; | 1952 | current_priority = pos->priority; |
1921 | current_lifeness = pos->lifeness; | 1953 | current_lifeness = pos->lifeness; |
1922 | active_task = pos; | 1954 | active_task = pos; |
1923 | #if PROFILE_DELAYS | 1955 | #if PROFILE_DELAYS |
1924 | if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > | 1956 | if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > |
1925 | DELAY_THRESHOLD.rel_value_us) | 1957 | DELAY_THRESHOLD.rel_value_us) |
1926 | { | 1958 | { |
1927 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1959 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1928 | "Task %p took %s to be scheduled\n", | 1960 | "Task %p took %s to be scheduled\n", |
1929 | pos, | 1961 | pos, |
1930 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), | 1962 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), |
1931 | GNUNET_YES)); | 1963 | GNUNET_YES)); |
1932 | } | 1964 | } |
1933 | #endif | 1965 | #endif |
1934 | tc.reason = pos->reason; | 1966 | tc.reason = pos->reason; |
1935 | GNUNET_NETWORK_fdset_zero (sh->rs); | 1967 | GNUNET_NETWORK_fdset_zero (sh->rs); |
1936 | GNUNET_NETWORK_fdset_zero (sh->ws); | 1968 | GNUNET_NETWORK_fdset_zero (sh->ws); |
1969 | // FIXME: do we have to remove FdInfos from fds if they are not ready? | ||
1937 | tc.fds_len = pos->fds_len; | 1970 | tc.fds_len = pos->fds_len; |
1938 | tc.fds = pos->fds; | 1971 | tc.fds = pos->fds; |
1939 | tc.read_ready = (NULL == pos->read_set) ? sh->rs : pos->read_set; | 1972 | for (int i = 0; i != pos->fds_len; ++i) |
1940 | if ( (-1 != pos->read_fd) && | 1973 | { |
1941 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY)) ) | 1974 | struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i]; |
1942 | GNUNET_NETWORK_fdset_set_native (sh->rs, | 1975 | if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) |
1943 | pos->read_fd); | 1976 | { |
1944 | tc.write_ready = (NULL == pos->write_set) ? sh->ws : pos->write_set; | 1977 | GNUNET_NETWORK_fdset_set_native (sh->rs, |
1945 | if ((-1 != pos->write_fd) && | 1978 | fdi->sock); |
1946 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) | 1979 | } |
1947 | GNUNET_NETWORK_fdset_set_native (sh->ws, | 1980 | if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) |
1948 | pos->write_fd); | 1981 | { |
1982 | GNUNET_NETWORK_fdset_set_native (sh->ws, | ||
1983 | fdi->sock); | ||
1984 | } | ||
1985 | } | ||
1986 | tc.read_ready = sh->rs; | ||
1987 | tc.write_ready = sh->ws; | ||
1949 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1988 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1950 | "Running task: %p\n", | 1989 | "Running task %p\n", |
1951 | pos); | 1990 | pos); |
1991 | GNUNET_assert (NULL != pos->callback); | ||
1952 | pos->callback (pos->callback_cls); | 1992 | pos->callback (pos->callback_cls); |
1993 | if (NULL != pos->fds) | ||
1994 | { | ||
1995 | int del_result = scheduler_driver->del (scheduler_driver->cls, pos); | ||
1996 | if (GNUNET_OK != del_result) | ||
1997 | { | ||
1998 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1999 | "driver could not delete task\n"); | ||
2000 | GNUNET_assert (0); | ||
2001 | } | ||
2002 | } | ||
1953 | active_task = NULL; | 2003 | active_task = NULL; |
1954 | dump_backtrace (pos); | 2004 | dump_backtrace (pos); |
1955 | destroy_task (pos); | 2005 | destroy_task (pos); |
1956 | tasks_run++; | 2006 | tasks_run++; |
1957 | } | 2007 | } |
2008 | shutdown_if_no_lifeness (); | ||
1958 | if (0 == ready_count) | 2009 | if (0 == ready_count) |
2010 | { | ||
2011 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
2012 | get_timeout ()); | ||
1959 | return GNUNET_NO; | 2013 | return GNUNET_NO; |
2014 | } | ||
2015 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
2016 | GNUNET_TIME_absolute_get ()); | ||
1960 | return GNUNET_OK; | 2017 | return GNUNET_OK; |
1961 | } | 2018 | } |
1962 | 2019 | ||
@@ -1979,8 +2036,8 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1979 | */ | 2036 | */ |
1980 | int | 2037 | int |
1981 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | 2038 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, |
1982 | GNUNET_SCHEDULER_TaskCallback task, | 2039 | GNUNET_SCHEDULER_TaskCallback task, |
1983 | void *task_cls) | 2040 | void *task_cls) |
1984 | { | 2041 | { |
1985 | int ret; | 2042 | int ret; |
1986 | struct GNUNET_SIGNAL_Context *shc_int; | 2043 | struct GNUNET_SIGNAL_Context *shc_int; |
@@ -1995,7 +2052,6 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
1995 | #endif | 2052 | #endif |
1996 | struct GNUNET_SCHEDULER_Task tsk; | 2053 | struct GNUNET_SCHEDULER_Task tsk; |
1997 | const struct GNUNET_DISK_FileHandle *pr; | 2054 | const struct GNUNET_DISK_FileHandle *pr; |
1998 | struct GNUNET_SCHEDULER_Handle sh; | ||
1999 | 2055 | ||
2000 | /* general set-up */ | 2056 | /* general set-up */ |
2001 | GNUNET_assert (NULL == active_task); | 2057 | GNUNET_assert (NULL == active_task); |
@@ -2007,54 +2063,56 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2007 | GNUNET_assert (NULL != shutdown_pipe_handle); | 2063 | GNUNET_assert (NULL != shutdown_pipe_handle); |
2008 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | 2064 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, |
2009 | GNUNET_DISK_PIPE_END_READ); | 2065 | GNUNET_DISK_PIPE_END_READ); |
2010 | GNUNET_assert (NULL != pr); | ||
2011 | my_pid = getpid (); | 2066 | my_pid = getpid (); |
2067 | scheduler_driver = driver; | ||
2012 | 2068 | ||
2013 | /* install signal handlers */ | 2069 | /* install signal handlers */ |
2014 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 2070 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2015 | "Registering signal handlers\n"); | 2071 | "Registering signal handlers\n"); |
2016 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, | 2072 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, |
2017 | &sighandler_shutdown); | 2073 | &sighandler_shutdown); |
2018 | shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, | 2074 | shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, |
2019 | &sighandler_shutdown); | 2075 | &sighandler_shutdown); |
2020 | #if (SIGTERM != GNUNET_TERM_SIG) | 2076 | #if (SIGTERM != GNUNET_TERM_SIG) |
2021 | shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, | 2077 | shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, |
2022 | &sighandler_shutdown); | 2078 | &sighandler_shutdown); |
2023 | #endif | 2079 | #endif |
2024 | #ifndef MINGW | 2080 | #ifndef MINGW |
2025 | shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, | 2081 | shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, |
2026 | &sighandler_pipe); | 2082 | &sighandler_pipe); |
2027 | shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, | 2083 | shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, |
2028 | &sighandler_shutdown); | 2084 | &sighandler_shutdown); |
2029 | shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, | 2085 | shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, |
2030 | &sighandler_shutdown); | 2086 | &sighandler_shutdown); |
2031 | #endif | 2087 | #endif |
2032 | 2088 | ||
2033 | /* Setup initial tasks */ | 2089 | /* Setup initial tasks */ |
2034 | current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; | 2090 | current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; |
2035 | current_lifeness = GNUNET_YES; | 2091 | current_lifeness = GNUNET_NO; |
2036 | memset (&tsk, | 2092 | memset (&tsk, |
2037 | 0, | 2093 | 0, |
2038 | sizeof (tsk)); | 2094 | sizeof (tsk)); |
2039 | active_task = &tsk; | 2095 | active_task = &tsk; |
2040 | tsk.sh = &sh; | 2096 | GNUNET_SCHEDULER_add_now (&GNUNET_OS_install_parent_control_handler, |
2097 | NULL); | ||
2098 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2099 | pr, | ||
2100 | &shutdown_cb, | ||
2101 | NULL); | ||
2102 | current_lifeness = GNUNET_YES; | ||
2041 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, | 2103 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, |
2042 | task_cls, | 2104 | task_cls, |
2043 | GNUNET_SCHEDULER_REASON_STARTUP, | 2105 | GNUNET_SCHEDULER_REASON_STARTUP, |
2044 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); | 2106 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); |
2045 | GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, | ||
2046 | &GNUNET_OS_install_parent_control_handler, | ||
2047 | NULL); | ||
2048 | active_task = NULL; | 2107 | active_task = NULL; |
2049 | driver->set_wakeup (driver->cls, | 2108 | scheduler_driver->set_wakeup (scheduler_driver->cls, |
2050 | GNUNET_TIME_absolute_get ()); | 2109 | get_timeout ()); |
2051 | |||
2052 | /* begin main event loop */ | 2110 | /* begin main event loop */ |
2053 | sh.rs = GNUNET_NETWORK_fdset_create (); | 2111 | sh.rs = GNUNET_NETWORK_fdset_create (); |
2054 | sh.ws = GNUNET_NETWORK_fdset_create (); | 2112 | sh.ws = GNUNET_NETWORK_fdset_create (); |
2055 | sh.driver = driver; | 2113 | GNUNET_NETWORK_fdset_handle_set (sh.rs, pr); |
2056 | ret = driver->loop (driver->cls, | 2114 | ret = driver->loop (driver->cls, |
2057 | &sh); | 2115 | &sh); |
2058 | GNUNET_NETWORK_fdset_destroy (sh.rs); | 2116 | GNUNET_NETWORK_fdset_destroy (sh.rs); |
2059 | GNUNET_NETWORK_fdset_destroy (sh.ws); | 2117 | GNUNET_NETWORK_fdset_destroy (sh.ws); |
2060 | 2118 | ||
@@ -2071,20 +2129,211 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2071 | #endif | 2129 | #endif |
2072 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); | 2130 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); |
2073 | shutdown_pipe_handle = NULL; | 2131 | shutdown_pipe_handle = NULL; |
2132 | scheduler_driver = NULL; | ||
2074 | return ret; | 2133 | return ret; |
2075 | } | 2134 | } |
2076 | 2135 | ||
2077 | 2136 | ||
2137 | int | ||
2138 | select_add (void *cls, | ||
2139 | struct GNUNET_SCHEDULER_Task *task, | ||
2140 | struct GNUNET_SCHEDULER_FdInfo *fdi) | ||
2141 | { | ||
2142 | struct DriverContext *context = cls; | ||
2143 | GNUNET_assert (NULL != context); | ||
2144 | GNUNET_assert (NULL != task); | ||
2145 | GNUNET_assert (NULL != fdi); | ||
2146 | GNUNET_assert (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et) || | ||
2147 | 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)); | ||
2148 | |||
2149 | if (!((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0)) | ||
2150 | { | ||
2151 | /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */ | ||
2152 | return GNUNET_SYSERR; | ||
2153 | } | ||
2154 | |||
2155 | struct Scheduled *scheduled = GNUNET_new (struct Scheduled); | ||
2156 | scheduled->task = task; | ||
2157 | scheduled->fdi = fdi; | ||
2158 | scheduled->et = fdi->et; | ||
2159 | |||
2160 | GNUNET_CONTAINER_DLL_insert (context->scheduled_head, | ||
2161 | context->scheduled_tail, | ||
2162 | scheduled); | ||
2163 | return GNUNET_OK; | ||
2164 | } | ||
2165 | |||
2166 | |||
2167 | int | ||
2168 | select_del (void *cls, | ||
2169 | struct GNUNET_SCHEDULER_Task *task) | ||
2170 | { | ||
2171 | struct DriverContext *context; | ||
2172 | struct Scheduled *pos; | ||
2173 | int ret; | ||
2174 | |||
2175 | GNUNET_assert (NULL != cls); | ||
2176 | |||
2177 | context = cls; | ||
2178 | ret = GNUNET_SYSERR; | ||
2179 | pos = context->scheduled_head; | ||
2180 | while (NULL != pos) | ||
2181 | { | ||
2182 | struct Scheduled *next = pos->next; | ||
2183 | if (pos->task == task) | ||
2184 | { | ||
2185 | GNUNET_CONTAINER_DLL_remove (context->scheduled_head, | ||
2186 | context->scheduled_tail, | ||
2187 | pos); | ||
2188 | GNUNET_free (pos); | ||
2189 | ret = GNUNET_OK; | ||
2190 | } | ||
2191 | pos = next; | ||
2192 | } | ||
2193 | return ret; | ||
2194 | } | ||
2195 | |||
2196 | |||
2197 | int | ||
2198 | select_loop (void *cls, | ||
2199 | struct GNUNET_SCHEDULER_Handle *sh) | ||
2200 | { | ||
2201 | struct GNUNET_NETWORK_FDSet *rs; | ||
2202 | struct GNUNET_NETWORK_FDSet *ws; | ||
2203 | struct DriverContext *context; | ||
2204 | int select_result; | ||
2205 | int tasks_ready; | ||
2206 | |||
2207 | context = cls; | ||
2208 | GNUNET_assert (NULL != context); | ||
2209 | rs = GNUNET_NETWORK_fdset_create (); | ||
2210 | ws = GNUNET_NETWORK_fdset_create (); | ||
2211 | tasks_ready = GNUNET_NO; | ||
2212 | while (NULL != context->scheduled_head || | ||
2213 | GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != context->timeout.rel_value_us) | ||
2214 | { | ||
2215 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2216 | "select timeout = %s\n", | ||
2217 | GNUNET_STRINGS_relative_time_to_string (context->timeout, GNUNET_NO)); | ||
2218 | |||
2219 | GNUNET_NETWORK_fdset_zero (rs); | ||
2220 | GNUNET_NETWORK_fdset_zero (ws); | ||
2221 | struct Scheduled *pos; | ||
2222 | for (pos = context->scheduled_head; NULL != pos; pos = pos->next) | ||
2223 | { | ||
2224 | if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) | ||
2225 | { | ||
2226 | GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock); | ||
2227 | } | ||
2228 | if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) | ||
2229 | { | ||
2230 | GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock); | ||
2231 | } | ||
2232 | } | ||
2233 | if (NULL == scheduler_select) | ||
2234 | { | ||
2235 | select_result = GNUNET_NETWORK_socket_select (rs, | ||
2236 | ws, | ||
2237 | NULL, | ||
2238 | context->timeout); | ||
2239 | } | ||
2240 | else | ||
2241 | { | ||
2242 | select_result = scheduler_select (scheduler_select_cls, | ||
2243 | rs, | ||
2244 | ws, | ||
2245 | NULL, | ||
2246 | context->timeout); | ||
2247 | } | ||
2248 | if (select_result == GNUNET_SYSERR) | ||
2249 | { | ||
2250 | if (errno == EINTR) | ||
2251 | continue; | ||
2252 | |||
2253 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); | ||
2254 | #ifndef MINGW | ||
2255 | #if USE_LSOF | ||
2256 | char lsof[512]; | ||
2257 | |||
2258 | snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); | ||
2259 | (void) close (1); | ||
2260 | (void) dup2 (2, 1); | ||
2261 | if (0 != system (lsof)) | ||
2262 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
2263 | "system"); | ||
2264 | #endif | ||
2265 | #endif | ||
2266 | #if DEBUG_FDS | ||
2267 | struct Scheduled *s; | ||
2268 | for (s = context->scheduled_head; NULL != s; s = s->next) | ||
2269 | { | ||
2270 | int flags = fcntl (s->fdi->sock, F_GETFD); | ||
2271 | if ((flags == -1) && (errno == EBADF)) | ||
2272 | { | ||
2273 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2274 | "Got invalid file descriptor %d!\n", | ||
2275 | s->fdi->sock); | ||
2276 | } | ||
2277 | } | ||
2278 | #endif | ||
2279 | GNUNET_assert (0); | ||
2280 | return GNUNET_SYSERR; | ||
2281 | } | ||
2282 | for (pos = context->scheduled_head; NULL != pos; pos = pos->next) | ||
2283 | { | ||
2284 | int is_ready = GNUNET_NO; | ||
2285 | if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et) && | ||
2286 | GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, pos->fdi->sock)) | ||
2287 | { | ||
2288 | pos->fdi->et |= GNUNET_SCHEDULER_ET_IN; | ||
2289 | is_ready = GNUNET_YES; | ||
2290 | } | ||
2291 | if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et) && | ||
2292 | GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, pos->fdi->sock)) | ||
2293 | { | ||
2294 | pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT; | ||
2295 | is_ready = GNUNET_YES; | ||
2296 | } | ||
2297 | if (GNUNET_YES == is_ready) | ||
2298 | { | ||
2299 | GNUNET_SCHEDULER_task_ready (pos->task, pos->fdi); | ||
2300 | } | ||
2301 | } | ||
2302 | tasks_ready = GNUNET_SCHEDULER_run_from_driver (sh); | ||
2303 | GNUNET_assert (GNUNET_SYSERR != tasks_ready); | ||
2304 | } | ||
2305 | return GNUNET_OK; | ||
2306 | } | ||
2307 | |||
2308 | |||
2309 | void | ||
2310 | select_set_wakeup(void *cls, | ||
2311 | struct GNUNET_TIME_Absolute dt) | ||
2312 | { | ||
2313 | struct DriverContext *context = cls; | ||
2314 | GNUNET_assert (NULL != context); | ||
2315 | |||
2316 | context->timeout = GNUNET_TIME_absolute_get_remaining (dt); | ||
2317 | } | ||
2318 | |||
2319 | |||
2078 | /** | 2320 | /** |
2079 | * Obtain the driver for using select() as the event loop. | 2321 | * Obtain the driver for using select() as the event loop. |
2080 | * | 2322 | * |
2081 | * @return NULL on error | 2323 | * @return NULL on error |
2082 | */ | 2324 | */ |
2083 | const struct GNUNET_SCHEDULER_Driver * | 2325 | struct GNUNET_SCHEDULER_Driver * |
2084 | GNUNET_SCHEDULER_driver_select () | 2326 | GNUNET_SCHEDULER_driver_select () |
2085 | { | 2327 | { |
2086 | GNUNET_break (0); // not implemented | 2328 | struct GNUNET_SCHEDULER_Driver *select_driver; |
2087 | return NULL; | 2329 | select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver); |
2330 | |||
2331 | select_driver->loop = &select_loop; | ||
2332 | select_driver->add = &select_add; | ||
2333 | select_driver->del = &select_del; | ||
2334 | select_driver->set_wakeup = &select_set_wakeup; | ||
2335 | |||
2336 | return select_driver; | ||
2088 | } | 2337 | } |
2089 | 2338 | ||
2090 | 2339 | ||