GNUnet 0.22.2
scheduler.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009-2017, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29// DEBUG
30#include <inttypes.h>
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__)
33
34#define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
35 "util-scheduler", \
36 syscall)
37
38
39#if HAVE_EXECINFO_H
40#include "execinfo.h"
41
46#define USE_LSOF GNUNET_NO
47
51#define EXECINFO GNUNET_NO
52
56#define DEBUG_FDS GNUNET_NO
57
61#define MAX_TRACE_DEPTH 50
62#endif
63
68#define PROFILE_DELAYS GNUNET_NO
69
74#define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS
75
76
83{
90
97
102
107
108#if (SIGTERM != GNUNET_TERM_SIG)
112 struct GNUNET_SIGNAL_Context *shc_gterm;
113#endif
114
119
124
129};
130
131
136{
141
146
151
156
161
168
172 unsigned int fds_len;
173
180
186
187#if PROFILE_DELAYS
192#endif
193
200
205
210
215
221
226
231
232#if EXECINFO
237 char **backtrace_strings;
238
242 int num_backtrace_strings;
243#endif
244
249};
250
257
258
263{
265
267
272
278
284};
285
286
291{
297
303
309};
310
311
320
325
330
335
340
349
358
364
369
373static struct
375
379static struct
381
388
394
398static unsigned int ready_count;
399
405
411
416
421
427
432
437
438
446void
448 void *new_select_cls)
449{
450 scheduler_select = new_select;
451 scheduler_select_cls = new_select_cls;
452}
453
454
463{
464 if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
465 return p;
466 GNUNET_assert (0);
467 return 0; /* make compiler happy */
468}
469
470
476static struct GNUNET_TIME_Absolute
478{
479 struct GNUNET_SCHEDULER_Task *pos;
480 struct GNUNET_TIME_Absolute now;
482
486 if (NULL != pos)
487 {
488 if (0 != pos->reason)
489 {
490 return now;
491 }
492 else
493 {
494 timeout = pos->timeout;
495 }
496 }
497 for (pos = pending_head; NULL != pos; pos = pos->next)
498 {
499 if (0 != pos->reason)
500 {
501 return now;
502 }
503 else if ((pos->timeout.abs_value_us !=
504 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) &&
505 (timeout.abs_value_us > pos->timeout.abs_value_us))
506 {
507 timeout = pos->timeout;
508 }
509 }
510 return timeout;
511}
512
513
514static void
516{
518 {
523 }
524}
525
526
527static void
529{
532 ready_tail[p],
537}
538
539
545static void
547{
549
551 ready_tail[p],
552 task);
553 if (p > work_priority)
556 ready_count++;
557}
558
559
566void
568{
569 struct GNUNET_SCHEDULER_Task *pos;
570
572 "GNUNET_SCHEDULER_shutdown\n");
573 if (NULL != install_parent_control_task)
574 {
577 }
578 if (NULL != shutdown_pipe_task)
579 {
581 shutdown_pipe_task = NULL;
582 }
583 while (NULL != (pos = shutdown_head))
584 {
587 pos);
589 queue_ready_task (pos);
590 }
591}
592
593
599static void
601{
602#if EXECINFO
603 for (unsigned int i = 0; i < t->num_backtrace_strings; i++)
605 "Task %p trace %u: %s\n",
606 t,
607 i,
608 t->backtrace_strings[i]);
609#else
610 (void) t;
611#endif
612}
613
614
620static void
622{
624 "destroying task %p\n",
625 t);
626
627 if (GNUNET_YES == t->own_handles)
628 {
629 for (unsigned int i = 0; i != t->fds_len; ++i)
630 {
631 const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd;
632 const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh;
633 if (fd)
634 {
636 (struct GNUNET_NETWORK_Handle *) fd);
637 }
638 if (fh)
639 {
640 // FIXME: on WIN32 this is not enough! A function
641 // GNUNET_DISK_file_free_memory_only would be nice
642 GNUNET_free_nz ((void *) fh);
643 }
644 }
645 }
646 if (t->fds_len > 1)
647 {
649 }
650#if EXECINFO
651 GNUNET_free (t->backtrace_strings);
652#endif
653 GNUNET_free (t);
654}
655
656
661
666static pid_t my_pid;
667
671static void
673{
674 return;
675}
676
677
681static void
683{
684 static char c;
685 int old_errno = errno; /* backup errno */
686
687 if (getpid () != my_pid)
688 _exit (1); /* we have fork'ed since the signal handler was created,
689 * ignore the signal, see https://gnunet.org/vfork discussion */
693 &c, sizeof(c));
694 errno = old_errno;
695}
696
697
698static void
700{
701 struct GNUNET_SCHEDULER_Task *t;
702
703 if (ready_count > 0)
704 return;
705 for (t = pending_head; NULL != t; t = t->next)
706 if (GNUNET_YES == t->lifeness)
707 return;
708 for (t = shutdown_head; NULL != t; t = t->next)
709 if (GNUNET_YES == t->lifeness)
710 return;
711 for (t = pending_timeout_head; NULL != t; t = t->next)
712 if (GNUNET_YES == t->lifeness)
713 return;
714 /* No lifeness! */
716}
717
718
721 struct DriverContext *context);
722
723
724void
726 void *task_cls)
727{
729 struct GNUNET_SCHEDULER_Driver *driver;
730 struct DriverContext context = {
731 .scheduled_head = NULL,
732 .scheduled_tail = NULL,
733 .timeout = GNUNET_TIME_absolute_get ()
734 };
735
737 driver->cls = &context;
740 task_cls,
745 &context));
747 GNUNET_free (driver);
748}
749
750
757const struct GNUNET_SCHEDULER_TaskContext *
759{
760 GNUNET_assert (NULL != active_task);
761 return &tc;
762}
763
764
774unsigned int
776{
777 unsigned int ret;
778
779 GNUNET_assert (NULL != active_task);
781 return ready_count;
784 ret = 0;
785 for (struct GNUNET_SCHEDULER_Task *pos = ready_head[check_priority (p)];
786 NULL != pos;
787 pos = pos->next)
788 ret++;
790 // Don't count the dummy marker
791 ret--;
792 return ret;
793}
794
795
796static void
798 const struct GNUNET_NETWORK_Handle *const *read_nh,
799 unsigned int read_nh_len,
800 const struct GNUNET_NETWORK_Handle *const *write_nh,
801 unsigned int write_nh_len,
802 const struct GNUNET_DISK_FileHandle *const *read_fh,
803 unsigned int read_fh_len,
804 const struct GNUNET_DISK_FileHandle *const *write_fh,
805 unsigned int write_fh_len)
806{
807 // FIXME: if we have exactly two network handles / exactly two file handles
808 // and they are equal, we can make one FdInfo with both
809 // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set.
810 struct GNUNET_SCHEDULER_FdInfo *fdi;
811
812 t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len;
813 if (1 == t->fds_len)
814 {
815 fdi = &t->fdx;
816 t->fds = fdi;
817 if (1 == read_nh_len)
818 {
819 GNUNET_assert (NULL != read_nh);
820 GNUNET_assert (NULL != *read_nh);
821 fdi->fd = *read_nh;
823 fdi->sock = GNUNET_NETWORK_get_fd (*read_nh);
824 t->read_fd = fdi->sock;
825 t->write_fd = -1;
826 }
827 else if (1 == write_nh_len)
828 {
829 GNUNET_assert (NULL != write_nh);
830 GNUNET_assert (NULL != *write_nh);
831 fdi->fd = *write_nh;
833 fdi->sock = GNUNET_NETWORK_get_fd (*write_nh);
834 t->read_fd = -1;
835 t->write_fd = fdi->sock;
836 }
837 else if (1 == read_fh_len)
838 {
839 GNUNET_assert (NULL != read_fh);
840 GNUNET_assert (NULL != *read_fh);
841 fdi->fh = *read_fh;
843 fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32
844 t->read_fd = fdi->sock;
845 t->write_fd = -1;
846 }
847 else
848 {
849 GNUNET_assert (NULL != write_fh);
850 GNUNET_assert (NULL != *write_fh);
851 fdi->fh = *write_fh;
853 fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32
854 t->read_fd = -1;
855 t->write_fd = fdi->sock;
856 }
857 }
858 else
859 {
861 t->fds = fdi;
862 t->read_fd = -1;
863 t->write_fd = -1;
864 for (int i = 0; i != read_nh_len; ++i)
865 {
866 fdi->fd = read_nh[i];
867 GNUNET_assert (NULL != fdi->fd);
869 fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]);
870 ++fdi;
871 }
872 for (int i = 0; i != write_nh_len; ++i)
873 {
874 fdi->fd = write_nh[i];
875 GNUNET_assert (NULL != fdi->fd);
877 fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]);
878 ++fdi;
879 }
880 for (int i = 0; i != read_fh_len; ++i)
881 {
882 fdi->fh = read_fh[i];
883 GNUNET_assert (NULL != fdi->fh);
885 fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32
886 ++fdi;
887 }
888 for (int i = 0; i != write_fh_len; ++i)
889 {
890 fdi->fh = write_fh[i];
891 GNUNET_assert (NULL != fdi->fh);
893 fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32
894 ++fdi;
895 }
896 }
897}
898
899
913static void
915{
916 struct GNUNET_SCHEDULER_FdInfo *fdi;
917 int success = GNUNET_YES;
918
919 for (unsigned int i = 0; i != t->fds_len; ++i)
920 {
921 fdi = &t->fds[i];
923 t,
924 fdi) && success;
926 }
927 if (GNUNET_YES != success)
928 {
930 "driver could not add task\n");
931 }
932}
933
934
935static void
937{
938 (void) cls;
941}
942
943
944static void
946{
947 char c;
948 const struct GNUNET_DISK_FileHandle *pr;
949
950 (void) cls;
951 shutdown_pipe_task = NULL;
955 /* consume the signal */
956 GNUNET_DISK_file_read (pr, &c, sizeof(c));
957 /* mark all active tasks as ready due to shutdown */
961 pr,
963 NULL);
964}
965
966
979void *
981{
983 int is_fd_task;
984 void *ret;
985
987 "canceling task %p\n",
988 task);
989
990 /* scheduler must be running */
992 is_fd_task = (NULL != task->fds);
993 if (is_fd_task)
994 {
995 int del_result = scheduler_driver->del (scheduler_driver->cls, task);
996 if (GNUNET_OK != del_result)
997 {
999 "driver could not delete task\n");
1000 GNUNET_assert (0);
1001 }
1002 }
1003 if (! task->in_ready_list)
1004 {
1005 if (is_fd_task)
1006 {
1009 task);
1010 }
1011 else if (GNUNET_YES == task->on_shutdown)
1012 {
1015 task);
1016 }
1017 else
1018 {
1021 task);
1022 if (pending_timeout_last == task)
1023 pending_timeout_last = NULL;
1024 }
1025 }
1026 else
1027 {
1028 p = check_priority (task->priority);
1030 ready_tail[p],
1031 task);
1032 ready_count--;
1033 }
1034 ret = task->callback_cls;
1035 destroy_task (task);
1036 return ret;
1037}
1038
1039
1045static void
1047{
1048#if EXECINFO
1049 void *backtrace_array[MAX_TRACE_DEPTH];
1050
1051 t->num_backtrace_strings
1052 = backtrace (backtrace_array, MAX_TRACE_DEPTH);
1053 t->backtrace_strings =
1054 backtrace_symbols (backtrace_array,
1055 t->num_backtrace_strings);
1056 dump_backtrace (t);
1057#else
1058 (void) t;
1059#endif
1060}
1061
1062
1073void
1075 task,
1076 void *task_cls,
1078 reason,
1080 priority)
1081{
1082 struct GNUNET_SCHEDULER_Task *t;
1083
1084 /* scheduler must be running */
1086 GNUNET_assert (NULL != task);
1088 t->read_fd = -1;
1089 t->write_fd = -1;
1090 t->callback = task;
1091 t->callback_cls = task_cls;
1092#if PROFILE_DELAYS
1093 t->start_time = GNUNET_TIME_absolute_get ();
1094#endif
1095 t->reason = reason;
1099 "Adding continuation task %p\n",
1100 t);
1101 init_backtrace (t);
1103}
1104
1105
1117struct GNUNET_SCHEDULER_Task *
1121 void *task_cls)
1122{
1123 struct GNUNET_SCHEDULER_Task *t;
1124 struct GNUNET_SCHEDULER_Task *pos;
1126 struct GNUNET_TIME_Relative left;
1127
1128 /* scheduler must be running */
1130 GNUNET_assert (NULL != task);
1133 t->callback = task;
1134 t->callback_cls = task_cls;
1135 t->read_fd = -1;
1136 t->write_fd = -1;
1137#if PROFILE_DELAYS
1138 t->start_time = GNUNET_TIME_absolute_get ();
1139#endif
1140 t->timeout = at;
1141 t->priority = check_priority (priority);
1143 init_backtrace (t);
1144
1146 if (0 == left.rel_value_us)
1147 {
1149 if (priority > work_priority)
1150 work_priority = priority;
1151 return t;
1152 }
1153
1154 /* try tail first (optimization in case we are
1155 * appending to a long list of tasks with timeouts) */
1156 if ((NULL == pending_timeout_head) ||
1158 {
1161 t);
1162 }
1163 else
1164 {
1165 /* first move from heuristic start backwards to before start time */
1166 prev = pending_timeout_last;
1167 while ((NULL != prev) &&
1169 prev = prev->prev;
1170 /* now, move from heuristic start (or head of list) forward to insertion point */
1171 if (NULL == prev)
1173 else
1174 pos = prev->next;
1175 while ((NULL != pos) && (pos->timeout.abs_value_us <=
1177 {
1178 prev = pos;
1179 pos = pos->next;
1180 }
1183 prev,
1184 t);
1185 }
1186 /* finally, update heuristic insertion point to last insertion... */
1189 "Adding task %p\n",
1190 t);
1191 return t;
1192}
1193
1194
1206struct GNUNET_SCHEDULER_Task *
1209 priority,
1211 void *task_cls)
1212{
1215 priority,
1216 task,
1217 task_cls);
1218}
1219
1220
1230struct GNUNET_SCHEDULER_Task *
1233 void *task_cls)
1234{
1236 prio,
1237 task,
1238 task_cls);
1239}
1240
1241
1253struct GNUNET_SCHEDULER_Task *
1256 void *task_cls)
1257{
1260 task,
1261 task_cls);
1262}
1263
1264
1276struct GNUNET_SCHEDULER_Task *
1279 void *task_cls)
1280{
1283 task,
1284 task_cls);
1285}
1286
1287
1303struct GNUNET_SCHEDULER_Task *
1305 void *task_cls)
1306{
1307 struct GNUNET_SCHEDULER_Task *t;
1308
1311 t->callback = task;
1312 t->callback_cls = task_cls;
1313 t->read_fd = -1;
1314 t->write_fd = -1;
1315#if PROFILE_DELAYS
1316 t->start_time = GNUNET_TIME_absolute_get ();
1317#endif
1323 init_backtrace (t);
1324 return t;
1325}
1326
1327
1338struct GNUNET_SCHEDULER_Task *
1340 void *task_cls)
1341{
1342 struct GNUNET_SCHEDULER_Task *t;
1343
1344 /* scheduler must be running */
1346 GNUNET_assert (NULL != task);
1349 t->callback = task;
1350 t->callback_cls = task_cls;
1351 t->read_fd = -1;
1352 t->write_fd = -1;
1353#if PROFILE_DELAYS
1354 t->start_time = GNUNET_TIME_absolute_get ();
1355#endif
1359 t->lifeness = GNUNET_NO;
1362 t);
1364 "Adding shutdown task %p\n",
1365 t);
1366 init_backtrace (t);
1367 return t;
1368}
1369
1370
1371struct GNUNET_SCHEDULER_Task *
1374 void *task_cls)
1375{
1376 struct GNUNET_SCHEDULER_Task *ret;
1377
1378 ret = GNUNET_SCHEDULER_add_now (task, task_cls);
1379 ret->lifeness = lifeness;
1380 return ret;
1381}
1382
1383
1384#if DEBUG_FDS
1391void
1392check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd)
1393{
1394 if (-1 != raw_fd)
1395 {
1396 int flags = fcntl (raw_fd, F_GETFD);
1397
1398 if ((flags == -1) && (errno == EBADF))
1399 {
1401 "Got invalid file descriptor %d!\n",
1402 raw_fd);
1403 init_backtrace (t);
1404 GNUNET_assert (0);
1405 }
1406 }
1407}
1408
1409
1410#endif
1411
1412
1438static struct GNUNET_SCHEDULER_Task *
1441 const struct GNUNET_NETWORK_Handle *read_nh,
1442 const struct GNUNET_NETWORK_Handle *write_nh,
1443 const struct GNUNET_DISK_FileHandle *read_fh,
1444 const struct GNUNET_DISK_FileHandle *write_fh,
1446 void *task_cls)
1447{
1448 struct GNUNET_SCHEDULER_Task *t;
1449
1450 /* scheduler must be running */
1452 GNUNET_assert (NULL != task);
1455 init_fd_info (t,
1456 &read_nh,
1457 read_nh ? 1 : 0,
1458 &write_nh,
1459 write_nh ? 1 : 0,
1460 &read_fh,
1461 read_fh ? 1 : 0,
1462 &write_fh,
1463 write_fh ? 1 : 0);
1464 t->callback = task;
1465 t->callback_cls = task_cls;
1466#if DEBUG_FDS
1467 check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1);
1468 check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1);
1469 check_fd (t, NULL != read_fh ? read_fh->fd : -1);
1470 check_fd (t, NULL != write_fh ? write_fh->fd : -1);
1471#endif
1472#if PROFILE_DELAYS
1473 t->start_time = GNUNET_TIME_absolute_get ();
1474#endif
1481 t);
1484 t->priority);
1485 init_backtrace (t);
1486 return t;
1487}
1488
1489
1510struct GNUNET_SCHEDULER_Task *
1512 struct GNUNET_NETWORK_Handle *rfd,
1514 void *task_cls)
1515{
1518 rfd, task, task_cls);
1519}
1520
1521
1544struct GNUNET_SCHEDULER_Task *
1547 priority,
1548 struct GNUNET_NETWORK_Handle *rfd,
1550 void *task_cls)
1551{
1553 rfd,
1554 GNUNET_YES,
1555 GNUNET_NO,
1556 task, task_cls);
1557}
1558
1559
1581struct GNUNET_SCHEDULER_Task *
1583 struct GNUNET_NETWORK_Handle *wfd,
1585 void *task_cls)
1586{
1589 wfd,
1591 task, task_cls);
1592}
1593
1594
1618struct GNUNET_SCHEDULER_Task *
1621 struct GNUNET_NETWORK_Handle *fd,
1622 int on_read,
1623 int on_write,
1625 void *task_cls)
1626{
1627 /* scheduler must be running */
1629 GNUNET_assert (on_read || on_write);
1631 return add_without_sets (delay, priority,
1632 on_read ? fd : NULL,
1633 on_write ? fd : NULL,
1634 NULL,
1635 NULL,
1636 task, task_cls);
1637}
1638
1639
1660struct GNUNET_SCHEDULER_Task *
1662 const struct GNUNET_DISK_FileHandle *rfd,
1664 void *task_cls)
1665{
1668 rfd, GNUNET_YES, GNUNET_NO,
1669 task, task_cls);
1670}
1671
1672
1693struct GNUNET_SCHEDULER_Task *
1695 const struct GNUNET_DISK_FileHandle *wfd,
1697 void *task_cls)
1698{
1701 wfd, GNUNET_NO, GNUNET_YES,
1702 task, task_cls);
1703}
1704
1705
1729struct GNUNET_SCHEDULER_Task *
1732 priority,
1733 const struct
1735 int on_read, int on_write,
1737 void *task_cls)
1738{
1739 /* scheduler must be running */
1741 GNUNET_assert (on_read || on_write);
1742 GNUNET_assert (fd->fd >= 0);
1743 return add_without_sets (delay, priority,
1744 NULL,
1745 NULL,
1746 on_read ? fd : NULL,
1747 on_write ? fd : NULL,
1748 task, task_cls);
1749}
1750
1751
1752static void
1754 const struct GNUNET_NETWORK_Handle ***ntarget,
1755 unsigned int *extracted_nhandles,
1756 const struct GNUNET_DISK_FileHandle ***ftarget,
1757 unsigned int *extracted_fhandles)
1758{
1759 // FIXME: this implementation only works for unix, for WIN32 the file handles
1760 // in fdset must be handled separately
1761 const struct GNUNET_NETWORK_Handle **nhandles;
1762 const struct GNUNET_DISK_FileHandle **fhandles;
1763 unsigned int nhandles_len;
1764 unsigned int fhandles_len;
1765
1766 nhandles = NULL;
1767 fhandles = NULL;
1768 nhandles_len = 0;
1769 fhandles_len = 0;
1770 for (int sock = 0; sock != fdset->nsds; ++sock)
1771 {
1772 if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock))
1773 {
1774 struct GNUNET_NETWORK_Handle *nhandle;
1775 struct GNUNET_DISK_FileHandle *fhandle;
1776
1777 nhandle = GNUNET_NETWORK_socket_box_native (sock);
1778 if (NULL != nhandle)
1779 {
1780 GNUNET_array_append (nhandles, nhandles_len, nhandle);
1781 }
1782 else
1783 {
1784 fhandle = GNUNET_DISK_get_handle_from_int_fd (sock);
1785 if (NULL != fhandle)
1786 {
1787 GNUNET_array_append (fhandles, fhandles_len, fhandle);
1788 }
1789 else
1790 {
1791 GNUNET_assert (0);
1792 }
1793 }
1794 }
1795 }
1796 *ntarget = nhandles_len > 0 ? nhandles : NULL;
1797 *ftarget = fhandles_len > 0 ? fhandles : NULL;
1798 *extracted_nhandles = nhandles_len;
1799 *extracted_fhandles = fhandles_len;
1800}
1801
1802
1834struct GNUNET_SCHEDULER_Task *
1836 struct GNUNET_TIME_Relative delay,
1837 const struct GNUNET_NETWORK_FDSet *rs,
1838 const struct GNUNET_NETWORK_FDSet *ws,
1840 void *task_cls)
1841{
1842 struct GNUNET_SCHEDULER_Task *t;
1843 const struct GNUNET_NETWORK_Handle **read_nhandles = NULL;
1844 const struct GNUNET_NETWORK_Handle **write_nhandles = NULL;
1845 const struct GNUNET_DISK_FileHandle **read_fhandles = NULL;
1846 const struct GNUNET_DISK_FileHandle **write_fhandles = NULL;
1847 unsigned int read_nhandles_len = 0;
1848 unsigned int write_nhandles_len = 0;
1849 unsigned int read_fhandles_len = 0;
1850 unsigned int write_fhandles_len = 0;
1851 int no_rs = (NULL == rs);
1852 int no_ws = (NULL == ws);
1853 int empty_rs = (NULL != rs) && (0 == rs->nsds);
1854 int empty_ws = (NULL != ws) && (0 == ws->nsds);
1855 int no_fds = (no_rs && no_ws) ||
1856 (empty_rs && empty_ws) ||
1857 (no_rs && empty_ws) ||
1858 (no_ws && empty_rs);
1859 int no_fds_extracted;
1860
1861 /* scheduler must be running */
1863 GNUNET_assert (NULL != task);
1864 if (! no_fds)
1865 {
1866 if (NULL != rs)
1867 {
1868 extract_handles (rs,
1869 &read_nhandles,
1870 &read_nhandles_len,
1871 &read_fhandles,
1872 &read_fhandles_len);
1873 }
1874 if (NULL != ws)
1875 {
1876 extract_handles (ws,
1877 &write_nhandles,
1878 &write_nhandles_len,
1879 &write_fhandles,
1880 &write_fhandles_len);
1881 }
1882 }
1890 no_fds_extracted = (0 == read_nhandles_len) &&
1891 (0 == read_fhandles_len) &&
1892 (0 == write_nhandles_len) &&
1893 (0 == write_fhandles_len);
1894 if (no_fds || no_fds_extracted)
1896 prio,
1897 task,
1898 task_cls);
1901 init_fd_info (t,
1902 read_nhandles,
1903 read_nhandles_len,
1904 write_nhandles,
1905 write_nhandles_len,
1906 read_fhandles,
1907 read_fhandles_len,
1908 write_fhandles,
1909 write_fhandles_len);
1910 t->callback = task;
1911 t->callback_cls = task_cls;
1913 /* free the arrays of pointers to network / file handles, the actual
1914 * handles will be freed in destroy_task */
1915 GNUNET_array_grow (read_nhandles, read_nhandles_len, 0);
1916 GNUNET_array_grow (write_nhandles, write_nhandles_len, 0);
1917 GNUNET_array_grow (read_fhandles, read_fhandles_len, 0);
1918 GNUNET_array_grow (write_fhandles, write_fhandles_len, 0);
1919#if PROFILE_DELAYS
1920 t->start_time = GNUNET_TIME_absolute_get ();
1921#endif
1923 t->priority =
1924 check_priority ((prio ==
1926 prio);
1930 t);
1933 t->priority);
1935 "Adding task %p\n",
1936 t);
1937 init_backtrace (t);
1938 return t;
1939}
1940
1941
1953void
1955 struct GNUNET_SCHEDULER_FdInfo *fdi)
1956{
1957 enum GNUNET_SCHEDULER_Reason reason;
1958
1959 reason = task->reason;
1960 if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1961 (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)))
1963 if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
1964 (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)))
1967 task->reason = reason;
1968 if (GNUNET_NO == task->in_ready_list)
1969 {
1972 task);
1973 queue_ready_task (task);
1974 }
1975}
1976
1977
1998int
2000{
2001 struct GNUNET_SCHEDULER_Task *pos;
2002 struct GNUNET_TIME_Absolute now;
2003
2004 /* check for tasks that reached the timeout! */
2005 now = GNUNET_TIME_absolute_get ();
2007 while (NULL != pos)
2008 {
2009 struct GNUNET_SCHEDULER_Task *next = pos->next;
2010 if (now.abs_value_us >= pos->timeout.abs_value_us)
2012 if (0 == pos->reason)
2013 break;
2016 pos);
2017 if (pending_timeout_last == pos)
2018 pending_timeout_last = NULL;
2019 queue_ready_task (pos);
2020 pos = next;
2021 }
2022 pos = pending_head;
2023 while (NULL != pos)
2024 {
2025 struct GNUNET_SCHEDULER_Task *next = pos->next;
2026 if (now.abs_value_us >= pos->timeout.abs_value_us)
2027 {
2031 pos);
2032 queue_ready_task (pos);
2033 }
2034 pos = next;
2035 }
2036
2037 if (0 == ready_count)
2038 {
2040
2041 if (timeout.abs_value_us > now.abs_value_us)
2042 {
2057 "GNUNET_SCHEDULER_do_work did not find any ready "
2058 "tasks and timeout has not been reached yet.\n");
2059 }
2060 else
2061 {
2066 GNUNET_assert (0);
2067 }
2068 }
2069 else
2070 {
2071 /* find out which task priority level we are going to
2072 process this time */
2075 /* yes, p>0 is correct, 0 is "KEEP" which should
2076 * always be an empty queue (see assertion)! */
2078 work_priority > 0;
2079 work_priority--)
2080 {
2082 if (NULL != pos)
2083 break;
2084 }
2085 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2086
2087 /* process all *existing* tasks at this priority
2088 level, then yield */
2090 while (NULL != (pos = ready_head[work_priority])
2091 && pos != &pass_end_marker)
2092 {
2095 pos);
2096 ready_count--;
2099 active_task = pos;
2100#if PROFILE_DELAYS
2101 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2102 DELAY_THRESHOLD.rel_value_us)
2103 {
2105 "Task %p took %s to be scheduled\n",
2106 pos,
2108 GNUNET_TIME_absolute_get_duration (pos->start_time),
2109 GNUNET_YES));
2110 }
2111#endif
2112 tc.reason = pos->reason;
2115 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2116 tc.fds_len = pos->fds_len;
2117 tc.fds = pos->fds;
2118 for (unsigned int i = 0; i != pos->fds_len; ++i)
2119 {
2120 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
2121 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
2122 {
2124 fdi->sock);
2125 }
2126 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
2127 {
2129 fdi->sock);
2130 }
2131 }
2132 tc.read_ready = sh->rs;
2133 tc.write_ready = sh->ws;
2135 "Running task %p\n",
2136 pos);
2137 GNUNET_assert (NULL != pos->callback);
2138 {
2139 struct GNUNET_AsyncScopeSave old_scope;
2140 if (pos->scope.have_scope)
2141 GNUNET_async_scope_enter (&pos->scope.scope_id, &old_scope);
2142 else
2143 GNUNET_async_scope_get (&old_scope);
2144 pos->callback (pos->callback_cls);
2145 GNUNET_async_scope_restore (&old_scope);
2146 }
2147 if (NULL != pos->fds)
2148 {
2149 int del_result = scheduler_driver->del (scheduler_driver->cls,
2150 pos);
2151 if (GNUNET_OK != del_result)
2152 {
2154 "driver could not delete task %p\n", pos);
2155 GNUNET_assert (0);
2156 }
2157 }
2158 active_task = NULL;
2159 dump_backtrace (pos);
2160 destroy_task (pos);
2161 }
2163 }
2165 if (0 == ready_count)
2166 {
2168 get_timeout ());
2169 return GNUNET_NO;
2170 }
2173 return GNUNET_YES;
2174}
2175
2176
2210{
2212 const struct GNUNET_DISK_FileHandle *pr;
2213
2214 /* scheduler must not be running */
2217 /* general set-up */
2223 my_pid = getpid ();
2224 scheduler_driver = driver;
2225
2226 /* install signal handlers */
2228 "Registering signal handlers\n");
2229 sh->shc_int = GNUNET_SIGNAL_handler_install (SIGINT,
2231 sh->shc_term = GNUNET_SIGNAL_handler_install (SIGTERM,
2233#if (SIGTERM != GNUNET_TERM_SIG)
2236#endif
2237 sh->shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE,
2239 sh->shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT,
2241 sh->shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP,
2243
2244 /* Setup initial tasks */
2247 /* ensure this task runs first, by using a priority level reserved for
2248 the scheduler (not really shutdown, but start-up ;-) */
2252 NULL);
2255 pr,
2257 NULL);
2260 get_timeout ());
2261 /* begin main event loop */
2265 return sh;
2266}
2267
2268
2283void
2285{
2286 GNUNET_break (NULL == pending_head);
2288 GNUNET_break (NULL == shutdown_head);
2289 for (int i = 0; i != GNUNET_SCHEDULER_PRIORITY_COUNT; ++i)
2290 {
2291 GNUNET_break (NULL == ready_head[i]);
2292 }
2295
2296 /* uninstall signal handlers */
2299#if (SIGTERM != GNUNET_TERM_SIG)
2301#endif
2306 shutdown_pipe_handle = NULL;
2307 scheduler_driver = NULL;
2308 GNUNET_free (sh);
2309}
2310
2311
2312static enum GNUNET_GenericReturnValue
2314 struct DriverContext *context)
2315{
2316 struct GNUNET_NETWORK_FDSet *rs;
2317 struct GNUNET_NETWORK_FDSet *ws;
2318 int select_result;
2319
2320 GNUNET_assert (NULL != context);
2323 while ((NULL != context->scheduled_head) ||
2324 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
2325 context->timeout.abs_value_us))
2326 {
2327 struct GNUNET_TIME_Relative time_remaining;
2328
2330 "select timeout = %s\n",
2332
2335
2336 for (struct Scheduled *pos = context->scheduled_head;
2337 NULL != pos;
2338 pos = pos->next)
2339 {
2340 if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et))
2341 {
2342 GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock);
2343 }
2344 if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et))
2345 {
2346 GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock);
2347 }
2348 }
2349 time_remaining = GNUNET_TIME_absolute_get_remaining (context->timeout);
2350 if (0 < ready_count)
2351 time_remaining = GNUNET_TIME_UNIT_ZERO;
2352 if (NULL == scheduler_select)
2353 {
2354 select_result = GNUNET_NETWORK_socket_select (rs,
2355 ws,
2356 NULL,
2357 time_remaining);
2358 }
2359 else
2360 {
2361 select_result = scheduler_select (scheduler_select_cls,
2362 rs,
2363 ws,
2364 NULL,
2365 time_remaining);
2366 }
2367 if (select_result == GNUNET_SYSERR)
2368 {
2369 if (errno == EINTR)
2370 continue;
2371
2373 "select");
2374#if USE_LSOF
2375 char lsof[512];
2376
2377 snprintf (lsof,
2378 sizeof(lsof),
2379 "lsof -p %d",
2380 getpid ());
2381 (void) close (1);
2382 (void) dup2 (2, 1);
2383 if (0 != system (lsof))
2385 "system");
2386#endif
2387#if DEBUG_FDS
2388 for (struct Scheduled *s = context->scheduled_head;
2389 NULL != s;
2390 s = s->next)
2391 {
2392 int flags = fcntl (s->fdi->sock,
2393 F_GETFD);
2394
2395 if ((flags == -1) &&
2396 (EBADF == errno))
2397 {
2399 "Got invalid file descriptor %d!\n",
2400 s->fdi->sock);
2401#if EXECINFO
2402 dump_backtrace (s->task);
2403#endif
2404 }
2405 }
2406#endif
2407 GNUNET_assert (0);
2410 return GNUNET_SYSERR;
2411 }
2412 if (select_result > 0)
2413 {
2414 for (struct Scheduled *pos = context->scheduled_head;
2415 NULL != pos;
2416 pos = pos->next)
2417 {
2418 int is_ready = GNUNET_NO;
2419
2420 if ((0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) &&
2421 (GNUNET_YES ==
2423 pos->fdi->sock)) )
2424 {
2425 pos->fdi->et |= GNUNET_SCHEDULER_ET_IN;
2426 is_ready = GNUNET_YES;
2427 }
2428 if ((0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) &&
2429 (GNUNET_YES ==
2431 pos->fdi->sock)) )
2432 {
2433 pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT;
2434 is_ready = GNUNET_YES;
2435 }
2436 if (GNUNET_YES == is_ready)
2437 {
2438 GNUNET_SCHEDULER_task_ready (pos->task,
2439 pos->fdi);
2440 }
2441 }
2442 }
2444 {
2446 "scheduler has more tasks ready!\n");
2447 }
2448 }
2451
2452 if ( (NULL == context->scheduled_head) &&
2453 (NULL != pending_timeout_head) &&
2454 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us ==
2455 context->timeout.abs_value_us) )
2456 {
2457 /* Only remaining task has timeout of 'forever'.
2458 We exit here more as sanity measure, as just
2459 waiting forever isn't exactly useful. Still,
2460 this is indicative of a bug in the client code. */
2461 GNUNET_break (0);
2462 return GNUNET_NO;
2463 }
2464 return GNUNET_OK;
2465}
2466
2467
2468static int
2469select_add (void *cls,
2470 struct GNUNET_SCHEDULER_Task *task,
2471 struct GNUNET_SCHEDULER_FdInfo *fdi)
2472{
2473 struct DriverContext *context = cls;
2474 struct Scheduled *scheduled;
2475
2476 GNUNET_assert (NULL != context);
2477 GNUNET_assert (NULL != task);
2478 GNUNET_assert (NULL != fdi);
2480 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et));
2481
2482 if (! ((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0))
2483 {
2484 /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */
2485 return GNUNET_SYSERR;
2486 }
2487
2488 scheduled = GNUNET_new (struct Scheduled);
2489 scheduled->task = task;
2490 scheduled->fdi = fdi;
2491 scheduled->et = fdi->et;
2492
2493 GNUNET_CONTAINER_DLL_insert (context->scheduled_head,
2494 context->scheduled_tail,
2495 scheduled);
2496 return GNUNET_OK;
2497}
2498
2499
2500static int
2501select_del (void *cls,
2503{
2504 struct DriverContext *context;
2505 struct Scheduled *pos;
2506 int ret;
2507
2508 GNUNET_assert (NULL != cls);
2509
2510 context = cls;
2512 pos = context->scheduled_head;
2513 while (NULL != pos)
2514 {
2515 struct Scheduled *next = pos->next;
2516 if (pos->task == task)
2517 {
2518 GNUNET_CONTAINER_DLL_remove (context->scheduled_head,
2519 context->scheduled_tail,
2520 pos);
2521 GNUNET_free (pos);
2522 ret = GNUNET_OK;
2523 }
2524 pos = next;
2525 }
2526 return ret;
2527}
2528
2529
2530static void
2532 struct GNUNET_TIME_Absolute dt)
2533{
2534 struct DriverContext *context = cls;
2535
2536 GNUNET_assert (NULL != context);
2537 context->timeout = dt;
2538}
2539
2540
2548{
2549 struct GNUNET_SCHEDULER_Driver *select_driver;
2550
2551 select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver);
2552
2553 select_driver->add = &select_add;
2554 select_driver->del = &select_del;
2555 select_driver->set_wakeup = &select_set_wakeup;
2556
2557 return select_driver;
2558}
2559
2560
2573void
2575{
2576 struct GNUNET_AsyncScopeSave dummy_old_scope;
2577
2578 GNUNET_assert (NULL != active_task);
2579 /* Since we're in a task, the context will be automatically
2580 restored by the scheduler. */
2581 GNUNET_async_scope_enter (aid, &dummy_old_scope);
2582}
2583
2584
2585/* end of scheduler.c */
static int ret
Final status code.
Definition: gnunet-arm.c:93
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:118
static struct GNUNET_TIME_Absolute start_time
Start time of the current round; used to determine how long one iteration takes (which influences how...
static pa_context * context
Pulseaudio context.
static struct GNUNET_IDENTITY_Handle * sh
Handle to IDENTITY service.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
static struct GNUNET_SCHEDULER_Task * t
Main task.
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:1602
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:682
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1425
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1572
enum GNUNET_GenericReturnValue GNUNET_DISK_handle_invalid(const struct GNUNET_DISK_FileHandle *h)
Checks whether a handle is invalid.
Definition: disk.c:186
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition: disk.c:1311
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:646
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_after(head, tail, other, element)
Insert an element into a DLL after the given other element.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_MAX(a, b)
GNUNET_SCHEDULER_Priority
Valid task priorities.
void GNUNET_async_scope_enter(const struct GNUNET_AsyncScopeId *aid, struct GNUNET_AsyncScopeSave *old_scope)
Set the async scope for the current thread.
int have_scope
GNUNET_YES unless this saved scope is the unnamed root scope.
void GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
Get the current async scope.
void GNUNET_async_scope_restore(struct GNUNET_AsyncScopeSave *old_scope)
Clear the current thread's async scope.
GNUNET_GenericReturnValue
Named constants for return values.
struct GNUNET_AsyncScopeId scope_id
Saved scope.
@ GNUNET_SCHEDULER_PRIORITY_COUNT
Number of priorities (must be the last priority).
@ GNUNET_SCHEDULER_PRIORITY_KEEP
Run with the same priority as the current job.
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
@ GNUNET_SCHEDULER_PRIORITY_SHUTDOWN
This is an internal priority level that is only used for tasks that are being triggered due to shutdo...
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_free_nz(ptr)
Wrapper around free.
void GNUNET_NETWORK_fdset_zero(struct GNUNET_NETWORK_FDSet *fds)
Reset FD set (clears all file descriptors).
Definition: network.c:918
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1185
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1001
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1169
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_box_native(int fd)
Box a native socket (and check that it is a socket).
Definition: network.c:580
void GNUNET_NETWORK_fdset_set_native(struct GNUNET_NETWORK_FDSet *to, int nfd)
Set a native fd in a set.
Definition: network.c:1058
int GNUNET_NETWORK_fdset_test_native(const struct GNUNET_NETWORK_FDSet *to, int nfd)
Test native fd in a set.
Definition: network.c:1076
void GNUNET_NETWORK_socket_free_memory_only_(struct GNUNET_NETWORK_Handle *desc)
Only free memory of a socket, keep the file descriptor untouched.
Definition: network.c:566
int GNUNET_NETWORK_socket_select(struct GNUNET_NETWORK_FDSet *rfds, struct GNUNET_NETWORK_FDSet *wfds, struct GNUNET_NETWORK_FDSet *efds, struct GNUNET_TIME_Relative timeout)
Check if sockets meet certain conditions.
Definition: network.c:1259
void GNUNET_NETWORK_fdset_handle_set(struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h)
Add a file handle to the fd set.
Definition: network.c:1092
void GNUNET_OS_install_parent_control_handler(void *cls)
Connects this process to its parent via pipe; essentially, the parent control handler will read signa...
Definition: os_priority.c:133
void GNUNET_SCHEDULER_shutdown()
Request the shutdown of a scheduler.
Definition: scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1511
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now_with_lifeness(int lifeness, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible with the (transitive) ignore-shutdown flag either e...
Definition: scheduler.c:1372
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:725
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1694
void GNUNET_SCHEDULER_driver_done(struct GNUNET_SCHEDULER_Handle *sh)
Counter-part of GNUNET_SCHEDULER_driver_init.
Definition: scheduler.c:2284
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified priority and to be run after the specified delay or wh...
Definition: scheduler.c:1545
void GNUNET_SCHEDULER_task_ready(struct GNUNET_SCHEDULER_Task *task, struct GNUNET_SCHEDULER_FdInfo *fdi)
Function used by event-loop implementations to signal the scheduler that a particular task is ready d...
Definition: scheduler.c:1954
void GNUNET_SCHEDULER_add_with_reason_and_priority(GNUNET_SCHEDULER_TaskCallback task, void *task_cls, enum GNUNET_SCHEDULER_Reason reason, enum GNUNET_SCHEDULER_Priority priority)
Continue the current execution with the given function.
Definition: scheduler.c:1074
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1661
int GNUNET_SCHEDULER_do_work(struct GNUNET_SCHEDULER_Handle *sh)
Function called by external event loop implementations to tell the scheduler to run some of the tasks...
Definition: scheduler.c:1999
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1582
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_select(enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
Definition: scheduler.c:1835
unsigned int GNUNET_SCHEDULER_get_load(enum GNUNET_SCHEDULER_Priority p)
Get information about the current load of this scheduler.
Definition: scheduler.c:775
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context()
Obtain the task context, giving the reason why the current task was started.
Definition: scheduler.c:758
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_file_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, const struct GNUNET_DISK_FileHandle *fd, int on_read, int on_write, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready.
Definition: scheduler.c:1730
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_at(struct GNUNET_TIME_Absolute at, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run at the specified time.
Definition: scheduler.c:1254
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1339
struct GNUNET_SCHEDULER_Driver * GNUNET_SCHEDULER_driver_select()
Obtain the driver for using select() as the event loop.
Definition: scheduler.c:2547
void GNUNET_SCHEDULER_begin_async_scope(struct GNUNET_AsyncScopeId *aid)
Change the async scope for the currently executing task and (transitively) for all tasks scheduled by...
Definition: scheduler.c:2574
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:980
void GNUNET_SCHEDULER_set_select(GNUNET_SCHEDULER_select new_select, void *new_select_cls)
Sets the select function to use in the scheduler (scheduler_select).
Definition: scheduler.c:447
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1304
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_net_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, struct GNUNET_NETWORK_Handle *fd, int on_read, int on_write, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready.
Definition: scheduler.c:1619
GNUNET_SCHEDULER_Reason
Reasons why the schedule may have triggered the task now.
void(* GNUNET_SCHEDULER_TaskCallback)(void *cls)
Signature of the main function of a task.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1277
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1207
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_at_with_priority(struct GNUNET_TIME_Absolute at, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run at the specified time.
Definition: scheduler.c:1118
struct GNUNET_SCHEDULER_Handle * GNUNET_SCHEDULER_driver_init(const struct GNUNET_SCHEDULER_Driver *driver)
Function called by external event loop implementations to initialize the scheduler.
Definition: scheduler.c:2209
GNUNET_SCHEDULER_EventType
Possible events on FDs, used as a bitmask.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_with_priority(enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified priority.
Definition: scheduler.c:1231
int(* GNUNET_SCHEDULER_select)(void *cls, struct GNUNET_NETWORK_FDSet *rfds, struct GNUNET_NETWORK_FDSet *wfds, struct GNUNET_NETWORK_FDSet *efds, struct GNUNET_TIME_Relative timeout)
Signature of the select function used by the scheduler.
@ GNUNET_SCHEDULER_REASON_TIMEOUT
The specified timeout has expired.
@ GNUNET_SCHEDULER_REASON_READ_READY
The reading socket is ready.
@ GNUNET_SCHEDULER_REASON_SHUTDOWN
We are shutting down and are running all shutdown-related tasks.
@ GNUNET_SCHEDULER_REASON_STARTUP
This is the very first task run during startup.
@ GNUNET_SCHEDULER_REASON_WRITE_READY
The writing socket is ready.
@ GNUNET_SCHEDULER_REASON_PREREQ_DONE
The prerequisite task is done.
@ GNUNET_SCHEDULER_ET_OUT
Buffer available for writing.
@ GNUNET_SCHEDULER_ET_NONE
No event (useful for timeout).
@ GNUNET_SCHEDULER_ET_IN
Data available for reading.
struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install(int signal, GNUNET_SIGNAL_Handler handler)
Install a signal handler that will be run if the given signal is received.
Definition: signal.c:52
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal handler.
Definition: signal.c:78
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition: time.c:438
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition: time.c:406
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:579
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:316
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
#define GNUNET_TIME_UNIT_ZERO_ABS
Absolute time zero.
const char * GNUNET_STRINGS_absolute_time_to_string(struct GNUNET_TIME_Absolute t)
Like asctime, except for GNUnet time.
Definition: strings.c:640
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:234
static void sighandler_pipe()
Signal handler called for SIGPIPE.
Definition: scheduler.c:672
static void dump_backtrace(struct GNUNET_SCHEDULER_Task *t)
Output stack trace of task t.
Definition: scheduler.c:600
static void driver_add_multiple(struct GNUNET_SCHEDULER_Task *t)
calls the given function func on each FdInfo related to t.
Definition: scheduler.c:914
static struct GNUNET_SCHEDULER_Task * shutdown_pipe_task
Task for reading from a pipe that signal handlers will use to initiate shutdown.
Definition: scheduler.c:393
static void select_set_wakeup(void *cls, struct GNUNET_TIME_Absolute dt)
Definition: scheduler.c:2531
static void destroy_task(struct GNUNET_SCHEDULER_Task *t)
Destroy a task (release associated resources)
Definition: scheduler.c:621
static enum GNUNET_SCHEDULER_Priority check_priority(enum GNUNET_SCHEDULER_Priority p)
Check that the given priority is legal (and return it).
Definition: scheduler.c:462
static void queue_ready_task(struct GNUNET_SCHEDULER_Task *task)
Put a task that is ready for execution into the ready queue.
Definition: scheduler.c:546
static int select_del(void *cls, struct GNUNET_SCHEDULER_Task *task)
Definition: scheduler.c:2501
static struct GNUNET_SCHEDULER_Task * install_parent_control_task
Task for installing parent control handlers (it might happen that the scheduler is shutdown before th...
Definition: scheduler.c:387
static struct GNUNET_SCHEDULER_Task * active_task
ID of the task that is running right now.
Definition: scheduler.c:368
static struct GNUNET_SCHEDULER_Task * ready_tail[GNUNET_SCHEDULER_PRIORITY_COUNT]
Tail of list of tasks ready to run right now, grouped by importance.
Definition: scheduler.c:379
static enum GNUNET_SCHEDULER_Priority current_priority
Priority of the task running right now.
Definition: scheduler.c:404
static struct GNUNET_SCHEDULER_Task * pending_head
Head of list of tasks waiting for an event.
Definition: scheduler.c:324
static struct GNUNET_TIME_Absolute get_timeout()
chooses the nearest timeout from all pending tasks, to be used to tell the driver the next wakeup tim...
Definition: scheduler.c:477
static void remove_pass_end_marker()
Definition: scheduler.c:515
#define DELAY_THRESHOLD
Task that were in the queue for longer than this are reported if PROFILE_DELAYS is active.
Definition: scheduler.c:74
static unsigned int ready_count
Number of tasks on the ready list.
Definition: scheduler.c:398
static struct GNUNET_DISK_PipeHandle * shutdown_pipe_handle
Pipe used to communicate shutdown via signal.
Definition: scheduler.c:660
static const struct GNUNET_SCHEDULER_Driver * scheduler_driver
The driver used for the event loop.
Definition: scheduler.c:319
static struct GNUNET_SCHEDULER_Task * pending_timeout_head
List of tasks waiting ONLY for a timeout event.
Definition: scheduler.c:348
static void install_parent_control_handler(void *cls)
Definition: scheduler.c:936
static int select_add(void *cls, struct GNUNET_SCHEDULER_Task *task, struct GNUNET_SCHEDULER_FdInfo *fdi)
Definition: scheduler.c:2469
static GNUNET_SCHEDULER_select scheduler_select
Function to use as a select() in the scheduler.
Definition: scheduler.c:426
static enum GNUNET_SCHEDULER_Priority work_priority
Priority used currently in GNUNET_SCHEDULER_do_work().
Definition: scheduler.c:420
static void shutdown_if_no_lifeness(void)
Definition: scheduler.c:699
static void * scheduler_select_cls
Closure for scheduler_select.
Definition: scheduler.c:436
static struct GNUNET_SCHEDULER_Task * pending_timeout_tail
List of tasks waiting ONLY for a timeout event.
Definition: scheduler.c:357
static struct GNUNET_SCHEDULER_Task * ready_head[GNUNET_SCHEDULER_PRIORITY_COUNT]
Head of list of tasks ready to run right now, grouped by importance.
Definition: scheduler.c:373
static struct GNUNET_SCHEDULER_Task pass_end_marker
Placed at the end of a ready queue to indicate where a scheduler run pass ends.
Definition: scheduler.c:256
static struct GNUNET_SCHEDULER_Task * add_without_sets(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, const struct GNUNET_NETWORK_Handle *read_nh, const struct GNUNET_NETWORK_Handle *write_nh, const struct GNUNET_DISK_FileHandle *read_fh, const struct GNUNET_DISK_FileHandle *write_fh, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
Definition: scheduler.c:1439
static int current_lifeness
Value of the 'lifeness' flag for the current task.
Definition: scheduler.c:415
static void set_work_priority(enum GNUNET_SCHEDULER_Priority p)
Definition: scheduler.c:528
static void init_backtrace(struct GNUNET_SCHEDULER_Task *t)
Initialize backtrace data for task t.
Definition: scheduler.c:1046
static enum GNUNET_SCHEDULER_Priority max_priority_added
Priority of the highest task added in the current select iteration.
Definition: scheduler.c:410
static struct GNUNET_SCHEDULER_Task * pending_timeout_last
Last inserted task waiting ONLY for a timeout event.
Definition: scheduler.c:363
static void sighandler_shutdown(void)
Signal handler called for signals that should cause us to shutdown.
Definition: scheduler.c:682
#define LOG(kind,...)
Definition: scheduler.c:32
static void shutdown_pipe_cb(void *cls)
Definition: scheduler.c:945
#define LOG_STRERROR(kind, syscall)
Definition: scheduler.c:34
static enum GNUNET_GenericReturnValue select_loop(struct GNUNET_SCHEDULER_Handle *sh, struct DriverContext *context)
Definition: scheduler.c:2313
static void init_fd_info(struct GNUNET_SCHEDULER_Task *t, const struct GNUNET_NETWORK_Handle *const *read_nh, unsigned int read_nh_len, const struct GNUNET_NETWORK_Handle *const *write_nh, unsigned int write_nh_len, const struct GNUNET_DISK_FileHandle *const *read_fh, unsigned int read_fh_len, const struct GNUNET_DISK_FileHandle *const *write_fh, unsigned int write_fh_len)
Definition: scheduler.c:797
static struct GNUNET_SCHEDULER_Task * pending_tail
Tail of list of tasks waiting for an event.
Definition: scheduler.c:329
static struct GNUNET_SCHEDULER_Task * shutdown_tail
Tail of list of tasks waiting for shutdown.
Definition: scheduler.c:339
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:431
static struct GNUNET_SCHEDULER_Task * shutdown_head
Head of list of tasks waiting for shutdown.
Definition: scheduler.c:334
static pid_t my_pid
Process ID of this process at the time we installed the various signal handlers.
Definition: scheduler.c:666
static void extract_handles(const struct GNUNET_NETWORK_FDSet *fdset, const struct GNUNET_NETWORK_Handle ***ntarget, unsigned int *extracted_nhandles, const struct GNUNET_DISK_FileHandle ***ftarget, unsigned int *extracted_fhandles)
Definition: scheduler.c:1753
Driver context used by GNUNET_SCHEDULER_run.
Definition: scheduler.c:291
struct Scheduled * scheduled_head
the head of a DLL containing information about the events the select driver is waiting for
Definition: scheduler.c:296
struct GNUNET_TIME_Absolute timeout
the time when the select driver will wake up again (after calling select)
Definition: scheduler.c:308
struct Scheduled * scheduled_tail
the tail of a DLL containing information about the events the select driver is waiting for
Definition: scheduler.c:302
Identifier for an asynchronous execution context.
Saved async scope identifier or root scope.
Handle used to access files (and pipes).
int fd
File handle on Unix-like systems.
Handle used to manage a pipe.
Definition: disk.c:69
collection of IO descriptors
int nsds
Maximum number of any socket descriptor in the set (plus one)
handle to a socket
Definition: network.c:53
API an external event loop has to implement for GNUNET_SCHEDULER_driver_init.
void * cls
Closure to pass to the functions in this struct.
int(* add)(void *cls, struct GNUNET_SCHEDULER_Task *task, struct GNUNET_SCHEDULER_FdInfo *fdi)
Add a task to be run if the conditions specified in the et field of the given fdi are satisfied.
void(* set_wakeup)(void *cls, struct GNUNET_TIME_Absolute dt)
Set time at which we definitively want to get a wakeup call.
int(* del)(void *cls, struct GNUNET_SCHEDULER_Task *task)
Delete a task from the set of tasks to be run.
Information about an event relating to a file descriptor/socket.
int sock
Underlying OS handle the event was about.
enum GNUNET_SCHEDULER_EventType et
Type of the event that was generated related to sock.
const struct GNUNET_DISK_FileHandle * fh
GNUnet file handle the event is about, matches sock, NULL if this is about a network socket or if no ...
const struct GNUNET_NETWORK_Handle * fd
GNUnet network socket the event is about, matches sock, NULL if this is about a file handle or if no ...
Argument to be passed from the driver to GNUNET_SCHEDULER_do_work().
Definition: scheduler.c:83
struct GNUNET_NETWORK_FDSet * rs
Passed here to avoid constantly allocating/deallocating this element, but generally we want to get ri...
Definition: scheduler.c:89
struct GNUNET_SIGNAL_Context * shc_quit
context of the SIGQUIT handler
Definition: scheduler.c:118
struct GNUNET_SIGNAL_Context * shc_hup
context of the SIGHUP handler
Definition: scheduler.c:123
struct GNUNET_SIGNAL_Context * shc_int
context of the SIGINT handler
Definition: scheduler.c:101
struct GNUNET_SIGNAL_Context * shc_pipe
context of the SIGPIPE handler
Definition: scheduler.c:128
struct GNUNET_NETWORK_FDSet * ws
Passed here to avoid constantly allocating/deallocating this element, but generally we want to get ri...
Definition: scheduler.c:96
struct GNUNET_SIGNAL_Context * shc_term
context of the SIGTERM handler
Definition: scheduler.c:106
Context information passed to each scheduler task.
const struct GNUNET_NETWORK_FDSet * read_ready
Set of file descriptors ready for reading; note that additional bits may be set that were not in the ...
enum GNUNET_SCHEDULER_Reason reason
Reason why the task is run now.
unsigned int fds_len
Length of the following array.
const struct GNUNET_SCHEDULER_FdInfo * fds
Array of length fds_len with information about ready FDs.
const struct GNUNET_NETWORK_FDSet * write_ready
Set of file descriptors ready for writing; note that additional bits may be set that were not in the ...
Entry in list of pending tasks.
Definition: scheduler.c:136
enum GNUNET_SCHEDULER_Priority priority
Task priority.
Definition: scheduler.c:204
struct GNUNET_SCHEDULER_Task * prev
This is a linked list.
Definition: scheduler.c:145
void * callback_cls
Closure for the callback.
Definition: scheduler.c:155
int in_ready_list
Is this task in the ready list?
Definition: scheduler.c:230
int lifeness
Should the existence of this task in the queue be counted as reason to not shutdown the scheduler?
Definition: scheduler.c:220
enum GNUNET_SCHEDULER_Reason reason
Why is the task ready? Set after task is added to ready queue.
Definition: scheduler.c:199
int own_handles
Do we own the network and file handles referenced by the FdInfo structs in the fds array.
Definition: scheduler.c:179
struct GNUNET_AsyncScopeSave scope
Asynchronous scope of the task that scheduled this scope,.
Definition: scheduler.c:248
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition: scheduler.c:140
int on_shutdown
Is this task run on shutdown?
Definition: scheduler.c:225
struct GNUNET_SCHEDULER_FdInfo * fds
Information about which FDs are ready for this task (and why).
Definition: scheduler.c:160
unsigned int fds_len
Size of the fds array.
Definition: scheduler.c:172
struct GNUNET_TIME_Absolute timeout
Absolute timeout value for the task, or GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
Definition: scheduler.c:185
GNUNET_SCHEDULER_TaskCallback callback
Function to run when ready.
Definition: scheduler.c:150
int write_fd
Set if we only wait for writing to a single FD, otherwise -1.
Definition: scheduler.c:214
struct GNUNET_SCHEDULER_FdInfo fdx
Storage location used for fds if we want to avoid a separate malloc() call in the common case that th...
Definition: scheduler.c:167
int read_fd
Set if we only wait for reading from a single FD, otherwise -1.
Definition: scheduler.c:209
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
A struct representing an event the select driver is waiting for.
Definition: scheduler.c:263
struct Scheduled * next
Definition: scheduler.c:266
enum GNUNET_SCHEDULER_EventType et
the event types (multiple event types can be ORed) the select driver is expected to wait for
Definition: scheduler.c:283
struct Scheduled * prev
Definition: scheduler.c:264
struct GNUNET_SCHEDULER_FdInfo * fdi
information about the network socket / file descriptor where the event is expected to occur
Definition: scheduler.c:277
struct GNUNET_SCHEDULER_Task * task
the task, the event is related to
Definition: scheduler.c:271