aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlurchi <lurchi@strangeplace.net>2017-12-30 21:32:59 +0100
committerlurchi <lurchi@strangeplace.net>2017-12-30 21:32:59 +0100
commitdca8eb9c44dbdfa3fc572dde40c1e0927cfee8db (patch)
treee0b2a09e6d4777308bb9b30511815b4d5f756891 /src
parent5c8feda7faa01365a1fb6983595ceb65dfe4fb11 (diff)
parent11f78ccd0b66e08b8d1084cc335daac99d3f6a7e (diff)
downloadgnunet-dca8eb9c44dbdfa3fc572dde40c1e0927cfee8db.tar.gz
gnunet-dca8eb9c44dbdfa3fc572dde40c1e0927cfee8db.zip
merge branch 'refactoring-scheduler'
Diffstat (limited to 'src')
-rw-r--r--src/fs/test_fs_download_persistence.c1
-rw-r--r--src/fs/test_fs_publish_persistence.c1
-rw-r--r--src/include/gnunet_common.h15
-rw-r--r--src/include/gnunet_network_lib.h6
-rw-r--r--src/include/gnunet_scheduler_lib.h44
-rw-r--r--src/util/network.c6
-rw-r--r--src/util/program.c12
-rw-r--r--src/util/scheduler.c1535
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 */
466int 466int
467GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc); 467GNUNET_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 */
476struct sockaddr* 476struct sockaddr*
477GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc); 477GNUNET_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 */
486socklen_t 486socklen_t
487GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc); 487GNUNET_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 */
227void 228void
228GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, 229GNUNET_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 */
254int 256int
255GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh); 257GNUNET_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 */
362const struct GNUNET_SCHEDULER_Driver * 370struct GNUNET_SCHEDULER_Driver *
363GNUNET_SCHEDULER_driver_select (void); 371GNUNET_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 */
1225int 1225int
1226GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) 1226GNUNET_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 */
1238struct sockaddr* 1238struct sockaddr*
1239GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc) 1239GNUNET_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 */
1251socklen_t 1251socklen_t
1252GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc) 1252GNUNET_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 */
74static void
75shutdown_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 */
226struct 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 */
254struct 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 */
283static 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 */
234static struct GNUNET_SCHEDULER_Task *pending_head; 288static struct GNUNET_SCHEDULER_Task *pending_head;
@@ -330,6 +384,11 @@ static struct GNUNET_SCHEDULER_TaskContext tc;
330 */ 384 */
331static void *scheduler_select_cls; 385static void *scheduler_select_cls;
332 386
387/**
388 * Scheduler handle used for the driver functions
389 */
390static 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 */
373static void 430struct GNUNET_TIME_Absolute
374update_sets (struct GNUNET_NETWORK_FDSet *rs, 431get_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 */
423static int
424set_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 */
450static int
451is_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 */
504static void
505check_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 */
569static void
570destroy_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
589dump_backtrace (struct GNUNET_SCHEDULER_Task *t) 513dump_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 */
612static void 533static void
613run_ready (struct GNUNET_NETWORK_FDSet *rs, 534destroy_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// */
709static void 606//static void
710short_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/** 635void
739 * Check if the system is still alive. Trigger shutdown if we 636shutdown_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 */
745static int
746check_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
785GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, 678GNUNET_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,
791void 684 .timeout = GNUNET_TIME_UNIT_FOREVER_REL};
792GNUNET_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
736void
737init_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 */
850void 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
873void
874shutdown_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 *
1038GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) 899GNUNET_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 */
1237struct GNUNET_SCHEDULER_Task * 1111struct GNUNET_SCHEDULER_Task *
1238GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, 1112GNUNET_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,
1305struct GNUNET_SCHEDULER_Task * 1179struct GNUNET_SCHEDULER_Task *
1306GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, 1180GNUNET_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 */
1332struct GNUNET_SCHEDULER_Task * 1206struct GNUNET_SCHEDULER_Task *
1333GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, 1207GNUNET_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 */
1352struct GNUNET_SCHEDULER_Task * 1226struct GNUNET_SCHEDULER_Task *
1353GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, 1227GNUNET_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 */
1291void
1292check_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
1436static struct GNUNET_SCHEDULER_Task * 1337static struct GNUNET_SCHEDULER_Task *
1437add_without_sets (struct GNUNET_TIME_Relative delay, 1338add_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 */
1544struct GNUNET_SCHEDULER_Task * 1435struct GNUNET_SCHEDULER_Task *
1545GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, 1436GNUNET_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
1655void
1656extract_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 */
1831void 1841void
1832GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, 1842GNUNET_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 */
1873int 1887int
1874GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) 1888GNUNET_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 */
1980int 2037int
1981GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, 2038GNUNET_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
2137int
2138select_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
2167int
2168select_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
2197int
2198select_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
2309void
2310select_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 */
2083const struct GNUNET_SCHEDULER_Driver * 2325struct GNUNET_SCHEDULER_Driver *
2084GNUNET_SCHEDULER_driver_select () 2326GNUNET_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