diff options
author | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-01-02 16:48:03 +0100 |
---|---|---|
committer | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-01-02 16:48:03 +0100 |
commit | 7c1f035ed971e12882cd7a65c7d36883842945b1 (patch) | |
tree | 3828089ef8124270b976ac94902ba27210d275a3 /src/util | |
parent | 92d8c8a77e242a61927acc0e22fcecea479e6c43 (diff) | |
parent | 61f532f18450e0d7c72f0c17f4a20b5854cf53bf (diff) | |
download | gnunet-7c1f035ed971e12882cd7a65c7d36883842945b1.tar.gz gnunet-7c1f035ed971e12882cd7a65c7d36883842945b1.zip |
-merge
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/client.c | 41 | ||||
-rw-r--r-- | src/util/mq.c | 22 | ||||
-rw-r--r-- | src/util/mst.c | 27 | ||||
-rw-r--r-- | src/util/network.c | 6 | ||||
-rw-r--r-- | src/util/program.c | 12 | ||||
-rw-r--r-- | src/util/scheduler.c | 1535 | ||||
-rw-r--r-- | src/util/service.c | 31 | ||||
-rw-r--r-- | src/util/time.c | 2 |
8 files changed, 1017 insertions, 659 deletions
diff --git a/src/util/client.c b/src/util/client.c index 3d74bff33..e5bf7e176 100644 --- a/src/util/client.c +++ b/src/util/client.c | |||
@@ -261,14 +261,27 @@ transmit_ready (void *cls) | |||
261 | pos = (const char *) cstate->msg; | 261 | pos = (const char *) cstate->msg; |
262 | len = ntohs (cstate->msg->size); | 262 | len = ntohs (cstate->msg->size); |
263 | GNUNET_assert (cstate->msg_off < len); | 263 | GNUNET_assert (cstate->msg_off < len); |
264 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
265 | "client: message of type %u trying to send with socket %p (MQ: %p\n", | ||
266 | ntohs(cstate->msg->type), | ||
267 | cstate->sock, | ||
268 | cstate->mq); | ||
269 | |||
264 | RETRY: | 270 | RETRY: |
265 | ret = GNUNET_NETWORK_socket_send (cstate->sock, | 271 | ret = GNUNET_NETWORK_socket_send (cstate->sock, |
266 | &pos[cstate->msg_off], | 272 | &pos[cstate->msg_off], |
267 | len - cstate->msg_off); | 273 | len - cstate->msg_off); |
268 | if (-1 == ret) | 274 | if (-1 == ret) |
269 | { | 275 | { |
270 | if (EINTR == errno) | 276 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
277 | "client: error during sending message of type %u\n", | ||
278 | ntohs(cstate->msg->type)); | ||
279 | if (EINTR == errno){ | ||
280 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
281 | "client: retrying message of type %u\n", | ||
282 | ntohs(cstate->msg->type)); | ||
271 | goto RETRY; | 283 | goto RETRY; |
284 | } | ||
272 | GNUNET_MQ_inject_error (cstate->mq, | 285 | GNUNET_MQ_inject_error (cstate->mq, |
273 | GNUNET_MQ_ERROR_WRITE); | 286 | GNUNET_MQ_ERROR_WRITE); |
274 | return; | 287 | return; |
@@ -277,6 +290,9 @@ transmit_ready (void *cls) | |||
277 | cstate->msg_off += ret; | 290 | cstate->msg_off += ret; |
278 | if (cstate->msg_off < len) | 291 | if (cstate->msg_off < len) |
279 | { | 292 | { |
293 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
294 | "client: rescheduling message of type %u\n", | ||
295 | ntohs(cstate->msg->type)); | ||
280 | cstate->send_task | 296 | cstate->send_task |
281 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | 297 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, |
282 | cstate->sock, | 298 | cstate->sock, |
@@ -286,6 +302,9 @@ transmit_ready (void *cls) | |||
286 | GNUNET_MQ_impl_send_in_flight (cstate->mq); | 302 | GNUNET_MQ_impl_send_in_flight (cstate->mq); |
287 | return; | 303 | return; |
288 | } | 304 | } |
305 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
306 | "client: sending message of type %u successful\n", | ||
307 | ntohs(cstate->msg->type)); | ||
289 | cstate->msg = NULL; | 308 | cstate->msg = NULL; |
290 | GNUNET_MQ_impl_send_continue (cstate->mq); | 309 | GNUNET_MQ_impl_send_continue (cstate->mq); |
291 | } | 310 | } |
@@ -297,7 +316,9 @@ transmit_ready (void *cls) | |||
297 | * | 316 | * |
298 | * @param cls the `struct ClientState` | 317 | * @param cls the `struct ClientState` |
299 | * @param msg message we received. | 318 | * @param msg message we received. |
300 | * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing | 319 | * @return #GNUNET_OK on success, |
320 | * #GNUNET_NO to stop further processing due to disconnect (no error) | ||
321 | * #GNUNET_SYSERR to stop further processing due to error | ||
301 | */ | 322 | */ |
302 | static int | 323 | static int |
303 | recv_message (void *cls, | 324 | recv_message (void *cls, |
@@ -306,7 +327,7 @@ recv_message (void *cls, | |||
306 | struct ClientState *cstate = cls; | 327 | struct ClientState *cstate = cls; |
307 | 328 | ||
308 | if (GNUNET_YES == cstate->in_destroy) | 329 | if (GNUNET_YES == cstate->in_destroy) |
309 | return GNUNET_SYSERR; | 330 | return GNUNET_NO; |
310 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 331 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
311 | "Received message of type %u and size %u from %s\n", | 332 | "Received message of type %u and size %u from %s\n", |
312 | ntohs (msg->type), | 333 | ntohs (msg->type), |
@@ -315,7 +336,7 @@ recv_message (void *cls, | |||
315 | GNUNET_MQ_inject_message (cstate->mq, | 336 | GNUNET_MQ_inject_message (cstate->mq, |
316 | msg); | 337 | msg); |
317 | if (GNUNET_YES == cstate->in_destroy) | 338 | if (GNUNET_YES == cstate->in_destroy) |
318 | return GNUNET_SYSERR; | 339 | return GNUNET_NO; |
319 | return GNUNET_OK; | 340 | return GNUNET_OK; |
320 | } | 341 | } |
321 | 342 | ||
@@ -371,8 +392,12 @@ connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq, | |||
371 | GNUNET_SCHEDULER_cancel (cstate->recv_task); | 392 | GNUNET_SCHEDULER_cancel (cstate->recv_task); |
372 | if (NULL != cstate->retry_task) | 393 | if (NULL != cstate->retry_task) |
373 | GNUNET_SCHEDULER_cancel (cstate->retry_task); | 394 | GNUNET_SCHEDULER_cancel (cstate->retry_task); |
374 | if (NULL != cstate->sock) | 395 | if (NULL != cstate->sock){ |
396 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
397 | "client: destroying socket: %p\n", | ||
398 | cstate->sock); | ||
375 | GNUNET_NETWORK_socket_close (cstate->sock); | 399 | GNUNET_NETWORK_socket_close (cstate->sock); |
400 | } | ||
376 | cancel_aps (cstate); | 401 | cancel_aps (cstate); |
377 | GNUNET_free (cstate->service_name); | 402 | GNUNET_free (cstate->service_name); |
378 | GNUNET_free_non_null (cstate->hostname); | 403 | GNUNET_free_non_null (cstate->hostname); |
@@ -794,8 +819,12 @@ connection_client_send_impl (struct GNUNET_MQ_Handle *mq, | |||
794 | GNUNET_assert (NULL == cstate->send_task); | 819 | GNUNET_assert (NULL == cstate->send_task); |
795 | cstate->msg = msg; | 820 | cstate->msg = msg; |
796 | cstate->msg_off = 0; | 821 | cstate->msg_off = 0; |
797 | if (NULL == cstate->sock) | 822 | if (NULL == cstate->sock){ |
823 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
824 | "client: message of type %u waiting for socket\n", | ||
825 | ntohs(msg->type)); | ||
798 | return; /* still waiting for connection */ | 826 | return; /* still waiting for connection */ |
827 | } | ||
799 | cstate->send_task | 828 | cstate->send_task |
800 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | 829 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, |
801 | cstate->sock, | 830 | cstate->sock, |
diff --git a/src/util/mq.c b/src/util/mq.c index 90b2aa968..8d71359ac 100644 --- a/src/util/mq.c +++ b/src/util/mq.c | |||
@@ -357,6 +357,12 @@ GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq, | |||
357 | } | 357 | } |
358 | GNUNET_assert (NULL == mq->envelope_head); | 358 | GNUNET_assert (NULL == mq->envelope_head); |
359 | mq->current_envelope = ev; | 359 | mq->current_envelope = ev; |
360 | |||
361 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
362 | "mq: sending message of type %u, queue empty (MQ: %p)\n", | ||
363 | ntohs(ev->mh->type), | ||
364 | mq); | ||
365 | |||
360 | mq->send_impl (mq, | 366 | mq->send_impl (mq, |
361 | ev->mh, | 367 | ev->mh, |
362 | mq->impl_state); | 368 | mq->impl_state); |
@@ -452,6 +458,11 @@ impl_send_continue (void *cls) | |||
452 | GNUNET_CONTAINER_DLL_remove (mq->envelope_head, | 458 | GNUNET_CONTAINER_DLL_remove (mq->envelope_head, |
453 | mq->envelope_tail, | 459 | mq->envelope_tail, |
454 | mq->current_envelope); | 460 | mq->current_envelope); |
461 | |||
462 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
463 | "mq: sending message of type %u from queue\n", | ||
464 | ntohs(mq->current_envelope->mh->type)); | ||
465 | |||
455 | mq->send_impl (mq, | 466 | mq->send_impl (mq, |
456 | mq->current_envelope->mh, | 467 | mq->current_envelope->mh, |
457 | mq->impl_state); | 468 | mq->impl_state); |
@@ -840,6 +851,9 @@ GNUNET_MQ_destroy (struct GNUNET_MQ_Handle *mq) | |||
840 | ev); | 851 | ev); |
841 | GNUNET_assert (0 < mq->queue_length); | 852 | GNUNET_assert (0 < mq->queue_length); |
842 | mq->queue_length--; | 853 | mq->queue_length--; |
854 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
855 | "MQ destroy drops message of type %u\n", | ||
856 | ntohs (ev->mh->type)); | ||
843 | GNUNET_MQ_discard (ev); | 857 | GNUNET_MQ_discard (ev); |
844 | } | 858 | } |
845 | if (NULL != mq->current_envelope) | 859 | if (NULL != mq->current_envelope) |
@@ -847,6 +861,9 @@ GNUNET_MQ_destroy (struct GNUNET_MQ_Handle *mq) | |||
847 | /* we can only discard envelopes that | 861 | /* we can only discard envelopes that |
848 | * are not queued! */ | 862 | * are not queued! */ |
849 | mq->current_envelope->parent_queue = NULL; | 863 | mq->current_envelope->parent_queue = NULL; |
864 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
865 | "MQ destroy drops current message of type %u\n", | ||
866 | ntohs (mq->current_envelope->mh->type)); | ||
850 | GNUNET_MQ_discard (mq->current_envelope); | 867 | GNUNET_MQ_discard (mq->current_envelope); |
851 | mq->current_envelope = NULL; | 868 | mq->current_envelope = NULL; |
852 | GNUNET_assert (0 < mq->queue_length); | 869 | GNUNET_assert (0 < mq->queue_length); |
@@ -928,6 +945,11 @@ GNUNET_MQ_send_cancel (struct GNUNET_MQ_Envelope *ev) | |||
928 | GNUNET_CONTAINER_DLL_remove (mq->envelope_head, | 945 | GNUNET_CONTAINER_DLL_remove (mq->envelope_head, |
929 | mq->envelope_tail, | 946 | mq->envelope_tail, |
930 | mq->current_envelope); | 947 | mq->current_envelope); |
948 | |||
949 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
950 | "mq: sending canceled message of type %u queue\n", | ||
951 | ntohs(ev->mh->type)); | ||
952 | |||
931 | mq->send_impl (mq, | 953 | mq->send_impl (mq, |
932 | mq->current_envelope->mh, | 954 | mq->current_envelope->mh, |
933 | mq->impl_state); | 955 | mq->impl_state); |
diff --git a/src/util/mst.c b/src/util/mst.c index 0d90c5d10..5e472965f 100644 --- a/src/util/mst.c +++ b/src/util/mst.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2010, 2016 GNUnet e.V. | 3 | Copyright (C) 2010, 2016, 2017 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
@@ -126,6 +126,7 @@ GNUNET_MST_from_buffer (struct GNUNET_MessageStreamTokenizer *mst, | |||
126 | int need_align; | 126 | int need_align; |
127 | unsigned long offset; | 127 | unsigned long offset; |
128 | int ret; | 128 | int ret; |
129 | int cbret; | ||
129 | 130 | ||
130 | GNUNET_assert (mst->off <= mst->pos); | 131 | GNUNET_assert (mst->off <= mst->pos); |
131 | GNUNET_assert (mst->pos <= mst->curr_buf); | 132 | GNUNET_assert (mst->pos <= mst->curr_buf); |
@@ -229,9 +230,17 @@ do_align: | |||
229 | if (one_shot == GNUNET_YES) | 230 | if (one_shot == GNUNET_YES) |
230 | one_shot = GNUNET_SYSERR; | 231 | one_shot = GNUNET_SYSERR; |
231 | mst->off += want; | 232 | mst->off += want; |
232 | if (GNUNET_SYSERR == mst->cb (mst->cb_cls, | 233 | if (GNUNET_OK != |
233 | hdr)) | 234 | (cbret = mst->cb (mst->cb_cls, |
235 | hdr))) | ||
236 | { | ||
237 | if (GNUNET_SYSERR == cbret) | ||
238 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
239 | "Failure processing message of type %u and size %u\n", | ||
240 | ntohs (hdr->type), | ||
241 | ntohs (hdr->size)); | ||
234 | return GNUNET_SYSERR; | 242 | return GNUNET_SYSERR; |
243 | } | ||
235 | if (mst->off == mst->pos) | 244 | if (mst->off == mst->pos) |
236 | { | 245 | { |
237 | /* reset to beginning of buffer, it's free right now! */ | 246 | /* reset to beginning of buffer, it's free right now! */ |
@@ -271,9 +280,17 @@ do_align: | |||
271 | } | 280 | } |
272 | if (one_shot == GNUNET_YES) | 281 | if (one_shot == GNUNET_YES) |
273 | one_shot = GNUNET_SYSERR; | 282 | one_shot = GNUNET_SYSERR; |
274 | if (GNUNET_SYSERR == mst->cb (mst->cb_cls, | 283 | if (GNUNET_OK != |
275 | hdr)) | 284 | (cbret = mst->cb (mst->cb_cls, |
285 | hdr))) | ||
286 | { | ||
287 | if (GNUNET_SYSERR == cbret) | ||
288 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
289 | "Failure processing message of type %u and size %u\n", | ||
290 | ntohs (hdr->type), | ||
291 | ntohs (hdr->size)); | ||
276 | return GNUNET_SYSERR; | 292 | return GNUNET_SYSERR; |
293 | } | ||
277 | buf += want; | 294 | buf += want; |
278 | size -= want; | 295 | size -= want; |
279 | } | 296 | } |
diff --git a/src/util/network.c b/src/util/network.c index 942288613..cf5ef3e00 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -1223,7 +1223,7 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, | |||
1223 | * @return POSIX file descriptor | 1223 | * @return POSIX file descriptor |
1224 | */ | 1224 | */ |
1225 | int | 1225 | int |
1226 | GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) | 1226 | GNUNET_NETWORK_get_fd (const struct GNUNET_NETWORK_Handle *desc) |
1227 | { | 1227 | { |
1228 | return desc->fd; | 1228 | return desc->fd; |
1229 | } | 1229 | } |
@@ -1236,7 +1236,7 @@ GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) | |||
1236 | * @return sockaddr | 1236 | * @return sockaddr |
1237 | */ | 1237 | */ |
1238 | struct sockaddr* | 1238 | struct sockaddr* |
1239 | GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc) | 1239 | GNUNET_NETWORK_get_addr (const struct GNUNET_NETWORK_Handle *desc) |
1240 | { | 1240 | { |
1241 | return desc->addr; | 1241 | return desc->addr; |
1242 | } | 1242 | } |
@@ -1249,7 +1249,7 @@ GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc) | |||
1249 | * @return socklen_t for sockaddr | 1249 | * @return socklen_t for sockaddr |
1250 | */ | 1250 | */ |
1251 | socklen_t | 1251 | socklen_t |
1252 | GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc) | 1252 | GNUNET_NETWORK_get_addrlen (const struct GNUNET_NETWORK_Handle *desc) |
1253 | { | 1253 | { |
1254 | return desc->addrlen; | 1254 | return desc->addrlen; |
1255 | } | 1255 | } |
diff --git a/src/util/program.c b/src/util/program.c index 92a9750f3..233792387 100644 --- a/src/util/program.c +++ b/src/util/program.c | |||
@@ -69,6 +69,16 @@ struct CommandContext | |||
69 | 69 | ||
70 | 70 | ||
71 | /** | 71 | /** |
72 | * task run when the scheduler shuts down | ||
73 | */ | ||
74 | static void | ||
75 | shutdown_task (void *cls) | ||
76 | { | ||
77 | GNUNET_SPEEDUP_stop_ (); | ||
78 | } | ||
79 | |||
80 | |||
81 | /** | ||
72 | * Initial task called by the scheduler for each | 82 | * Initial task called by the scheduler for each |
73 | * program. Runs the program-specific main task. | 83 | * program. Runs the program-specific main task. |
74 | */ | 84 | */ |
@@ -78,6 +88,7 @@ program_main (void *cls) | |||
78 | struct CommandContext *cc = cls; | 88 | struct CommandContext *cc = cls; |
79 | 89 | ||
80 | GNUNET_SPEEDUP_start_(cc->cfg); | 90 | GNUNET_SPEEDUP_start_(cc->cfg); |
91 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
81 | GNUNET_RESOLVER_connect (cc->cfg); | 92 | GNUNET_RESOLVER_connect (cc->cfg); |
82 | cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg); | 93 | cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg); |
83 | } | 94 | } |
@@ -306,7 +317,6 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName, | |||
306 | } | 317 | } |
307 | ret = GNUNET_OK; | 318 | ret = GNUNET_OK; |
308 | cleanup: | 319 | cleanup: |
309 | GNUNET_SPEEDUP_stop_ (); | ||
310 | GNUNET_CONFIGURATION_destroy (cfg); | 320 | GNUNET_CONFIGURATION_destroy (cfg); |
311 | GNUNET_free_non_null (cc.cfgfile); | 321 | GNUNET_free_non_null (cc.cfgfile); |
312 | GNUNET_free (cfg_fn); | 322 | GNUNET_free (cfg_fn); |
diff --git a/src/util/scheduler.c b/src/util/scheduler.c index 540a60557..b96e4e6c4 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 | |||
222 | |||
223 | /** | ||
224 | * A struct representing an event the select driver is waiting for | ||
225 | */ | ||
226 | struct Scheduled | ||
227 | { | ||
228 | struct Scheduled *prev; | ||
229 | |||
230 | struct Scheduled *next; | ||
231 | |||
232 | /** | ||
233 | * the task, the event is related to | ||
234 | */ | ||
235 | struct GNUNET_SCHEDULER_Task *task; | ||
236 | |||
237 | /** | ||
238 | * information about the network socket / file descriptor where | ||
239 | * the event is expected to occur | ||
240 | */ | ||
241 | struct GNUNET_SCHEDULER_FdInfo *fdi; | ||
242 | |||
243 | /** | ||
244 | * the event types (multiple event types can be ORed) the select | ||
245 | * driver is expected to wait for | ||
246 | */ | ||
247 | enum GNUNET_SCHEDULER_EventType et; | ||
248 | }; | ||
249 | |||
250 | |||
251 | /** | ||
252 | * Driver context used by GNUNET_SCHEDULER_run | ||
253 | */ | ||
254 | struct DriverContext | ||
255 | { | ||
256 | /** | ||
257 | * the head of a DLL containing information about the events the | ||
258 | * select driver is waiting for | ||
259 | */ | ||
260 | struct Scheduled *scheduled_head; | ||
227 | 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; | ||
228 | }; | 273 | }; |
229 | 274 | ||
230 | 275 | ||
231 | /** | 276 | /** |
277 | * The driver used for the event loop. Will be handed over to | ||
278 | * the scheduler in #GNUNET_SCHEDULER_run_from_driver(), peristed | ||
279 | * there in this variable for later use in functions like | ||
280 | * #GNUNET_SCHEDULER_add_select(), #add_without_sets() and | ||
281 | * #GNUNET_SCHEDULER_cancel(). | ||
282 | */ | ||
283 | static const struct GNUNET_SCHEDULER_Driver *scheduler_driver; | ||
284 | |||
285 | /** | ||
232 | * Head of list of tasks waiting for an event. | 286 | * Head of list of tasks waiting for an event. |
233 | */ | 287 | */ |
234 | static struct GNUNET_SCHEDULER_Task *pending_head; | 288 | static struct GNUNET_SCHEDULER_Task *pending_head; |
@@ -330,6 +384,11 @@ static struct GNUNET_SCHEDULER_TaskContext tc; | |||
330 | */ | 384 | */ |
331 | static void *scheduler_select_cls; | 385 | static void *scheduler_select_cls; |
332 | 386 | ||
387 | /** | ||
388 | * Scheduler handle used for the driver functions | ||
389 | */ | ||
390 | static struct GNUNET_SCHEDULER_Handle sh; | ||
391 | |||
333 | 392 | ||
334 | /** | 393 | /** |
335 | * Sets the select function to use in the scheduler (scheduler_select). | 394 | * Sets the select function to use in the scheduler (scheduler_select). |
@@ -364,115 +423,44 @@ check_priority (enum GNUNET_SCHEDULER_Priority p) | |||
364 | 423 | ||
365 | 424 | ||
366 | /** | 425 | /** |
367 | * Update all sets and timeout for select. | 426 | * chooses the nearest timeout from all pending tasks, to be used |
368 | * | 427 | * to tell the driver the next wakeup time (using its set_wakeup |
369 | * @param rs read-set, set to all FDs we would like to read (updated) | 428 | * callback) |
370 | * @param ws write-set, set to all FDs we would like to write (updated) | ||
371 | * @param timeout next timeout (updated) | ||
372 | */ | 429 | */ |
373 | static void | 430 | struct GNUNET_TIME_Absolute |
374 | update_sets (struct GNUNET_NETWORK_FDSet *rs, | 431 | get_timeout () |
375 | struct GNUNET_NETWORK_FDSet *ws, | ||
376 | struct GNUNET_TIME_Relative *timeout) | ||
377 | { | 432 | { |
378 | struct GNUNET_SCHEDULER_Task *pos; | 433 | struct GNUNET_SCHEDULER_Task *pos; |
379 | struct GNUNET_TIME_Absolute now; | 434 | struct GNUNET_TIME_Absolute now; |
380 | struct GNUNET_TIME_Relative to; | 435 | struct GNUNET_TIME_Absolute timeout; |
381 | 436 | ||
382 | now = GNUNET_TIME_absolute_get (); | ||
383 | pos = pending_timeout_head; | 437 | pos = pending_timeout_head; |
438 | now = GNUNET_TIME_absolute_get (); | ||
439 | timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
384 | if (NULL != pos) | 440 | if (NULL != pos) |
385 | { | 441 | { |
386 | to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); | ||
387 | if (timeout->rel_value_us > to.rel_value_us) | ||
388 | *timeout = to; | ||
389 | if (0 != pos->reason) | 442 | if (0 != pos->reason) |
390 | *timeout = GNUNET_TIME_UNIT_ZERO; | 443 | { |
444 | timeout = now; | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | timeout = pos->timeout; | ||
449 | } | ||
391 | } | 450 | } |
392 | for (pos = pending_head; NULL != pos; pos = pos->next) | 451 | for (pos = pending_head; NULL != pos; pos = pos->next) |
393 | { | 452 | { |
394 | if (pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) | 453 | if (0 != pos->reason) |
395 | { | 454 | { |
396 | to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); | 455 | timeout = now; |
397 | if (timeout->rel_value_us > to.rel_value_us) | 456 | } |
398 | *timeout = to; | 457 | else if ((pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) && |
458 | (timeout.abs_value_us > pos->timeout.abs_value_us)) | ||
459 | { | ||
460 | timeout = pos->timeout; | ||
399 | } | 461 | } |
400 | if (-1 != pos->read_fd) | ||
401 | GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); | ||
402 | if (-1 != pos->write_fd) | ||
403 | GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); | ||
404 | if (NULL != pos->read_set) | ||
405 | GNUNET_NETWORK_fdset_add (rs, pos->read_set); | ||
406 | if (NULL != pos->write_set) | ||
407 | GNUNET_NETWORK_fdset_add (ws, pos->write_set); | ||
408 | if (0 != pos->reason) | ||
409 | *timeout = GNUNET_TIME_UNIT_ZERO; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | |||
414 | /** | ||
415 | * Check if the ready set overlaps with the set we want to have ready. | ||
416 | * If so, update the want set (set all FDs that are ready). If not, | ||
417 | * return #GNUNET_NO. | ||
418 | * | ||
419 | * @param ready set that is ready | ||
420 | * @param want set that we want to be ready | ||
421 | * @return #GNUNET_YES if there was some overlap | ||
422 | */ | ||
423 | static int | ||
424 | set_overlaps (const struct GNUNET_NETWORK_FDSet *ready, | ||
425 | struct GNUNET_NETWORK_FDSet *want) | ||
426 | { | ||
427 | if ((NULL == want) || (NULL == ready)) | ||
428 | return GNUNET_NO; | ||
429 | if (GNUNET_NETWORK_fdset_overlap (ready, want)) | ||
430 | { | ||
431 | /* copy all over (yes, there maybe unrelated bits, | ||
432 | * but this should not hurt well-written clients) */ | ||
433 | GNUNET_NETWORK_fdset_copy (want, ready); | ||
434 | return GNUNET_YES; | ||
435 | } | 462 | } |
436 | return GNUNET_NO; | 463 | return timeout; |
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
441 | * Check if the given task is eligible to run now. | ||
442 | * Also set the reason why it is eligible. | ||
443 | * | ||
444 | * @param task task to check if it is ready | ||
445 | * @param now the current time | ||
446 | * @param rs set of FDs ready for reading | ||
447 | * @param ws set of FDs ready for writing | ||
448 | * @return #GNUNET_YES if we can run it, #GNUNET_NO if not. | ||
449 | */ | ||
450 | static int | ||
451 | is_ready (struct GNUNET_SCHEDULER_Task *task, | ||
452 | struct GNUNET_TIME_Absolute now, | ||
453 | const struct GNUNET_NETWORK_FDSet *rs, | ||
454 | const struct GNUNET_NETWORK_FDSet *ws) | ||
455 | { | ||
456 | enum GNUNET_SCHEDULER_Reason reason; | ||
457 | |||
458 | reason = task->reason; | ||
459 | if (now.abs_value_us >= task->timeout.abs_value_us) | ||
460 | reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | ||
461 | if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && | ||
462 | (((task->read_fd != -1) && | ||
463 | (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, task->read_fd))) || | ||
464 | (set_overlaps (rs, task->read_set)))) | ||
465 | reason |= GNUNET_SCHEDULER_REASON_READ_READY; | ||
466 | if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | ||
467 | (((task->write_fd != -1) && | ||
468 | (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, task->write_fd))) | ||
469 | || (set_overlaps (ws, task->write_set)))) | ||
470 | reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; | ||
471 | if (0 == reason) | ||
472 | return GNUNET_NO; /* not ready */ | ||
473 | reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; | ||
474 | task->reason = reason; | ||
475 | return GNUNET_YES; | ||
476 | } | 464 | } |
477 | 465 | ||
478 | 466 | ||
@@ -495,51 +483,6 @@ queue_ready_task (struct GNUNET_SCHEDULER_Task *task) | |||
495 | 483 | ||
496 | 484 | ||
497 | /** | 485 | /** |
498 | * Check which tasks are ready and move them | ||
499 | * to the respective ready queue. | ||
500 | * | ||
501 | * @param rs FDs ready for reading | ||
502 | * @param ws FDs ready for writing | ||
503 | */ | ||
504 | static void | ||
505 | check_ready (const struct GNUNET_NETWORK_FDSet *rs, | ||
506 | const struct GNUNET_NETWORK_FDSet *ws) | ||
507 | { | ||
508 | struct GNUNET_SCHEDULER_Task *pos; | ||
509 | struct GNUNET_SCHEDULER_Task *next; | ||
510 | struct GNUNET_TIME_Absolute now; | ||
511 | |||
512 | now = GNUNET_TIME_absolute_get (); | ||
513 | while (NULL != (pos = pending_timeout_head)) | ||
514 | { | ||
515 | if (now.abs_value_us >= pos->timeout.abs_value_us) | ||
516 | pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | ||
517 | if (0 == pos->reason) | ||
518 | break; | ||
519 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
520 | pending_timeout_tail, | ||
521 | pos); | ||
522 | if (pending_timeout_last == pos) | ||
523 | pending_timeout_last = NULL; | ||
524 | queue_ready_task (pos); | ||
525 | } | ||
526 | pos = pending_head; | ||
527 | while (NULL != pos) | ||
528 | { | ||
529 | next = pos->next; | ||
530 | if (GNUNET_YES == is_ready (pos, now, rs, ws)) | ||
531 | { | ||
532 | GNUNET_CONTAINER_DLL_remove (pending_head, | ||
533 | pending_tail, | ||
534 | pos); | ||
535 | queue_ready_task (pos); | ||
536 | } | ||
537 | pos = next; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | |||
542 | /** | ||
543 | * Request the shutdown of a scheduler. Marks all tasks | 486 | * Request the shutdown of a scheduler. Marks all tasks |
544 | * awaiting shutdown as ready. Note that tasks | 487 | * awaiting shutdown as ready. Note that tasks |
545 | * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call | 488 | * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call |
@@ -562,25 +505,6 @@ GNUNET_SCHEDULER_shutdown () | |||
562 | 505 | ||
563 | 506 | ||
564 | /** | 507 | /** |
565 | * Destroy a task (release associated resources) | ||
566 | * | ||
567 | * @param t task to destroy | ||
568 | */ | ||
569 | static void | ||
570 | destroy_task (struct GNUNET_SCHEDULER_Task *t) | ||
571 | { | ||
572 | if (NULL != t->read_set) | ||
573 | GNUNET_NETWORK_fdset_destroy (t->read_set); | ||
574 | if (NULL != t->write_set) | ||
575 | GNUNET_NETWORK_fdset_destroy (t->write_set); | ||
576 | #if EXECINFO | ||
577 | GNUNET_free (t->backtrace_strings); | ||
578 | #endif | ||
579 | GNUNET_free (t); | ||
580 | } | ||
581 | |||
582 | |||
583 | /** | ||
584 | * Output stack trace of task @a t. | 508 | * Output stack trace of task @a t. |
585 | * | 509 | * |
586 | * @param t task to dump stack trace of | 510 | * @param t task to dump stack trace of |
@@ -592,88 +516,59 @@ dump_backtrace (struct GNUNET_SCHEDULER_Task *t) | |||
592 | unsigned int i; | 516 | unsigned int i; |
593 | 517 | ||
594 | for (i = 0; i < t->num_backtrace_strings; i++) | 518 | for (i = 0; i < t->num_backtrace_strings; i++) |
595 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 519 | LOG (GNUNET_ERROR_TYPE_WARNING, |
596 | "Task %p trace %u: %s\n", | 520 | "Task %p trace %u: %s\n", |
597 | t, | 521 | t, |
598 | i, | 522 | i, |
599 | t->backtrace_strings[i]); | 523 | t->backtrace_strings[i]); |
600 | #endif | 524 | #endif |
601 | } | 525 | } |
602 | 526 | ||
603 | 527 | ||
604 | /** | 528 | /** |
605 | * Run at least one task in the highest-priority queue that is not | 529 | * Destroy a task (release associated resources) |
606 | * empty. Keep running tasks until we are either no longer running | ||
607 | * "URGENT" tasks or until we have at least one "pending" task (which | ||
608 | * may become ready, hence we should select on it). Naturally, if | ||
609 | * there are no more ready tasks, we also return. | ||
610 | * | 530 | * |
611 | * @param rs FDs ready for reading | 531 | * @param t task to destroy |
612 | * @param ws FDs ready for writing | ||
613 | */ | 532 | */ |
614 | static void | 533 | static void |
615 | run_ready (struct GNUNET_NETWORK_FDSet *rs, | 534 | destroy_task (struct GNUNET_SCHEDULER_Task *t) |
616 | struct GNUNET_NETWORK_FDSet *ws) | ||
617 | { | 535 | { |
618 | enum GNUNET_SCHEDULER_Priority p; | 536 | unsigned int i; |
619 | struct GNUNET_SCHEDULER_Task *pos; | ||
620 | 537 | ||
621 | max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; | 538 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
622 | do | 539 | "destroying task %p\n", |
540 | t); | ||
541 | |||
542 | if (GNUNET_YES == t->own_handles) | ||
623 | { | 543 | { |
624 | if (0 == ready_count) | 544 | for (i = 0; i != t->fds_len; ++i) |
625 | return; | ||
626 | GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]); | ||
627 | /* yes, p>0 is correct, 0 is "KEEP" which should | ||
628 | * always be an empty queue (see assertion)! */ | ||
629 | for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) | ||
630 | { | ||
631 | pos = ready_head[p]; | ||
632 | if (NULL != pos) | ||
633 | break; | ||
634 | } | ||
635 | GNUNET_assert (NULL != pos); /* ready_count wrong? */ | ||
636 | GNUNET_CONTAINER_DLL_remove (ready_head[p], | ||
637 | ready_tail[p], | ||
638 | pos); | ||
639 | ready_count--; | ||
640 | current_priority = pos->priority; | ||
641 | current_lifeness = pos->lifeness; | ||
642 | active_task = pos; | ||
643 | #if PROFILE_DELAYS | ||
644 | if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > | ||
645 | DELAY_THRESHOLD.rel_value_us) | ||
646 | { | 545 | { |
647 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 546 | const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd; |
648 | "Task %p took %s to be scheduled\n", | 547 | const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh; |
649 | pos, | 548 | if (fd) |
650 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), | 549 | { |
651 | 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 | } | ||
652 | } | 558 | } |
653 | #endif | ||
654 | tc.reason = pos->reason; | ||
655 | tc.read_ready = (NULL == pos->read_set) ? rs : pos->read_set; | ||
656 | if ((-1 != pos->read_fd) && | ||
657 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY))) | ||
658 | GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); | ||
659 | tc.write_ready = (NULL == pos->write_set) ? ws : pos->write_set; | ||
660 | if ((-1 != pos->write_fd) && | ||
661 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) | ||
662 | GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); | ||
663 | if ((0 != (tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | ||
664 | (-1 != pos->write_fd) && | ||
665 | (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd))) | ||
666 | GNUNET_assert (0); // added to ready in previous select loop! | ||
667 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
668 | "Running task: %p\n", | ||
669 | pos); | ||
670 | pos->callback (pos->callback_cls); | ||
671 | dump_backtrace (pos); | ||
672 | active_task = NULL; | ||
673 | destroy_task (pos); | ||
674 | tasks_run++; | ||
675 | } | 559 | } |
676 | 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); | ||
677 | } | 572 | } |
678 | 573 | ||
679 | 574 | ||
@@ -700,22 +595,22 @@ sighandler_pipe () | |||
700 | #endif | 595 | #endif |
701 | 596 | ||
702 | 597 | ||
703 | /** | 598 | ///** |
704 | * Wait for a short time. | 599 | // * Wait for a short time. |
705 | * 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 |
706 | * modern systems to context switch and allow another process to do | 601 | // * modern systems to context switch and allow another process to do |
707 | * some 'real' work). | 602 | // * some 'real' work). |
708 | * | 603 | // * |
709 | * @param ms how many ms to wait | 604 | // * @param ms how many ms to wait |
710 | */ | 605 | // */ |
711 | static void | 606 | //static void |
712 | short_wait (unsigned int ms) | 607 | //short_wait (unsigned int ms) |
713 | { | 608 | //{ |
714 | struct GNUNET_TIME_Relative timeout; | 609 | // struct GNUNET_TIME_Relative timeout; |
715 | 610 | // | |
716 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms); | 611 | // timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms); |
717 | (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout); | 612 | // (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout); |
718 | } | 613 | //} |
719 | 614 | ||
720 | 615 | ||
721 | /** | 616 | /** |
@@ -737,35 +632,31 @@ sighandler_shutdown () | |||
737 | } | 632 | } |
738 | 633 | ||
739 | 634 | ||
740 | /** | 635 | void |
741 | * Check if the system is still alive. Trigger shutdown if we | 636 | shutdown_if_no_lifeness () |
742 | * have tasks, but none of them give us lifeness. | ||
743 | * | ||
744 | * @return #GNUNET_OK to continue the main loop, | ||
745 | * #GNUNET_NO to exit | ||
746 | */ | ||
747 | static int | ||
748 | check_lifeness () | ||
749 | { | 637 | { |
750 | struct GNUNET_SCHEDULER_Task *t; | 638 | struct GNUNET_SCHEDULER_Task *t; |
751 | 639 | ||
752 | if (ready_count > 0) | 640 | if (ready_count > 0) |
753 | return GNUNET_OK; | 641 | return; |
754 | for (t = pending_head; NULL != t; t = t->next) | 642 | for (t = pending_head; NULL != t; t = t->next) |
755 | if (t->lifeness == GNUNET_YES) | 643 | if (GNUNET_YES == t->lifeness) |
756 | return GNUNET_OK; | 644 | return; |
757 | for (t = shutdown_head; NULL != t; t = t->next) | 645 | for (t = shutdown_head; NULL != t; t = t->next) |
758 | if (t->lifeness == GNUNET_YES) | 646 | if (GNUNET_YES == t->lifeness) |
759 | return GNUNET_OK; | 647 | return; |
760 | for (t = pending_timeout_head; NULL != t; t = t->next) | 648 | for (t = pending_timeout_head; NULL != t; t = t->next) |
761 | if (t->lifeness == GNUNET_YES) | 649 | if (GNUNET_YES == t->lifeness) |
762 | return GNUNET_OK; | 650 | return; |
763 | 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) | ||
764 | { | 654 | { |
765 | GNUNET_SCHEDULER_shutdown (); | 655 | struct GNUNET_SCHEDULER_Task *next = t->next; |
766 | return GNUNET_OK; | 656 | GNUNET_SCHEDULER_cancel (t); |
657 | t = next; | ||
767 | } | 658 | } |
768 | return GNUNET_NO; | 659 | GNUNET_SCHEDULER_shutdown (); |
769 | } | 660 | } |
770 | 661 | ||
771 | 662 | ||
@@ -787,204 +678,17 @@ void | |||
787 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, | 678 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, |
788 | void *task_cls) | 679 | void *task_cls) |
789 | { | 680 | { |
790 | GNUNET_SCHEDULER_run_with_optional_signals(GNUNET_YES, task, task_cls); | 681 | struct GNUNET_SCHEDULER_Driver *driver; |
791 | } | 682 | struct DriverContext context = {.scheduled_head = NULL, |
792 | 683 | .scheduled_tail = NULL, | |
793 | void | 684 | .timeout = GNUNET_TIME_UNIT_FOREVER_REL}; |
794 | GNUNET_SCHEDULER_run_with_optional_signals (int install_signals, | 685 | |
795 | GNUNET_SCHEDULER_TaskCallback task, | 686 | driver = GNUNET_SCHEDULER_driver_select (); |
796 | void *task_cls) | 687 | driver->cls = &context; |
797 | { | 688 | |
798 | struct GNUNET_NETWORK_FDSet *rs; | 689 | GNUNET_SCHEDULER_run_with_driver (driver, task, task_cls); |
799 | struct GNUNET_NETWORK_FDSet *ws; | 690 | |
800 | struct GNUNET_TIME_Relative timeout; | 691 | GNUNET_free (driver); |
801 | int ret; | ||
802 | struct GNUNET_SIGNAL_Context *shc_int; | ||
803 | struct GNUNET_SIGNAL_Context *shc_term; | ||
804 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
805 | struct GNUNET_SIGNAL_Context *shc_gterm; | ||
806 | #endif | ||
807 | |||
808 | #ifndef MINGW | ||
809 | struct GNUNET_SIGNAL_Context *shc_quit; | ||
810 | struct GNUNET_SIGNAL_Context *shc_hup; | ||
811 | struct GNUNET_SIGNAL_Context *shc_pipe; | ||
812 | #endif | ||
813 | unsigned long long last_tr; | ||
814 | unsigned int busy_wait_warning; | ||
815 | const struct GNUNET_DISK_FileHandle *pr; | ||
816 | char c; | ||
817 | |||
818 | GNUNET_assert (NULL == active_task); | ||
819 | rs = GNUNET_NETWORK_fdset_create (); | ||
820 | ws = GNUNET_NETWORK_fdset_create (); | ||
821 | GNUNET_assert (NULL == shutdown_pipe_handle); | ||
822 | shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, | ||
823 | GNUNET_NO, | ||
824 | GNUNET_NO, | ||
825 | GNUNET_NO); | ||
826 | GNUNET_assert (NULL != shutdown_pipe_handle); | ||
827 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | ||
828 | GNUNET_DISK_PIPE_END_READ); | ||
829 | GNUNET_assert (NULL != pr); | ||
830 | my_pid = getpid (); | ||
831 | |||
832 | if (GNUNET_YES == install_signals) | ||
833 | { | ||
834 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
835 | "Registering signal handlers\n"); | ||
836 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, | ||
837 | &sighandler_shutdown); | ||
838 | shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, | ||
839 | &sighandler_shutdown); | ||
840 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
841 | shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, | ||
842 | &sighandler_shutdown); | ||
843 | #endif | ||
844 | #ifndef MINGW | ||
845 | shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, | ||
846 | &sighandler_pipe); | ||
847 | shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, | ||
848 | &sighandler_shutdown); | ||
849 | shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, | ||
850 | &sighandler_shutdown); | ||
851 | #endif | ||
852 | } | ||
853 | |||
854 | current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; | ||
855 | current_lifeness = GNUNET_YES; | ||
856 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, | ||
857 | task_cls, | ||
858 | GNUNET_SCHEDULER_REASON_STARTUP, | ||
859 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); | ||
860 | active_task = (void *) (long) -1; /* force passing of sanity check */ | ||
861 | GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, | ||
862 | &GNUNET_OS_install_parent_control_handler, | ||
863 | NULL); | ||
864 | active_task = NULL; | ||
865 | last_tr = 0; | ||
866 | busy_wait_warning = 0; | ||
867 | while (GNUNET_OK == check_lifeness ()) | ||
868 | { | ||
869 | GNUNET_NETWORK_fdset_zero (rs); | ||
870 | GNUNET_NETWORK_fdset_zero (ws); | ||
871 | timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
872 | update_sets (rs, ws, &timeout); | ||
873 | GNUNET_NETWORK_fdset_handle_set (rs, pr); | ||
874 | if (ready_count > 0) | ||
875 | { | ||
876 | /* no blocking, more work already ready! */ | ||
877 | timeout = GNUNET_TIME_UNIT_ZERO; | ||
878 | } | ||
879 | if (NULL == scheduler_select) | ||
880 | ret = GNUNET_NETWORK_socket_select (rs, | ||
881 | ws, | ||
882 | NULL, | ||
883 | timeout); | ||
884 | else | ||
885 | ret = scheduler_select (scheduler_select_cls, | ||
886 | rs, | ||
887 | ws, | ||
888 | NULL, | ||
889 | timeout); | ||
890 | if (ret == GNUNET_SYSERR) | ||
891 | { | ||
892 | if (errno == EINTR) | ||
893 | continue; | ||
894 | |||
895 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); | ||
896 | #ifndef MINGW | ||
897 | #if USE_LSOF | ||
898 | char lsof[512]; | ||
899 | |||
900 | snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); | ||
901 | (void) close (1); | ||
902 | (void) dup2 (2, 1); | ||
903 | if (0 != system (lsof)) | ||
904 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
905 | "system"); | ||
906 | #endif | ||
907 | #endif | ||
908 | #if DEBUG_FDS | ||
909 | struct GNUNET_SCHEDULER_Task *t; | ||
910 | |||
911 | for (t = pending_head; NULL != t; t = t->next) | ||
912 | { | ||
913 | if (-1 != t->read_fd) | ||
914 | { | ||
915 | int flags = fcntl (t->read_fd, F_GETFD); | ||
916 | if ((flags == -1) && (errno == EBADF)) | ||
917 | { | ||
918 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
919 | "Got invalid file descriptor %d!\n", | ||
920 | t->read_fd); | ||
921 | dump_backtrace (t); | ||
922 | } | ||
923 | } | ||
924 | if (-1 != t->write_fd) | ||
925 | { | ||
926 | int flags = fcntl (t->write_fd, F_GETFD); | ||
927 | if ((flags == -1) && (errno == EBADF)) | ||
928 | { | ||
929 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
930 | "Got invalid file descriptor %d!\n", | ||
931 | t->write_fd); | ||
932 | dump_backtrace (t); | ||
933 | } | ||
934 | } | ||
935 | } | ||
936 | #endif | ||
937 | GNUNET_assert (0); | ||
938 | break; | ||
939 | } | ||
940 | |||
941 | if ( (0 == ret) && | ||
942 | (0 == timeout.rel_value_us) && | ||
943 | (busy_wait_warning > 16) ) | ||
944 | { | ||
945 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
946 | "Looks like we're busy waiting...\n"); | ||
947 | short_wait (100); /* mitigate */ | ||
948 | } | ||
949 | check_ready (rs, ws); | ||
950 | run_ready (rs, ws); | ||
951 | if (GNUNET_NETWORK_fdset_handle_isset (rs, pr)) | ||
952 | { | ||
953 | /* consume the signal */ | ||
954 | GNUNET_DISK_file_read (pr, &c, sizeof (c)); | ||
955 | /* mark all active tasks as ready due to shutdown */ | ||
956 | GNUNET_SCHEDULER_shutdown (); | ||
957 | } | ||
958 | if (last_tr == tasks_run) | ||
959 | { | ||
960 | short_wait (1); | ||
961 | busy_wait_warning++; | ||
962 | } | ||
963 | else | ||
964 | { | ||
965 | last_tr = tasks_run; | ||
966 | busy_wait_warning = 0; | ||
967 | } | ||
968 | } | ||
969 | |||
970 | if (GNUNET_YES == install_signals) | ||
971 | { | ||
972 | GNUNET_SIGNAL_handler_uninstall (shc_int); | ||
973 | GNUNET_SIGNAL_handler_uninstall (shc_term); | ||
974 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
975 | GNUNET_SIGNAL_handler_uninstall (shc_gterm); | ||
976 | #endif | ||
977 | #ifndef MINGW | ||
978 | GNUNET_SIGNAL_handler_uninstall (shc_pipe); | ||
979 | GNUNET_SIGNAL_handler_uninstall (shc_quit); | ||
980 | GNUNET_SIGNAL_handler_uninstall (shc_hup); | ||
981 | #endif | ||
982 | } | ||
983 | |||
984 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); | ||
985 | shutdown_pipe_handle = NULL; | ||
986 | GNUNET_NETWORK_fdset_destroy (rs); | ||
987 | GNUNET_NETWORK_fdset_destroy (ws); | ||
988 | } | 692 | } |
989 | 693 | ||
990 | 694 | ||
@@ -1029,9 +733,164 @@ GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p) | |||
1029 | } | 733 | } |
1030 | 734 | ||
1031 | 735 | ||
736 | void | ||
737 | init_fd_info (struct GNUNET_SCHEDULER_Task *t, | ||
738 | const struct GNUNET_NETWORK_Handle *const *read_nh, | ||
739 | unsigned int read_nh_len, | ||
740 | const struct GNUNET_NETWORK_Handle *const *write_nh, | ||
741 | unsigned int write_nh_len, | ||
742 | const struct GNUNET_DISK_FileHandle *const *read_fh, | ||
743 | unsigned int read_fh_len, | ||
744 | const struct GNUNET_DISK_FileHandle *const *write_fh, | ||
745 | unsigned int write_fh_len) | ||
746 | { | ||
747 | // FIXME: if we have exactly two network handles / exactly two file handles | ||
748 | // and they are equal, we can make one FdInfo with both | ||
749 | // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set. | ||
750 | struct GNUNET_SCHEDULER_FdInfo *fdi; | ||
751 | |||
752 | t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len; | ||
753 | if (1 == t->fds_len) | ||
754 | { | ||
755 | fdi = &t->fdx; | ||
756 | t->fds = fdi; | ||
757 | if (1 == read_nh_len) | ||
758 | { | ||
759 | fdi->fd = *read_nh; | ||
760 | GNUNET_assert (NULL != fdi->fd); | ||
761 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
762 | fdi->sock = GNUNET_NETWORK_get_fd (*read_nh); | ||
763 | t->read_fd = fdi->sock; | ||
764 | t->write_fd = -1; | ||
765 | } | ||
766 | else if (1 == write_nh_len) | ||
767 | { | ||
768 | fdi->fd = *write_nh; | ||
769 | GNUNET_assert (NULL != fdi->fd); | ||
770 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
771 | fdi->sock = GNUNET_NETWORK_get_fd (*write_nh); | ||
772 | t->read_fd = -1; | ||
773 | t->write_fd = fdi->sock; | ||
774 | } | ||
775 | else if (1 == read_fh_len) | ||
776 | { | ||
777 | fdi->fh = *read_fh; | ||
778 | GNUNET_assert (NULL != fdi->fh); | ||
779 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
780 | fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32 | ||
781 | t->read_fd = fdi->sock; | ||
782 | t->write_fd = -1; | ||
783 | } | ||
784 | else | ||
785 | { | ||
786 | fdi->fh = *write_fh; | ||
787 | GNUNET_assert (NULL != fdi->fh); | ||
788 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
789 | fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32 | ||
790 | t->read_fd = -1; | ||
791 | t->write_fd = fdi->sock; | ||
792 | } | ||
793 | } | ||
794 | else | ||
795 | { | ||
796 | fdi = GNUNET_new_array (t->fds_len, struct GNUNET_SCHEDULER_FdInfo); | ||
797 | t->fds = fdi; | ||
798 | t->read_fd = -1; | ||
799 | t->write_fd = -1; | ||
800 | unsigned int i; | ||
801 | for (i = 0; i != read_nh_len; ++i) | ||
802 | { | ||
803 | fdi->fd = read_nh[i]; | ||
804 | GNUNET_assert (NULL != fdi->fd); | ||
805 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
806 | fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]); | ||
807 | ++fdi; | ||
808 | } | ||
809 | for (i = 0; i != write_nh_len; ++i) | ||
810 | { | ||
811 | fdi->fd = write_nh[i]; | ||
812 | GNUNET_assert (NULL != fdi->fd); | ||
813 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
814 | fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]); | ||
815 | ++fdi; | ||
816 | } | ||
817 | for (i = 0; i != read_fh_len; ++i) | ||
818 | { | ||
819 | fdi->fh = read_fh[i]; | ||
820 | GNUNET_assert (NULL != fdi->fh); | ||
821 | fdi->et = GNUNET_SCHEDULER_ET_IN; | ||
822 | fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32 | ||
823 | ++fdi; | ||
824 | } | ||
825 | for (i = 0; i != write_fh_len; ++i) | ||
826 | { | ||
827 | fdi->fh = write_fh[i]; | ||
828 | GNUNET_assert (NULL != fdi->fh); | ||
829 | fdi->et = GNUNET_SCHEDULER_ET_OUT; | ||
830 | fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32 | ||
831 | ++fdi; | ||
832 | } | ||
833 | } | ||
834 | } | ||
835 | |||
836 | |||
837 | /** | ||
838 | * calls the given function @a func on each FdInfo related to @a t. | ||
839 | * Optionally updates the event type field in each FdInfo after calling | ||
840 | * @a func. | ||
841 | * | ||
842 | * @param t the task | ||
843 | * @param driver_func the function to call with each FdInfo contained in | ||
844 | * in @a t | ||
845 | * @param if_not_ready only call @a driver_func on FdInfos that are not | ||
846 | * ready | ||
847 | * @param et the event type to be set in each FdInfo after calling | ||
848 | * @a driver_func on it, or -1 if no updating not desired. | ||
849 | */ | ||
850 | void driver_add_multiple (struct GNUNET_SCHEDULER_Task *t, | ||
851 | enum GNUNET_SCHEDULER_EventType et) | ||
852 | { | ||
853 | struct GNUNET_SCHEDULER_FdInfo *fdi; | ||
854 | int success = GNUNET_YES; | ||
855 | |||
856 | for (int i = 0; i != t->fds_len; ++i) | ||
857 | { | ||
858 | fdi = &t->fds[i]; | ||
859 | success = scheduler_driver->add (scheduler_driver->cls, t, fdi) && success; | ||
860 | if (et != -1) | ||
861 | { | ||
862 | fdi->et = et; | ||
863 | } | ||
864 | } | ||
865 | if (GNUNET_YES != success) | ||
866 | { | ||
867 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
868 | "driver could not add task\n"); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | |||
873 | void | ||
874 | shutdown_cb (void *cls) | ||
875 | { | ||
876 | char c; | ||
877 | const struct GNUNET_DISK_FileHandle *pr; | ||
878 | |||
879 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | ||
880 | GNUNET_DISK_PIPE_END_READ); | ||
881 | GNUNET_assert (! GNUNET_DISK_handle_invalid (pr)); | ||
882 | /* consume the signal */ | ||
883 | GNUNET_DISK_file_read (pr, &c, sizeof (c)); | ||
884 | /* mark all active tasks as ready due to shutdown */ | ||
885 | GNUNET_SCHEDULER_shutdown (); | ||
886 | } | ||
887 | |||
888 | |||
1032 | /** | 889 | /** |
1033 | * Cancel the task with the specified identifier. | 890 | * Cancel the task with the specified identifier. |
1034 | * 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). | ||
1035 | * | 894 | * |
1036 | * @param task id of the task to cancel | 895 | * @param task id of the task to cancel |
1037 | * @return original closure of the task | 896 | * @return original closure of the task |
@@ -1040,34 +899,50 @@ void * | |||
1040 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) | 899 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) |
1041 | { | 900 | { |
1042 | enum GNUNET_SCHEDULER_Priority p; | 901 | enum GNUNET_SCHEDULER_Priority p; |
902 | int is_fd_task; | ||
1043 | void *ret; | 903 | void *ret; |
1044 | 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); | ||
1045 | GNUNET_assert ( (NULL != active_task) || | 911 | GNUNET_assert ( (NULL != active_task) || |
1046 | (GNUNET_NO == task->lifeness) ); | 912 | (GNUNET_NO == task->lifeness) ); |
1047 | if (! task->in_ready_list) | 913 | is_fd_task = (NULL != task->fds); |
914 | if (is_fd_task) | ||
1048 | { | 915 | { |
1049 | if ( (-1 == task->read_fd) && | 916 | int del_result = scheduler_driver->del (scheduler_driver->cls, task); |
1050 | (-1 == task->write_fd) && | 917 | if (GNUNET_OK != del_result) |
1051 | (NULL == task->read_set) && | ||
1052 | (NULL == task->write_set) ) | ||
1053 | { | 918 | { |
1054 | if (GNUNET_YES == task->on_shutdown) | 919 | LOG (GNUNET_ERROR_TYPE_ERROR, |
1055 | GNUNET_CONTAINER_DLL_remove (shutdown_head, | 920 | "driver could not delete task\n"); |
1056 | shutdown_tail, | 921 | GNUNET_assert (0); |
1057 | task); | ||
1058 | else | ||
1059 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
1060 | pending_timeout_tail, | ||
1061 | task); | ||
1062 | if (task == pending_timeout_last) | ||
1063 | pending_timeout_last = NULL; | ||
1064 | } | 922 | } |
1065 | else | 923 | } |
924 | if (! task->in_ready_list) | ||
925 | { | ||
926 | if (is_fd_task) | ||
1066 | { | 927 | { |
1067 | GNUNET_CONTAINER_DLL_remove (pending_head, | 928 | GNUNET_CONTAINER_DLL_remove (pending_head, |
1068 | pending_tail, | 929 | pending_tail, |
1069 | task); | 930 | task); |
1070 | } | 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 | } | ||
1071 | } | 946 | } |
1072 | else | 947 | else |
1073 | { | 948 | { |
@@ -1078,9 +953,6 @@ GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) | |||
1078 | ready_count--; | 953 | ready_count--; |
1079 | } | 954 | } |
1080 | ret = task->callback_cls; | 955 | ret = task->callback_cls; |
1081 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1082 | "Canceling task %p\n", | ||
1083 | task); | ||
1084 | destroy_task (task); | 956 | destroy_task (task); |
1085 | return ret; | 957 | return ret; |
1086 | } | 958 | } |
@@ -1101,7 +973,7 @@ init_backtrace (struct GNUNET_SCHEDULER_Task *t) | |||
1101 | = backtrace (backtrace_array, MAX_TRACE_DEPTH); | 973 | = backtrace (backtrace_array, MAX_TRACE_DEPTH); |
1102 | t->backtrace_strings = | 974 | t->backtrace_strings = |
1103 | backtrace_symbols (backtrace_array, | 975 | backtrace_symbols (backtrace_array, |
1104 | t->num_backtrace_strings); | 976 | t->num_backtrace_strings); |
1105 | dump_backtrace (t); | 977 | dump_backtrace (t); |
1106 | #endif | 978 | #endif |
1107 | } | 979 | } |
@@ -1218,7 +1090,7 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at, | |||
1218 | pending_timeout_last = t; | 1090 | pending_timeout_last = t; |
1219 | 1091 | ||
1220 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1092 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1221 | "Adding task: %p\n", | 1093 | "Adding task %p\n", |
1222 | t); | 1094 | t); |
1223 | init_backtrace (t); | 1095 | init_backtrace (t); |
1224 | return t; | 1096 | return t; |
@@ -1238,8 +1110,8 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at, | |||
1238 | */ | 1110 | */ |
1239 | struct GNUNET_SCHEDULER_Task * | 1111 | struct GNUNET_SCHEDULER_Task * |
1240 | GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, | 1112 | GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, |
1241 | enum GNUNET_SCHEDULER_Priority priority, | 1113 | enum GNUNET_SCHEDULER_Priority priority, |
1242 | GNUNET_SCHEDULER_TaskCallback task, | 1114 | GNUNET_SCHEDULER_TaskCallback task, |
1243 | void *task_cls) | 1115 | void *task_cls) |
1244 | { | 1116 | { |
1245 | 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), |
@@ -1307,12 +1179,12 @@ GNUNET_SCHEDULER_add_at (struct GNUNET_TIME_Absolute at, | |||
1307 | struct GNUNET_SCHEDULER_Task * | 1179 | struct GNUNET_SCHEDULER_Task * |
1308 | GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, | 1180 | GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, |
1309 | GNUNET_SCHEDULER_TaskCallback task, | 1181 | GNUNET_SCHEDULER_TaskCallback task, |
1310 | void *task_cls) | 1182 | void *task_cls) |
1311 | { | 1183 | { |
1312 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, | 1184 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, |
1313 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, | 1185 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, |
1314 | task, | 1186 | task, |
1315 | task_cls); | 1187 | task_cls); |
1316 | } | 1188 | } |
1317 | 1189 | ||
1318 | 1190 | ||
@@ -1333,11 +1205,11 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, | |||
1333 | */ | 1205 | */ |
1334 | struct GNUNET_SCHEDULER_Task * | 1206 | struct GNUNET_SCHEDULER_Task * |
1335 | GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, | 1207 | GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, |
1336 | void *task_cls) | 1208 | void *task_cls) |
1337 | { | 1209 | { |
1338 | return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, | 1210 | return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, |
1339 | task, | 1211 | task, |
1340 | task_cls); | 1212 | task_cls); |
1341 | } | 1213 | } |
1342 | 1214 | ||
1343 | 1215 | ||
@@ -1353,7 +1225,7 @@ GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, | |||
1353 | */ | 1225 | */ |
1354 | struct GNUNET_SCHEDULER_Task * | 1226 | struct GNUNET_SCHEDULER_Task * |
1355 | GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, | 1227 | GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, |
1356 | void *task_cls) | 1228 | void *task_cls) |
1357 | { | 1229 | { |
1358 | struct GNUNET_SCHEDULER_Task *t; | 1230 | struct GNUNET_SCHEDULER_Task *t; |
1359 | 1231 | ||
@@ -1370,12 +1242,12 @@ GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, | |||
1370 | t->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | 1242 | t->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; |
1371 | t->priority = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN; | 1243 | t->priority = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN; |
1372 | t->on_shutdown = GNUNET_YES; | 1244 | t->on_shutdown = GNUNET_YES; |
1373 | t->lifeness = GNUNET_YES; | 1245 | t->lifeness = GNUNET_NO; |
1374 | GNUNET_CONTAINER_DLL_insert (shutdown_head, | 1246 | GNUNET_CONTAINER_DLL_insert (shutdown_head, |
1375 | shutdown_tail, | 1247 | shutdown_tail, |
1376 | t); | 1248 | t); |
1377 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1249 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1378 | "Adding task: %p\n", | 1250 | "Adding shutdown task %p\n", |
1379 | t); | 1251 | t); |
1380 | init_backtrace (t); | 1252 | init_backtrace (t); |
1381 | return t; | 1253 | return t; |
@@ -1409,6 +1281,33 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, | |||
1409 | } | 1281 | } |
1410 | 1282 | ||
1411 | 1283 | ||
1284 | #if DEBUG_FDS | ||
1285 | /** | ||
1286 | * check a raw file descriptor and abort if it is bad (for debugging purposes) | ||
1287 | * | ||
1288 | * @param t the task related to the file descriptor | ||
1289 | * @param raw_fd the raw file descriptor to check | ||
1290 | */ | ||
1291 | void | ||
1292 | check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd) | ||
1293 | { | ||
1294 | if (-1 != raw_fd) | ||
1295 | { | ||
1296 | int flags = fcntl (raw_fd, F_GETFD); | ||
1297 | |||
1298 | if ((flags == -1) && (errno == EBADF)) | ||
1299 | { | ||
1300 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1301 | "Got invalid file descriptor %d!\n", | ||
1302 | raw_fd); | ||
1303 | init_backtrace (t); | ||
1304 | GNUNET_assert (0); | ||
1305 | } | ||
1306 | } | ||
1307 | } | ||
1308 | #endif | ||
1309 | |||
1310 | |||
1412 | /** | 1311 | /** |
1413 | * 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 |
1414 | * 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 |
@@ -1437,9 +1336,11 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, | |||
1437 | #ifndef MINGW | 1336 | #ifndef MINGW |
1438 | static struct GNUNET_SCHEDULER_Task * | 1337 | static struct GNUNET_SCHEDULER_Task * |
1439 | add_without_sets (struct GNUNET_TIME_Relative delay, | 1338 | add_without_sets (struct GNUNET_TIME_Relative delay, |
1440 | enum GNUNET_SCHEDULER_Priority priority, | 1339 | enum GNUNET_SCHEDULER_Priority priority, |
1441 | int rfd, | 1340 | const struct GNUNET_NETWORK_Handle *read_nh, |
1442 | 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, | ||
1443 | GNUNET_SCHEDULER_TaskCallback task, | 1344 | GNUNET_SCHEDULER_TaskCallback task, |
1444 | void *task_cls) | 1345 | void *task_cls) |
1445 | { | 1346 | { |
@@ -1448,39 +1349,23 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1448 | GNUNET_assert (NULL != active_task); | 1349 | GNUNET_assert (NULL != active_task); |
1449 | GNUNET_assert (NULL != task); | 1350 | GNUNET_assert (NULL != task); |
1450 | 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); | ||
1451 | t->callback = task; | 1361 | t->callback = task; |
1452 | t->callback_cls = task_cls; | 1362 | t->callback_cls = task_cls; |
1453 | #if DEBUG_FDS | 1363 | #if DEBUG_FDS |
1454 | if (-1 != rfd) | 1364 | check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1); |
1455 | { | 1365 | check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1); |
1456 | int flags = fcntl (rfd, F_GETFD); | 1366 | check_fd (t, NULL != read_fh ? read_fh->fd : -1); |
1457 | 1367 | check_fd (t, NULL != write_fh ? write_fh->fd : -1); | |
1458 | if ((flags == -1) && (errno == EBADF)) | ||
1459 | { | ||
1460 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1461 | "Got invalid file descriptor %d!\n", | ||
1462 | rfd); | ||
1463 | init_backtrace (t); | ||
1464 | GNUNET_assert (0); | ||
1465 | } | ||
1466 | } | ||
1467 | if (-1 != wfd) | ||
1468 | { | ||
1469 | int flags = fcntl (wfd, F_GETFD); | ||
1470 | |||
1471 | if (flags == -1 && errno == EBADF) | ||
1472 | { | ||
1473 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1474 | "Got invalid file descriptor %d!\n", | ||
1475 | wfd); | ||
1476 | init_backtrace (t); | ||
1477 | GNUNET_assert (0); | ||
1478 | } | ||
1479 | } | ||
1480 | #endif | 1368 | #endif |
1481 | t->read_fd = rfd; | ||
1482 | GNUNET_assert (wfd >= -1); | ||
1483 | t->write_fd = wfd; | ||
1484 | #if PROFILE_DELAYS | 1369 | #if PROFILE_DELAYS |
1485 | t->start_time = GNUNET_TIME_absolute_get (); | 1370 | t->start_time = GNUNET_TIME_absolute_get (); |
1486 | #endif | 1371 | #endif |
@@ -1490,11 +1375,9 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1490 | GNUNET_CONTAINER_DLL_insert (pending_head, | 1375 | GNUNET_CONTAINER_DLL_insert (pending_head, |
1491 | pending_tail, | 1376 | pending_tail, |
1492 | t); | 1377 | t); |
1378 | driver_add_multiple (t, GNUNET_SCHEDULER_ET_NONE); | ||
1493 | max_priority_added = GNUNET_MAX (max_priority_added, | 1379 | max_priority_added = GNUNET_MAX (max_priority_added, |
1494 | t->priority); | 1380 | t->priority); |
1495 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1496 | "Adding task %p\n", | ||
1497 | t); | ||
1498 | init_backtrace (t); | 1381 | init_backtrace (t); |
1499 | return t; | 1382 | return t; |
1500 | } | 1383 | } |
@@ -1507,6 +1390,9 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1507 | * 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 |
1508 | * scheduled for execution once either the delay has expired or the | 1391 | * scheduled for execution once either the delay has expired or the |
1509 | * 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). | ||
1510 | * | 1396 | * |
1511 | * @param delay when should this operation time out? | 1397 | * @param delay when should this operation time out? |
1512 | * @param rfd read file-descriptor | 1398 | * @param rfd read file-descriptor |
@@ -1522,8 +1408,8 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
1522 | void *task_cls) | 1408 | void *task_cls) |
1523 | { | 1409 | { |
1524 | return GNUNET_SCHEDULER_add_read_net_with_priority (delay, | 1410 | return GNUNET_SCHEDULER_add_read_net_with_priority (delay, |
1525 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, | 1411 | GNUNET_SCHEDULER_PRIORITY_DEFAULT, |
1526 | rfd, task, task_cls); | 1412 | rfd, task, task_cls); |
1527 | } | 1413 | } |
1528 | 1414 | ||
1529 | 1415 | ||
@@ -1534,6 +1420,9 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
1534 | * socket being ready. The task will be scheduled for execution once | 1420 | * socket being ready. The task will be scheduled for execution once |
1535 | * 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 |
1536 | * 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). | ||
1537 | * | 1426 | * |
1538 | * @param delay when should this operation time out? | 1427 | * @param delay when should this operation time out? |
1539 | * @param priority priority to use for the task | 1428 | * @param priority priority to use for the task |
@@ -1545,9 +1434,9 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
1545 | */ | 1434 | */ |
1546 | struct GNUNET_SCHEDULER_Task * | 1435 | struct GNUNET_SCHEDULER_Task * |
1547 | GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, | 1436 | GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, |
1548 | enum GNUNET_SCHEDULER_Priority priority, | 1437 | enum GNUNET_SCHEDULER_Priority priority, |
1549 | struct GNUNET_NETWORK_Handle *rfd, | 1438 | struct GNUNET_NETWORK_Handle *rfd, |
1550 | GNUNET_SCHEDULER_TaskCallback task, | 1439 | GNUNET_SCHEDULER_TaskCallback task, |
1551 | void *task_cls) | 1440 | void *task_cls) |
1552 | { | 1441 | { |
1553 | return GNUNET_SCHEDULER_add_net_with_priority (delay, priority, | 1442 | return GNUNET_SCHEDULER_add_net_with_priority (delay, priority, |
@@ -1565,6 +1454,9 @@ GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1565 | * scheduled for execution once either the delay has expired or the | 1454 | * scheduled for execution once either the delay has expired or the |
1566 | * 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 |
1567 | * 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). | ||
1568 | * | 1460 | * |
1569 | * @param delay when should this operation time out? | 1461 | * @param delay when should this operation time out? |
1570 | * @param wfd write file-descriptor | 1462 | * @param wfd write file-descriptor |
@@ -1592,6 +1484,9 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, | |||
1592 | * 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 |
1593 | * scheduled for execution once either the delay has expired or the | 1485 | * scheduled for execution once either the delay has expired or the |
1594 | * 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). | ||
1595 | * | 1490 | * |
1596 | * @param delay when should this operation time out? | 1491 | * @param delay when should this operation time out? |
1597 | * @param priority priority of the task | 1492 | * @param priority priority of the task |
@@ -1612,6 +1507,9 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1612 | GNUNET_SCHEDULER_TaskCallback task, | 1507 | GNUNET_SCHEDULER_TaskCallback task, |
1613 | void *task_cls) | 1508 | void *task_cls) |
1614 | { | 1509 | { |
1510 | /* scheduler must be running */ | ||
1511 | GNUNET_assert (NULL != scheduler_driver); | ||
1512 | |||
1615 | #if MINGW | 1513 | #if MINGW |
1616 | struct GNUNET_NETWORK_FDSet *s; | 1514 | struct GNUNET_NETWORK_FDSet *s; |
1617 | struct GNUNET_SCHEDULER_Task * ret; | 1515 | struct GNUNET_SCHEDULER_Task * ret; |
@@ -1627,10 +1525,13 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1627 | GNUNET_NETWORK_fdset_destroy (s); | 1525 | GNUNET_NETWORK_fdset_destroy (s); |
1628 | return ret; | 1526 | return ret; |
1629 | #else | 1527 | #else |
1528 | GNUNET_assert (on_read || on_write); | ||
1630 | GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0); | 1529 | GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0); |
1631 | return add_without_sets (delay, priority, | 1530 | return add_without_sets (delay, priority, |
1632 | on_read ? GNUNET_NETWORK_get_fd (fd) : -1, | 1531 | on_read ? fd : NULL, |
1633 | on_write ? GNUNET_NETWORK_get_fd (fd) : -1, | 1532 | on_write ? fd : NULL, |
1533 | NULL, | ||
1534 | NULL, | ||
1634 | task, task_cls); | 1535 | task, task_cls); |
1635 | #endif | 1536 | #endif |
1636 | } | 1537 | } |
@@ -1642,6 +1543,9 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1642 | * 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 |
1643 | * scheduled for execution once either the delay has expired or the | 1544 | * scheduled for execution once either the delay has expired or the |
1644 | * 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). | ||
1645 | * | 1549 | * |
1646 | * @param delay when should this operation time out? | 1550 | * @param delay when should this operation time out? |
1647 | * @param rfd read file-descriptor | 1551 | * @param rfd read file-descriptor |
@@ -1668,6 +1572,9 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, | |||
1668 | * 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 |
1669 | * scheduled for execution once either the delay has expired or the | 1573 | * scheduled for execution once either the delay has expired or the |
1670 | * 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). | ||
1671 | * | 1578 | * |
1672 | * @param delay when should this operation time out? | 1579 | * @param delay when should this operation time out? |
1673 | * @param wfd write file-descriptor | 1580 | * @param wfd write file-descriptor |
@@ -1694,6 +1601,9 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, | |||
1694 | * 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 |
1695 | * scheduled for execution once either the delay has expired or the | 1602 | * scheduled for execution once either the delay has expired or the |
1696 | * 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). | ||
1697 | * | 1607 | * |
1698 | * @param delay when should this operation time out? | 1608 | * @param delay when should this operation time out? |
1699 | * @param priority priority of the task | 1609 | * @param priority priority of the task |
@@ -1712,6 +1622,9 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
1712 | int on_read, int on_write, | 1622 | int on_read, int on_write, |
1713 | GNUNET_SCHEDULER_TaskCallback task, void *task_cls) | 1623 | GNUNET_SCHEDULER_TaskCallback task, void *task_cls) |
1714 | { | 1624 | { |
1625 | /* scheduler must be running */ | ||
1626 | GNUNET_assert (NULL != scheduler_driver); | ||
1627 | |||
1715 | #if MINGW | 1628 | #if MINGW |
1716 | struct GNUNET_NETWORK_FDSet *s; | 1629 | struct GNUNET_NETWORK_FDSet *s; |
1717 | struct GNUNET_SCHEDULER_Task * ret; | 1630 | struct GNUNET_SCHEDULER_Task * ret; |
@@ -1727,19 +1640,70 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
1727 | GNUNET_NETWORK_fdset_destroy (s); | 1640 | GNUNET_NETWORK_fdset_destroy (s); |
1728 | return ret; | 1641 | return ret; |
1729 | #else | 1642 | #else |
1730 | int real_fd; | 1643 | GNUNET_assert (on_read || on_write); |
1731 | 1644 | GNUNET_assert (fd->fd >= 0); | |
1732 | GNUNET_DISK_internal_file_handle_ (fd, &real_fd, sizeof (int)); | 1645 | return add_without_sets (delay, priority, |
1733 | GNUNET_assert (real_fd >= 0); | 1646 | NULL, |
1734 | return add_without_sets ( | 1647 | NULL, |
1735 | delay, priority, | 1648 | on_read ? fd : NULL, |
1736 | on_read ? real_fd : -1, | 1649 | on_write ? fd : NULL, |
1737 | on_write ? real_fd : -1, | 1650 | task, task_cls); |
1738 | task, task_cls); | ||
1739 | #endif | 1651 | #endif |
1740 | } | 1652 | } |
1741 | 1653 | ||
1742 | 1654 | ||
1655 | void | ||
1656 | extract_handles (struct GNUNET_SCHEDULER_Task *t, | ||
1657 | const struct GNUNET_NETWORK_FDSet *fdset, | ||
1658 | const struct GNUNET_NETWORK_Handle ***ntarget, | ||
1659 | unsigned int *extracted_nhandles, | ||
1660 | const struct GNUNET_DISK_FileHandle ***ftarget, | ||
1661 | unsigned int *extracted_fhandles) | ||
1662 | { | ||
1663 | // FIXME: this implementation only works for unix, for WIN32 the file handles | ||
1664 | // in fdset must be handled separately | ||
1665 | const struct GNUNET_NETWORK_Handle **nhandles; | ||
1666 | const struct GNUNET_DISK_FileHandle **fhandles; | ||
1667 | unsigned int nhandles_len, fhandles_len; | ||
1668 | int sock; | ||
1669 | |||
1670 | nhandles = NULL; | ||
1671 | fhandles = NULL; | ||
1672 | nhandles_len = 0; | ||
1673 | fhandles_len = 0; | ||
1674 | for (sock = 0; sock != fdset->nsds; ++sock) | ||
1675 | { | ||
1676 | if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock)) | ||
1677 | { | ||
1678 | struct GNUNET_NETWORK_Handle *nhandle; | ||
1679 | struct GNUNET_DISK_FileHandle *fhandle; | ||
1680 | |||
1681 | nhandle = GNUNET_NETWORK_socket_box_native (sock); | ||
1682 | if (NULL != nhandle) | ||
1683 | { | ||
1684 | GNUNET_array_append (nhandles, nhandles_len, nhandle); | ||
1685 | } | ||
1686 | else | ||
1687 | { | ||
1688 | fhandle = GNUNET_DISK_get_handle_from_int_fd (sock); | ||
1689 | if (NULL != fhandle) | ||
1690 | { | ||
1691 | GNUNET_array_append (fhandles, fhandles_len, fhandle); | ||
1692 | } | ||
1693 | else | ||
1694 | { | ||
1695 | GNUNET_assert (0); | ||
1696 | } | ||
1697 | } | ||
1698 | } | ||
1699 | } | ||
1700 | *ntarget = nhandles_len > 0 ? nhandles : NULL; | ||
1701 | *ftarget = fhandles_len > 0 ? fhandles : NULL; | ||
1702 | *extracted_nhandles = nhandles_len; | ||
1703 | *extracted_fhandles = fhandles_len; | ||
1704 | } | ||
1705 | |||
1706 | |||
1743 | /** | 1707 | /** |
1744 | * 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 |
1745 | * 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 |
@@ -1755,6 +1719,9 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
1755 | * || any-rs-ready | 1719 | * || any-rs-ready |
1756 | * || any-ws-ready) ) | 1720 | * || any-ws-ready) ) |
1757 | * </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). | ||
1758 | * | 1725 | * |
1759 | * @param prio how important is this task? | 1726 | * @param prio how important is this task? |
1760 | * @param delay how long should we wait? | 1727 | * @param delay how long should we wait? |
@@ -1774,13 +1741,20 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1774 | void *task_cls) | 1741 | void *task_cls) |
1775 | { | 1742 | { |
1776 | struct GNUNET_SCHEDULER_Task *t; | 1743 | struct GNUNET_SCHEDULER_Task *t; |
1777 | 1744 | const struct GNUNET_NETWORK_Handle **read_nhandles; | |
1778 | if ( (NULL == rs) && | 1745 | const struct GNUNET_NETWORK_Handle **write_nhandles; |
1779 | (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))) | ||
1780 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, | 1752 | return GNUNET_SCHEDULER_add_delayed_with_priority (delay, |
1781 | prio, | 1753 | prio, |
1782 | task, | 1754 | task, |
1783 | task_cls); | 1755 | task_cls); |
1756 | /* scheduler must be running */ | ||
1757 | GNUNET_assert (NULL != scheduler_driver); | ||
1784 | GNUNET_assert (NULL != active_task); | 1758 | GNUNET_assert (NULL != active_task); |
1785 | GNUNET_assert (NULL != task); | 1759 | GNUNET_assert (NULL != task); |
1786 | t = GNUNET_new (struct GNUNET_SCHEDULER_Task); | 1760 | t = GNUNET_new (struct GNUNET_SCHEDULER_Task); |
@@ -1788,16 +1762,48 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1788 | t->callback_cls = task_cls; | 1762 | t->callback_cls = task_cls; |
1789 | t->read_fd = -1; | 1763 | t->read_fd = -1; |
1790 | 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; | ||
1791 | if (NULL != rs) | 1774 | if (NULL != rs) |
1792 | { | 1775 | { |
1793 | t->read_set = GNUNET_NETWORK_fdset_create (); | 1776 | extract_handles (t, |
1794 | GNUNET_NETWORK_fdset_copy (t->read_set, rs); | 1777 | rs, |
1778 | &read_nhandles, | ||
1779 | &read_nhandles_len, | ||
1780 | &read_fhandles, | ||
1781 | &read_fhandles_len); | ||
1795 | } | 1782 | } |
1796 | if (NULL != ws) | 1783 | if (NULL != ws) |
1797 | { | 1784 | { |
1798 | t->write_set = GNUNET_NETWORK_fdset_create (); | 1785 | extract_handles (t, |
1799 | GNUNET_NETWORK_fdset_copy (t->write_set, ws); | 1786 | ws, |
1787 | &write_nhandles, | ||
1788 | &write_nhandles_len, | ||
1789 | &write_fhandles, | ||
1790 | &write_fhandles_len); | ||
1800 | } | 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); | ||
1801 | #if PROFILE_DELAYS | 1807 | #if PROFILE_DELAYS |
1802 | t->start_time = GNUNET_TIME_absolute_get (); | 1808 | t->start_time = GNUNET_TIME_absolute_get (); |
1803 | #endif | 1809 | #endif |
@@ -1810,8 +1816,9 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1810 | GNUNET_CONTAINER_DLL_insert (pending_head, | 1816 | GNUNET_CONTAINER_DLL_insert (pending_head, |
1811 | pending_tail, | 1817 | pending_tail, |
1812 | t); | 1818 | t); |
1819 | driver_add_multiple (t, GNUNET_SCHEDULER_ET_NONE); | ||
1813 | max_priority_added = GNUNET_MAX (max_priority_added, | 1820 | max_priority_added = GNUNET_MAX (max_priority_added, |
1814 | t->priority); | 1821 | t->priority); |
1815 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1822 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1816 | "Adding task %p\n", | 1823 | "Adding task %p\n", |
1817 | t); | 1824 | t); |
@@ -1822,17 +1829,18 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1822 | 1829 | ||
1823 | /** | 1830 | /** |
1824 | * Function used by event-loop implementations to signal the scheduler | 1831 | * Function used by event-loop implementations to signal the scheduler |
1825 | * 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. | ||
1826 | * | 1834 | * |
1827 | * This function will then queue the task to notify the application | 1835 | * This function will then queue the task to notify the application |
1828 | * that the task is ready (with the respective priority). | 1836 | * that the task is ready (with the respective priority). |
1829 | * | 1837 | * |
1830 | * @param task the task that is ready, NULL for wake up calls | 1838 | * @param task the task that is ready |
1831 | * @param et information about why the task is ready | 1839 | * @param fdi information about the related FD |
1832 | */ | 1840 | */ |
1833 | void | 1841 | void |
1834 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | 1842 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, |
1835 | enum GNUNET_SCHEDULER_EventType et) | 1843 | struct GNUNET_SCHEDULER_FdInfo *fdi) |
1836 | { | 1844 | { |
1837 | enum GNUNET_SCHEDULER_Reason reason; | 1845 | enum GNUNET_SCHEDULER_Reason reason; |
1838 | struct GNUNET_TIME_Absolute now; | 1846 | struct GNUNET_TIME_Absolute now; |
@@ -1842,17 +1850,20 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | |||
1842 | if (now.abs_value_us >= task->timeout.abs_value_us) | 1850 | if (now.abs_value_us >= task->timeout.abs_value_us) |
1843 | reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | 1851 | reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; |
1844 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && | 1852 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && |
1845 | (0 != (GNUNET_SCHEDULER_ET_IN & et)) ) | 1853 | (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) ) |
1846 | reason |= GNUNET_SCHEDULER_REASON_READ_READY; | 1854 | reason |= GNUNET_SCHEDULER_REASON_READ_READY; |
1847 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | 1855 | if ( (0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && |
1848 | (0 != (GNUNET_SCHEDULER_ET_OUT & et)) ) | 1856 | (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) ) |
1849 | reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; | 1857 | reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; |
1850 | reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; | 1858 | reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; |
1851 | task->reason = reason; | 1859 | task->reason = reason; |
1852 | task->fds = &task->fdx; | 1860 | if (GNUNET_NO == task->in_ready_list) |
1853 | task->fdx.et = et; | 1861 | { |
1854 | task->fds_len = 1; | 1862 | GNUNET_CONTAINER_DLL_remove (pending_head, |
1855 | queue_ready_task (task); | 1863 | pending_tail, |
1864 | task); | ||
1865 | queue_ready_task (task); | ||
1866 | } | ||
1856 | } | 1867 | } |
1857 | 1868 | ||
1858 | 1869 | ||
@@ -1862,15 +1873,16 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | |||
1862 | * 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 |
1863 | * well. If we return #GNUNET_YES, the driver should call this | 1874 | * well. If we return #GNUNET_YES, the driver should call this |
1864 | * 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 |
1865 | * 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 |
1866 | * 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. | ||
1867 | * | 1879 | * |
1868 | * @param sh scheduler handle that was given to the `loop` | 1880 | * @param sh scheduler handle that was given to the `loop` |
1869 | * @return #GNUNET_OK if there are more tasks that are ready, | 1881 | * @return #GNUNET_OK if there are more tasks that are ready, |
1870 | * and thus we would like to run more (yield to avoid | 1882 | * and thus we would like to run more (yield to avoid |
1871 | * blocking other activities for too long) | 1883 | * blocking other activities for too long) |
1872 | * #GNUNET_NO if we are done running tasks (yield to block) | 1884 | * #GNUNET_NO if we are done running tasks (yield to block) |
1873 | * #GNUNET_SYSERR on error | 1885 | * #GNUNET_SYSERR on error, e.g. no tasks were ready |
1874 | */ | 1886 | */ |
1875 | int | 1887 | int |
1876 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | 1888 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) |
@@ -1894,9 +1906,27 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1894 | pending_timeout_last = NULL; | 1906 | pending_timeout_last = NULL; |
1895 | queue_ready_task (pos); | 1907 | queue_ready_task (pos); |
1896 | } | 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 | } | ||
1897 | 1923 | ||
1898 | if (0 == ready_count) | 1924 | if (0 == ready_count) |
1899 | 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 | } | ||
1900 | 1930 | ||
1901 | /* find out which task priority level we are going to | 1931 | /* find out which task priority level we are going to |
1902 | process this time */ | 1932 | process this time */ |
@@ -1916,49 +1946,74 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1916 | while (NULL != (pos = ready_head[p])) | 1946 | while (NULL != (pos = ready_head[p])) |
1917 | { | 1947 | { |
1918 | GNUNET_CONTAINER_DLL_remove (ready_head[p], | 1948 | GNUNET_CONTAINER_DLL_remove (ready_head[p], |
1919 | ready_tail[p], | 1949 | ready_tail[p], |
1920 | pos); | 1950 | pos); |
1921 | ready_count--; | 1951 | ready_count--; |
1922 | current_priority = pos->priority; | 1952 | current_priority = pos->priority; |
1923 | current_lifeness = pos->lifeness; | 1953 | current_lifeness = pos->lifeness; |
1924 | active_task = pos; | 1954 | active_task = pos; |
1925 | #if PROFILE_DELAYS | 1955 | #if PROFILE_DELAYS |
1926 | 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 > |
1927 | DELAY_THRESHOLD.rel_value_us) | 1957 | DELAY_THRESHOLD.rel_value_us) |
1928 | { | 1958 | { |
1929 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1959 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1930 | "Task %p took %s to be scheduled\n", | 1960 | "Task %p took %s to be scheduled\n", |
1931 | pos, | 1961 | pos, |
1932 | 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), |
1933 | GNUNET_YES)); | 1963 | GNUNET_YES)); |
1934 | } | 1964 | } |
1935 | #endif | 1965 | #endif |
1936 | tc.reason = pos->reason; | 1966 | tc.reason = pos->reason; |
1937 | GNUNET_NETWORK_fdset_zero (sh->rs); | 1967 | GNUNET_NETWORK_fdset_zero (sh->rs); |
1938 | 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? | ||
1939 | tc.fds_len = pos->fds_len; | 1970 | tc.fds_len = pos->fds_len; |
1940 | tc.fds = pos->fds; | 1971 | tc.fds = pos->fds; |
1941 | tc.read_ready = (NULL == pos->read_set) ? sh->rs : pos->read_set; | 1972 | for (int i = 0; i != pos->fds_len; ++i) |
1942 | if ( (-1 != pos->read_fd) && | 1973 | { |
1943 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY)) ) | 1974 | struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i]; |
1944 | GNUNET_NETWORK_fdset_set_native (sh->rs, | 1975 | if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) |
1945 | pos->read_fd); | 1976 | { |
1946 | tc.write_ready = (NULL == pos->write_set) ? sh->ws : pos->write_set; | 1977 | GNUNET_NETWORK_fdset_set_native (sh->rs, |
1947 | if ((-1 != pos->write_fd) && | 1978 | fdi->sock); |
1948 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) | 1979 | } |
1949 | GNUNET_NETWORK_fdset_set_native (sh->ws, | 1980 | if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) |
1950 | 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; | ||
1951 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1988 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1952 | "Running task: %p\n", | 1989 | "Running task %p\n", |
1953 | pos); | 1990 | pos); |
1991 | GNUNET_assert (NULL != pos->callback); | ||
1954 | 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 | } | ||
1955 | active_task = NULL; | 2003 | active_task = NULL; |
1956 | dump_backtrace (pos); | 2004 | dump_backtrace (pos); |
1957 | destroy_task (pos); | 2005 | destroy_task (pos); |
1958 | tasks_run++; | 2006 | tasks_run++; |
1959 | } | 2007 | } |
2008 | shutdown_if_no_lifeness (); | ||
1960 | if (0 == ready_count) | 2009 | if (0 == ready_count) |
2010 | { | ||
2011 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
2012 | get_timeout ()); | ||
1961 | return GNUNET_NO; | 2013 | return GNUNET_NO; |
2014 | } | ||
2015 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
2016 | GNUNET_TIME_absolute_get ()); | ||
1962 | return GNUNET_OK; | 2017 | return GNUNET_OK; |
1963 | } | 2018 | } |
1964 | 2019 | ||
@@ -1981,8 +2036,8 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1981 | */ | 2036 | */ |
1982 | int | 2037 | int |
1983 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | 2038 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, |
1984 | GNUNET_SCHEDULER_TaskCallback task, | 2039 | GNUNET_SCHEDULER_TaskCallback task, |
1985 | void *task_cls) | 2040 | void *task_cls) |
1986 | { | 2041 | { |
1987 | int ret; | 2042 | int ret; |
1988 | struct GNUNET_SIGNAL_Context *shc_int; | 2043 | struct GNUNET_SIGNAL_Context *shc_int; |
@@ -1997,7 +2052,6 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
1997 | #endif | 2052 | #endif |
1998 | struct GNUNET_SCHEDULER_Task tsk; | 2053 | struct GNUNET_SCHEDULER_Task tsk; |
1999 | const struct GNUNET_DISK_FileHandle *pr; | 2054 | const struct GNUNET_DISK_FileHandle *pr; |
2000 | struct GNUNET_SCHEDULER_Handle sh; | ||
2001 | 2055 | ||
2002 | /* general set-up */ | 2056 | /* general set-up */ |
2003 | GNUNET_assert (NULL == active_task); | 2057 | GNUNET_assert (NULL == active_task); |
@@ -2009,54 +2063,56 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2009 | GNUNET_assert (NULL != shutdown_pipe_handle); | 2063 | GNUNET_assert (NULL != shutdown_pipe_handle); |
2010 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | 2064 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, |
2011 | GNUNET_DISK_PIPE_END_READ); | 2065 | GNUNET_DISK_PIPE_END_READ); |
2012 | GNUNET_assert (NULL != pr); | ||
2013 | my_pid = getpid (); | 2066 | my_pid = getpid (); |
2067 | scheduler_driver = driver; | ||
2014 | 2068 | ||
2015 | /* install signal handlers */ | 2069 | /* install signal handlers */ |
2016 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 2070 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2017 | "Registering signal handlers\n"); | 2071 | "Registering signal handlers\n"); |
2018 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, | 2072 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, |
2019 | &sighandler_shutdown); | 2073 | &sighandler_shutdown); |
2020 | shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, | 2074 | shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, |
2021 | &sighandler_shutdown); | 2075 | &sighandler_shutdown); |
2022 | #if (SIGTERM != GNUNET_TERM_SIG) | 2076 | #if (SIGTERM != GNUNET_TERM_SIG) |
2023 | shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, | 2077 | shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, |
2024 | &sighandler_shutdown); | 2078 | &sighandler_shutdown); |
2025 | #endif | 2079 | #endif |
2026 | #ifndef MINGW | 2080 | #ifndef MINGW |
2027 | shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, | 2081 | shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, |
2028 | &sighandler_pipe); | 2082 | &sighandler_pipe); |
2029 | shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, | 2083 | shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, |
2030 | &sighandler_shutdown); | 2084 | &sighandler_shutdown); |
2031 | shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, | 2085 | shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, |
2032 | &sighandler_shutdown); | 2086 | &sighandler_shutdown); |
2033 | #endif | 2087 | #endif |
2034 | 2088 | ||
2035 | /* Setup initial tasks */ | 2089 | /* Setup initial tasks */ |
2036 | current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; | 2090 | current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; |
2037 | current_lifeness = GNUNET_YES; | 2091 | current_lifeness = GNUNET_NO; |
2038 | memset (&tsk, | 2092 | memset (&tsk, |
2039 | 0, | 2093 | 0, |
2040 | sizeof (tsk)); | 2094 | sizeof (tsk)); |
2041 | active_task = &tsk; | 2095 | active_task = &tsk; |
2042 | 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; | ||
2043 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, | 2103 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, |
2044 | task_cls, | 2104 | task_cls, |
2045 | GNUNET_SCHEDULER_REASON_STARTUP, | 2105 | GNUNET_SCHEDULER_REASON_STARTUP, |
2046 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); | 2106 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); |
2047 | GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, | ||
2048 | &GNUNET_OS_install_parent_control_handler, | ||
2049 | NULL); | ||
2050 | active_task = NULL; | 2107 | active_task = NULL; |
2051 | driver->set_wakeup (driver->cls, | 2108 | scheduler_driver->set_wakeup (scheduler_driver->cls, |
2052 | GNUNET_TIME_absolute_get ()); | 2109 | get_timeout ()); |
2053 | |||
2054 | /* begin main event loop */ | 2110 | /* begin main event loop */ |
2055 | sh.rs = GNUNET_NETWORK_fdset_create (); | 2111 | sh.rs = GNUNET_NETWORK_fdset_create (); |
2056 | sh.ws = GNUNET_NETWORK_fdset_create (); | 2112 | sh.ws = GNUNET_NETWORK_fdset_create (); |
2057 | sh.driver = driver; | 2113 | GNUNET_NETWORK_fdset_handle_set (sh.rs, pr); |
2058 | ret = driver->loop (driver->cls, | 2114 | ret = driver->loop (driver->cls, |
2059 | &sh); | 2115 | &sh); |
2060 | GNUNET_NETWORK_fdset_destroy (sh.rs); | 2116 | GNUNET_NETWORK_fdset_destroy (sh.rs); |
2061 | GNUNET_NETWORK_fdset_destroy (sh.ws); | 2117 | GNUNET_NETWORK_fdset_destroy (sh.ws); |
2062 | 2118 | ||
@@ -2073,20 +2129,215 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2073 | #endif | 2129 | #endif |
2074 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); | 2130 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); |
2075 | shutdown_pipe_handle = NULL; | 2131 | shutdown_pipe_handle = NULL; |
2132 | scheduler_driver = NULL; | ||
2076 | return ret; | 2133 | return ret; |
2077 | } | 2134 | } |
2078 | 2135 | ||
2079 | 2136 | ||
2137 | int | ||
2138 | select_add (void *cls, | ||
2139 | struct GNUNET_SCHEDULER_Task *task, | ||
2140 | struct GNUNET_SCHEDULER_FdInfo *fdi) | ||
2141 | { | ||
2142 | struct DriverContext *context = cls; | ||
2143 | GNUNET_assert (NULL != context); | ||
2144 | GNUNET_assert (NULL != task); | ||
2145 | GNUNET_assert (NULL != fdi); | ||
2146 | GNUNET_assert (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et) || | ||
2147 | 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)); | ||
2148 | |||
2149 | if (!((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0)) | ||
2150 | { | ||
2151 | /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */ | ||
2152 | return GNUNET_SYSERR; | ||
2153 | } | ||
2154 | |||
2155 | struct Scheduled *scheduled = GNUNET_new (struct Scheduled); | ||
2156 | scheduled->task = task; | ||
2157 | scheduled->fdi = fdi; | ||
2158 | scheduled->et = fdi->et; | ||
2159 | |||
2160 | GNUNET_CONTAINER_DLL_insert (context->scheduled_head, | ||
2161 | context->scheduled_tail, | ||
2162 | scheduled); | ||
2163 | return GNUNET_OK; | ||
2164 | } | ||
2165 | |||
2166 | |||
2167 | int | ||
2168 | select_del (void *cls, | ||
2169 | struct GNUNET_SCHEDULER_Task *task) | ||
2170 | { | ||
2171 | struct DriverContext *context; | ||
2172 | struct Scheduled *pos; | ||
2173 | int ret; | ||
2174 | |||
2175 | GNUNET_assert (NULL != cls); | ||
2176 | |||
2177 | context = cls; | ||
2178 | ret = GNUNET_SYSERR; | ||
2179 | pos = context->scheduled_head; | ||
2180 | while (NULL != pos) | ||
2181 | { | ||
2182 | struct Scheduled *next = pos->next; | ||
2183 | if (pos->task == task) | ||
2184 | { | ||
2185 | GNUNET_CONTAINER_DLL_remove (context->scheduled_head, | ||
2186 | context->scheduled_tail, | ||
2187 | pos); | ||
2188 | GNUNET_free (pos); | ||
2189 | ret = GNUNET_OK; | ||
2190 | } | ||
2191 | pos = next; | ||
2192 | } | ||
2193 | return ret; | ||
2194 | } | ||
2195 | |||
2196 | |||
2197 | int | ||
2198 | select_loop (void *cls, | ||
2199 | struct GNUNET_SCHEDULER_Handle *sh) | ||
2200 | { | ||
2201 | struct GNUNET_NETWORK_FDSet *rs; | ||
2202 | struct GNUNET_NETWORK_FDSet *ws; | ||
2203 | struct DriverContext *context; | ||
2204 | int select_result; | ||
2205 | int tasks_ready; | ||
2206 | |||
2207 | context = cls; | ||
2208 | GNUNET_assert (NULL != context); | ||
2209 | rs = GNUNET_NETWORK_fdset_create (); | ||
2210 | ws = GNUNET_NETWORK_fdset_create (); | ||
2211 | tasks_ready = GNUNET_NO; | ||
2212 | while (NULL != context->scheduled_head || | ||
2213 | GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != context->timeout.rel_value_us) | ||
2214 | { | ||
2215 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2216 | "select timeout = %s\n", | ||
2217 | GNUNET_STRINGS_relative_time_to_string (context->timeout, GNUNET_NO)); | ||
2218 | |||
2219 | GNUNET_NETWORK_fdset_zero (rs); | ||
2220 | GNUNET_NETWORK_fdset_zero (ws); | ||
2221 | struct Scheduled *pos; | ||
2222 | for (pos = context->scheduled_head; NULL != pos; pos = pos->next) | ||
2223 | { | ||
2224 | if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) | ||
2225 | { | ||
2226 | GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock); | ||
2227 | } | ||
2228 | if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) | ||
2229 | { | ||
2230 | GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock); | ||
2231 | } | ||
2232 | } | ||
2233 | if (NULL == scheduler_select) | ||
2234 | { | ||
2235 | select_result = GNUNET_NETWORK_socket_select (rs, | ||
2236 | ws, | ||
2237 | NULL, | ||
2238 | context->timeout); | ||
2239 | } | ||
2240 | else | ||
2241 | { | ||
2242 | select_result = scheduler_select (scheduler_select_cls, | ||
2243 | rs, | ||
2244 | ws, | ||
2245 | NULL, | ||
2246 | context->timeout); | ||
2247 | } | ||
2248 | if (select_result == GNUNET_SYSERR) | ||
2249 | { | ||
2250 | if (errno == EINTR) | ||
2251 | continue; | ||
2252 | |||
2253 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); | ||
2254 | #ifndef MINGW | ||
2255 | #if USE_LSOF | ||
2256 | char lsof[512]; | ||
2257 | |||
2258 | snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); | ||
2259 | (void) close (1); | ||
2260 | (void) dup2 (2, 1); | ||
2261 | if (0 != system (lsof)) | ||
2262 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
2263 | "system"); | ||
2264 | #endif | ||
2265 | #endif | ||
2266 | #if DEBUG_FDS | ||
2267 | struct Scheduled *s; | ||
2268 | for (s = context->scheduled_head; NULL != s; s = s->next) | ||
2269 | { | ||
2270 | int flags = fcntl (s->fdi->sock, F_GETFD); | ||
2271 | if ((flags == -1) && (errno == EBADF)) | ||
2272 | { | ||
2273 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2274 | "Got invalid file descriptor %d!\n", | ||
2275 | s->fdi->sock); | ||
2276 | } | ||
2277 | } | ||
2278 | #endif | ||
2279 | GNUNET_assert (0); | ||
2280 | GNUNET_NETWORK_fdset_destroy (rs); | ||
2281 | GNUNET_NETWORK_fdset_destroy (ws); | ||
2282 | return GNUNET_SYSERR; | ||
2283 | } | ||
2284 | for (pos = context->scheduled_head; NULL != pos; pos = pos->next) | ||
2285 | { | ||
2286 | int is_ready = GNUNET_NO; | ||
2287 | if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et) && | ||
2288 | GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, pos->fdi->sock)) | ||
2289 | { | ||
2290 | pos->fdi->et |= GNUNET_SCHEDULER_ET_IN; | ||
2291 | is_ready = GNUNET_YES; | ||
2292 | } | ||
2293 | if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et) && | ||
2294 | GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, pos->fdi->sock)) | ||
2295 | { | ||
2296 | pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT; | ||
2297 | is_ready = GNUNET_YES; | ||
2298 | } | ||
2299 | if (GNUNET_YES == is_ready) | ||
2300 | { | ||
2301 | GNUNET_SCHEDULER_task_ready (pos->task, pos->fdi); | ||
2302 | } | ||
2303 | } | ||
2304 | tasks_ready = GNUNET_SCHEDULER_run_from_driver (sh); | ||
2305 | GNUNET_assert (GNUNET_SYSERR != tasks_ready); | ||
2306 | } | ||
2307 | GNUNET_NETWORK_fdset_destroy (rs); | ||
2308 | GNUNET_NETWORK_fdset_destroy (ws); | ||
2309 | return GNUNET_OK; | ||
2310 | } | ||
2311 | |||
2312 | |||
2313 | void | ||
2314 | select_set_wakeup(void *cls, | ||
2315 | struct GNUNET_TIME_Absolute dt) | ||
2316 | { | ||
2317 | struct DriverContext *context = cls; | ||
2318 | GNUNET_assert (NULL != context); | ||
2319 | |||
2320 | context->timeout = GNUNET_TIME_absolute_get_remaining (dt); | ||
2321 | } | ||
2322 | |||
2323 | |||
2080 | /** | 2324 | /** |
2081 | * Obtain the driver for using select() as the event loop. | 2325 | * Obtain the driver for using select() as the event loop. |
2082 | * | 2326 | * |
2083 | * @return NULL on error | 2327 | * @return NULL on error |
2084 | */ | 2328 | */ |
2085 | const struct GNUNET_SCHEDULER_Driver * | 2329 | struct GNUNET_SCHEDULER_Driver * |
2086 | GNUNET_SCHEDULER_driver_select () | 2330 | GNUNET_SCHEDULER_driver_select () |
2087 | { | 2331 | { |
2088 | GNUNET_break (0); // not implemented | 2332 | struct GNUNET_SCHEDULER_Driver *select_driver; |
2089 | return NULL; | 2333 | select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver); |
2334 | |||
2335 | select_driver->loop = &select_loop; | ||
2336 | select_driver->add = &select_add; | ||
2337 | select_driver->del = &select_del; | ||
2338 | select_driver->set_wakeup = &select_set_wakeup; | ||
2339 | |||
2340 | return select_driver; | ||
2090 | } | 2341 | } |
2091 | 2342 | ||
2092 | 2343 | ||
diff --git a/src/util/service.c b/src/util/service.c index fcdf45a51..b4eb33caa 100644 --- a/src/util/service.c +++ b/src/util/service.c | |||
@@ -1932,6 +1932,11 @@ do_send (void *cls) | |||
1932 | size_t left; | 1932 | size_t left; |
1933 | const char *buf; | 1933 | const char *buf; |
1934 | 1934 | ||
1935 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1936 | "service: sending message with type %u", | ||
1937 | ntohs(client->msg->type)); | ||
1938 | |||
1939 | |||
1935 | client->send_task = NULL; | 1940 | client->send_task = NULL; |
1936 | buf = (const char *) client->msg; | 1941 | buf = (const char *) client->msg; |
1937 | left = ntohs (client->msg->size) - client->msg_pos; | 1942 | left = ntohs (client->msg->size) - client->msg_pos; |
@@ -1941,6 +1946,8 @@ do_send (void *cls) | |||
1941 | GNUNET_assert (ret <= (ssize_t) left); | 1946 | GNUNET_assert (ret <= (ssize_t) left); |
1942 | if (0 == ret) | 1947 | if (0 == ret) |
1943 | { | 1948 | { |
1949 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1950 | "no data send"); | ||
1944 | GNUNET_MQ_inject_error (client->mq, | 1951 | GNUNET_MQ_inject_error (client->mq, |
1945 | GNUNET_MQ_ERROR_WRITE); | 1952 | GNUNET_MQ_ERROR_WRITE); |
1946 | return; | 1953 | return; |
@@ -1958,6 +1965,9 @@ do_send (void *cls) | |||
1958 | if (EPIPE != errno) | 1965 | if (EPIPE != errno) |
1959 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | 1966 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, |
1960 | "send"); | 1967 | "send"); |
1968 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1969 | "socket send returned with error code %i", | ||
1970 | errno); | ||
1961 | GNUNET_MQ_inject_error (client->mq, | 1971 | GNUNET_MQ_inject_error (client->mq, |
1962 | GNUNET_MQ_ERROR_WRITE); | 1972 | GNUNET_MQ_ERROR_WRITE); |
1963 | return; | 1973 | return; |
@@ -2402,7 +2412,7 @@ resume_client_receive (void *cls) | |||
2402 | GNUNET_YES); | 2412 | GNUNET_YES); |
2403 | if (GNUNET_SYSERR == ret) | 2413 | if (GNUNET_SYSERR == ret) |
2404 | { | 2414 | { |
2405 | if (NULL != c->drop_task) | 2415 | if (NULL == c->drop_task) |
2406 | GNUNET_SERVICE_client_drop (c); | 2416 | GNUNET_SERVICE_client_drop (c); |
2407 | return; | 2417 | return; |
2408 | } | 2418 | } |
@@ -2431,6 +2441,7 @@ resume_client_receive (void *cls) | |||
2431 | void | 2441 | void |
2432 | GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c) | 2442 | GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c) |
2433 | { | 2443 | { |
2444 | GNUNET_assert (NULL == c->drop_task); | ||
2434 | GNUNET_assert (GNUNET_YES == c->needs_continue); | 2445 | GNUNET_assert (GNUNET_YES == c->needs_continue); |
2435 | GNUNET_assert (NULL == c->recv_task); | 2446 | GNUNET_assert (NULL == c->recv_task); |
2436 | c->needs_continue = GNUNET_NO; | 2447 | c->needs_continue = GNUNET_NO; |
@@ -2513,6 +2524,24 @@ GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c) | |||
2513 | { | 2524 | { |
2514 | struct GNUNET_SERVICE_Handle *sh = c->sh; | 2525 | struct GNUNET_SERVICE_Handle *sh = c->sh; |
2515 | 2526 | ||
2527 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2528 | "Client dropped: %p (MQ: %p)\n", | ||
2529 | c, | ||
2530 | c->mq); | ||
2531 | |||
2532 | #if EXECINFO | ||
2533 | void *backtrace_array[MAX_TRACE_DEPTH]; | ||
2534 | int num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); | ||
2535 | char **backtrace_strings = | ||
2536 | backtrace_symbols (backtrace_array, | ||
2537 | t->num_backtrace_strings); | ||
2538 | for (unsigned int i = 0; i < num_backtrace_strings; i++) | ||
2539 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2540 | "client drop trace %u: %s\n", | ||
2541 | i, | ||
2542 | backtrace_strings[i]); | ||
2543 | #endif | ||
2544 | |||
2516 | if (NULL != c->drop_task) | 2545 | if (NULL != c->drop_task) |
2517 | { | 2546 | { |
2518 | /* asked to drop twice! */ | 2547 | /* asked to drop twice! */ |
diff --git a/src/util/time.c b/src/util/time.c index 19100ac36..5ffb19ec1 100644 --- a/src/util/time.c +++ b/src/util/time.c | |||
@@ -693,7 +693,7 @@ GNUNET_TIME_year_to_time (unsigned int year) | |||
693 | } | 693 | } |
694 | t.tm_year = year - 1900; | 694 | t.tm_year = year - 1900; |
695 | t.tm_mday = 1; | 695 | t.tm_mday = 1; |
696 | t.tm_mon = 1; | 696 | t.tm_mon = 0; |
697 | t.tm_wday = 1; | 697 | t.tm_wday = 1; |
698 | t.tm_yday = 1; | 698 | t.tm_yday = 1; |
699 | tp = mktime (&t); | 699 | tp = mktime (&t); |