GNUnet 0.26.2-17-g3d7c5992e
 
Loading...
Searching...
No Matches
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
35#define EXTRA_DEBUG 0
36
37#define LOG(kind, ...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__)
38
39#define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
40 "util-scheduler", \
41 syscall)
42
43
44#if HAVE_EXECINFO_H
45#include "execinfo.h"
46
51#define USE_LSOF GNUNET_NO
52
56#define EXECINFO GNUNET_NO
57
61#define DEBUG_FDS GNUNET_NO
62
66#define MAX_TRACE_DEPTH 50
67#endif
68
73#define PROFILE_DELAYS GNUNET_NO
74
79#define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS
80
81
88{
95
102
107
112
113#if (SIGTERM != GNUNET_TERM_SIG)
117 struct GNUNET_SIGNAL_Context *shc_gterm;
118#endif
119
124
129
134};
135
136
141{
146
151
156
161
166
173
177 unsigned int fds_len;
178
185
191
192#if PROFILE_DELAYS
197#endif
198
205
210
215
220
226
231
236
237#if EXECINFO
242 char **backtrace_strings;
243
247 int num_backtrace_strings;
248#endif
249
254};
255
262
263
290
291
315
316
325
330
335
340
345
354
363
369
374
378static struct
380
384static struct
386
393
399
403static unsigned int ready_count;
404
410
416
421
426
432
437
442
443
451void
453 void *new_select_cls)
454{
455 scheduler_select = new_select;
456 scheduler_select_cls = new_select_cls;
457}
458
459
468{
469 if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
470 return p;
471 GNUNET_assert (0);
472 return 0; /* make compiler happy */
473}
474
475
481static struct GNUNET_TIME_Absolute
483{
484 struct GNUNET_SCHEDULER_Task *pos;
485 struct GNUNET_TIME_Absolute now;
487
491 if (NULL != pos)
492 {
493 if (0 != pos->reason)
494 {
495 return now;
496 }
497 else
498 {
499 timeout = pos->timeout;
500 }
501 }
502 for (pos = pending_head; NULL != pos; pos = pos->next)
503 {
504 if (0 != pos->reason)
505 {
506 return now;
507 }
508 else if ((pos->timeout.abs_value_us !=
509 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) &&
510 (timeout.abs_value_us > pos->timeout.abs_value_us))
511 {
512 timeout = pos->timeout;
513 }
514 }
515 return timeout;
516}
517
518
519static void
530
531
532static void
543
544
550static void
563
564
571void
573{
574 struct GNUNET_SCHEDULER_Task *pos;
575
577 "GNUNET_SCHEDULER_shutdown\n");
578 if (NULL != install_parent_control_task)
579 {
582 }
583 if (NULL != shutdown_pipe_task)
584 {
586 shutdown_pipe_task = NULL;
587 }
588 while (NULL != (pos = shutdown_head))
589 {
592 pos);
594 queue_ready_task (pos);
595 }
596}
597
598
604static void
606{
607#if EXECINFO
608 for (unsigned int i = 0; i < t->num_backtrace_strings; i++)
610 "Task %p trace %u: %s\n",
611 t,
612 i,
613 t->backtrace_strings[i]);
614#else
615 (void) t;
616#endif
617}
618
619
625static void
627{
628#if EXTRA_DEBUG
630 "destroying task %p\n",
631 t);
632#endif
633 if (GNUNET_YES == t->own_handles)
634 {
635 for (unsigned int i = 0; i != t->fds_len; ++i)
636 {
637 const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd;
638 const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh;
639 if (fd)
640 {
642 (struct GNUNET_NETWORK_Handle *) fd);
643 }
644 if (fh)
645 {
646 // FIXME: on WIN32 this is not enough! A function
647 // GNUNET_DISK_file_free_memory_only would be nice
648 GNUNET_free_nz ((void *) fh);
649 }
650 }
651 }
652 if (t->fds_len > 1)
653 {
655 }
656#if EXECINFO
657 GNUNET_free (t->backtrace_strings);
658#endif
659 GNUNET_free (t);
660}
661
662
667
672static pid_t my_pid;
673
677static void
679{
680 return;
681}
682
683
687static void
689{
690 static char c;
691 int old_errno = errno; /* backup errno */
692
693 if (getpid () != my_pid)
694 _exit (1); /* we have fork'ed since the signal handler was created,
695 * ignore the signal, see https://gnunet.org/vfork discussion */
699 &c, sizeof(c));
700 errno = old_errno;
701}
702
703
704static void
706{
707 struct GNUNET_SCHEDULER_Task *t;
708
709 if (ready_count > 0)
710 return;
711 for (t = pending_head; NULL != t; t = t->next)
712 if (GNUNET_YES == t->lifeness)
713 return;
714 for (t = shutdown_head; NULL != t; t = t->next)
715 if (GNUNET_YES == t->lifeness)
716 return;
717 for (t = pending_timeout_head; NULL != t; t = t->next)
718 if (GNUNET_YES == t->lifeness)
719 return;
720 /* No lifeness! */
722}
723
724
727 struct DriverContext *context);
728
729
730void
732 void *task_cls)
733{
735 struct GNUNET_SCHEDULER_Driver *driver;
736 struct DriverContext context = {
737 .scheduled_head = NULL,
738 .scheduled_tail = NULL,
739 .timeout = GNUNET_TIME_absolute_get ()
740 };
741
743 driver->cls = &context;
746 task_cls,
751 &context));
753 GNUNET_free (driver);
754}
755
756
763const struct GNUNET_SCHEDULER_TaskContext *
765{
766 GNUNET_assert (NULL != active_task);
767 return &tc;
768}
769
770
780unsigned int
782{
783 unsigned int ret;
784
785 GNUNET_assert (NULL != active_task);
787 return ready_count;
790 ret = 0;
791 for (struct GNUNET_SCHEDULER_Task *pos = ready_head[check_priority (p)];
792 NULL != pos;
793 pos = pos->next)
794 ret++;
796 // Don't count the dummy marker
797 ret--;
798 return ret;
799}
800
801
802static void
804 const struct GNUNET_NETWORK_Handle *const *read_nh,
805 unsigned int read_nh_len,
806 const struct GNUNET_NETWORK_Handle *const *write_nh,
807 unsigned int write_nh_len,
808 const struct GNUNET_DISK_FileHandle *const *read_fh,
809 unsigned int read_fh_len,
810 const struct GNUNET_DISK_FileHandle *const *write_fh,
811 unsigned int write_fh_len)
812{
813 // FIXME: if we have exactly two network handles / exactly two file handles
814 // and they are equal, we can make one FdInfo with both
815 // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set.
816 struct GNUNET_SCHEDULER_FdInfo *fdi;
817
818 t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len;
819 if (1 == t->fds_len)
820 {
821 fdi = &t->fdx;
822 t->fds = fdi;
823 if (1 == read_nh_len)
824 {
825 GNUNET_assert (NULL != read_nh);
826 GNUNET_assert (NULL != *read_nh);
827 fdi->fd = *read_nh;
829 fdi->sock = GNUNET_NETWORK_get_fd (*read_nh);
830 t->read_fd = fdi->sock;
831 t->write_fd = -1;
832 }
833 else if (1 == write_nh_len)
834 {
835 GNUNET_assert (NULL != write_nh);
836 GNUNET_assert (NULL != *write_nh);
837 fdi->fd = *write_nh;
839 fdi->sock = GNUNET_NETWORK_get_fd (*write_nh);
840 t->read_fd = -1;
841 t->write_fd = fdi->sock;
842 }
843 else if (1 == read_fh_len)
844 {
845 GNUNET_assert (NULL != read_fh);
846 GNUNET_assert (NULL != *read_fh);
847 fdi->fh = *read_fh;
849 fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32
850 t->read_fd = fdi->sock;
851 t->write_fd = -1;
852 }
853 else
854 {
855 GNUNET_assert (NULL != write_fh);
856 GNUNET_assert (NULL != *write_fh);
857 fdi->fh = *write_fh;
859 fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32
860 t->read_fd = -1;
861 t->write_fd = fdi->sock;
862 }
863 }
864 else
865 {
867 t->fds = fdi;
868 t->read_fd = -1;
869 t->write_fd = -1;
870 for (int i = 0; i != read_nh_len; ++i)
871 {
872 fdi->fd = read_nh[i];
873 GNUNET_assert (NULL != fdi->fd);
875 fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]);
876 ++fdi;
877 }
878 for (int i = 0; i != write_nh_len; ++i)
879 {
880 fdi->fd = write_nh[i];
881 GNUNET_assert (NULL != fdi->fd);
883 fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]);
884 ++fdi;
885 }
886 for (int i = 0; i != read_fh_len; ++i)
887 {
888 fdi->fh = read_fh[i];
889 GNUNET_assert (NULL != fdi->fh);
891 fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32
892 ++fdi;
893 }
894 for (int i = 0; i != write_fh_len; ++i)
895 {
896 fdi->fh = write_fh[i];
897 GNUNET_assert (NULL != fdi->fh);
899 fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32
900 ++fdi;
901 }
902 }
903}
904
905
919static void
921{
922 struct GNUNET_SCHEDULER_FdInfo *fdi;
923 int success = GNUNET_YES;
924
925 for (unsigned int i = 0; i != t->fds_len; ++i)
926 {
927 fdi = &t->fds[i];
929 t,
930 fdi) && success;
932 }
933 if (GNUNET_YES != success)
934 {
936 "driver could not add task\n");
937 }
938}
939
940
941static void
948
949
950static void
952{
953 char c;
954 const struct GNUNET_DISK_FileHandle *pr;
955
956 (void) cls;
957 shutdown_pipe_task = NULL;
961 /* consume the signal */
962 GNUNET_DISK_file_read (pr, &c, sizeof(c));
963 /* mark all active tasks as ready due to shutdown */
967 pr,
969 NULL);
970}
971
972
985void *
987{
989 int is_fd_task;
990 void *ret;
991
993 "canceling task %p\n",
994 task);
995
996 /* scheduler must be running */
998 is_fd_task = (NULL != task->fds);
999 if (is_fd_task)
1000 {
1001 int del_result = scheduler_driver->del (scheduler_driver->cls, task);
1002 if (GNUNET_OK != del_result)
1003 {
1005 "driver could not delete task\n");
1006 GNUNET_assert (0);
1007 }
1008 }
1009 if (! task->in_ready_list)
1010 {
1011 if (is_fd_task)
1012 {
1015 task);
1016 }
1017 else if (GNUNET_YES == task->on_shutdown)
1018 {
1021 task);
1022 }
1023 else
1024 {
1027 task);
1028 if (pending_timeout_last == task)
1029 pending_timeout_last = NULL;
1030 }
1031 }
1032 else
1033 {
1034 p = check_priority (task->priority);
1036 ready_tail[p],
1037 task);
1038 ready_count--;
1039 }
1040 ret = task->callback_cls;
1041 destroy_task (task);
1042 return ret;
1043}
1044
1045
1051static void
1053{
1054#if EXECINFO
1055 void *backtrace_array[MAX_TRACE_DEPTH];
1056
1057 t->num_backtrace_strings
1058 = backtrace (backtrace_array, MAX_TRACE_DEPTH);
1059 t->backtrace_strings =
1060 backtrace_symbols (backtrace_array,
1061 t->num_backtrace_strings);
1062 dump_backtrace (t);
1063#else
1064 (void) t;
1065#endif
1066}
1067
1068
1079void
1081 task,
1082 void *task_cls,
1084 reason,
1086 priority)
1087{
1088 struct GNUNET_SCHEDULER_Task *t;
1089
1090 /* scheduler must be running */
1092 GNUNET_assert (NULL != task);
1094 t->read_fd = -1;
1095 t->write_fd = -1;
1096 t->callback = task;
1097 t->callback_cls = task_cls;
1098#if PROFILE_DELAYS
1099 t->start_time = GNUNET_TIME_absolute_get ();
1100#endif
1101 t->reason = reason;
1105 "Adding continuation task %p\n",
1106 t);
1107 init_backtrace (t);
1109}
1110
1111
1123struct GNUNET_SCHEDULER_Task *
1127 void *task_cls)
1128{
1129 struct GNUNET_SCHEDULER_Task *t;
1130 struct GNUNET_SCHEDULER_Task *pos;
1132 struct GNUNET_TIME_Relative left;
1133
1134 /* scheduler must be running */
1136 GNUNET_assert (NULL != task);
1139 t->callback = task;
1140 t->callback_cls = task_cls;
1141 t->read_fd = -1;
1142 t->write_fd = -1;
1143#if PROFILE_DELAYS
1144 t->start_time = GNUNET_TIME_absolute_get ();
1145#endif
1146 t->timeout = at;
1147 t->priority = check_priority (priority);
1149 init_backtrace (t);
1150
1152 if (0 == left.rel_value_us)
1153 {
1155 if (priority > work_priority)
1156 work_priority = priority;
1157 return t;
1158 }
1159
1160 /* try tail first (optimization in case we are
1161 * appending to a long list of tasks with timeouts) */
1162 if ((NULL == pending_timeout_head) ||
1164 {
1167 t);
1168 }
1169 else
1170 {
1171 /* first move from heuristic start backwards to before start time */
1172 prev = pending_timeout_last;
1173 while ((NULL != prev) &&
1175 prev = prev->prev;
1176 /* now, move from heuristic start (or head of list) forward to insertion point */
1177 if (NULL == prev)
1179 else
1180 pos = prev->next;
1181 while ((NULL != pos) && (pos->timeout.abs_value_us <=
1183 {
1184 prev = pos;
1185 pos = pos->next;
1186 }
1189 prev,
1190 t);
1191 }
1192 /* finally, update heuristic insertion point to last insertion... */
1195 "Adding task %p\n",
1196 t);
1197 return t;
1198}
1199
1200
1212struct GNUNET_SCHEDULER_Task *
1215 priority,
1217 void *task_cls)
1218{
1221 priority,
1222 task,
1223 task_cls);
1224}
1225
1226
1236struct GNUNET_SCHEDULER_Task *
1239 void *task_cls)
1240{
1242 prio,
1243 task,
1244 task_cls);
1245}
1246
1247
1259struct GNUNET_SCHEDULER_Task *
1262 void *task_cls)
1263{
1266 task,
1267 task_cls);
1268}
1269
1270
1282struct GNUNET_SCHEDULER_Task *
1285 void *task_cls)
1286{
1289 task,
1290 task_cls);
1291}
1292
1293
1309struct GNUNET_SCHEDULER_Task *
1311 void *task_cls)
1312{
1313 struct GNUNET_SCHEDULER_Task *t;
1314
1317 t->callback = task;
1318 t->callback_cls = task_cls;
1319 t->read_fd = -1;
1320 t->write_fd = -1;
1321#if PROFILE_DELAYS
1322 t->start_time = GNUNET_TIME_absolute_get ();
1323#endif
1329 init_backtrace (t);
1330 return t;
1331}
1332
1333
1344struct GNUNET_SCHEDULER_Task *
1346 void *task_cls)
1347{
1348 struct GNUNET_SCHEDULER_Task *t;
1349
1350 /* scheduler must be running */
1352 GNUNET_assert (NULL != task);
1355 t->callback = task;
1356 t->callback_cls = task_cls;
1357 t->read_fd = -1;
1358 t->write_fd = -1;
1359#if PROFILE_DELAYS
1360 t->start_time = GNUNET_TIME_absolute_get ();
1361#endif
1365 t->lifeness = GNUNET_NO;
1368 t);
1370 "Adding shutdown task %p\n",
1371 t);
1372 init_backtrace (t);
1373 return t;
1374}
1375
1376
1377struct GNUNET_SCHEDULER_Task *
1380 void *task_cls)
1381{
1382 struct GNUNET_SCHEDULER_Task *ret;
1383
1384 ret = GNUNET_SCHEDULER_add_now (task, task_cls);
1385 ret->lifeness = lifeness;
1386 return ret;
1387}
1388
1389
1390#if DEBUG_FDS
1397void
1398check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd)
1399{
1400 if (-1 != raw_fd)
1401 {
1402 int flags = fcntl (raw_fd, F_GETFD);
1403
1404 if ((flags == -1) && (errno == EBADF))
1405 {
1407 "Got invalid file descriptor %d!\n",
1408 raw_fd);
1409 init_backtrace (t);
1410 GNUNET_assert (0);
1411 }
1412 }
1413}
1414
1415
1416#endif
1417
1418
1444static struct GNUNET_SCHEDULER_Task *
1447 const struct GNUNET_NETWORK_Handle *read_nh,
1448 const struct GNUNET_NETWORK_Handle *write_nh,
1449 const struct GNUNET_DISK_FileHandle *read_fh,
1450 const struct GNUNET_DISK_FileHandle *write_fh,
1452 void *task_cls)
1453{
1454 struct GNUNET_SCHEDULER_Task *t;
1455
1456 /* scheduler must be running */
1458 GNUNET_assert (NULL != task);
1461 init_fd_info (t,
1462 &read_nh,
1463 read_nh ? 1 : 0,
1464 &write_nh,
1465 write_nh ? 1 : 0,
1466 &read_fh,
1467 read_fh ? 1 : 0,
1468 &write_fh,
1469 write_fh ? 1 : 0);
1470 t->callback = task;
1471 t->callback_cls = task_cls;
1472#if DEBUG_FDS
1473 check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1);
1474 check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1);
1475 check_fd (t, NULL != read_fh ? read_fh->fd : -1);
1476 check_fd (t, NULL != write_fh ? write_fh->fd : -1);
1477#endif
1478#if PROFILE_DELAYS
1479 t->start_time = GNUNET_TIME_absolute_get ();
1480#endif
1487 t);
1490 t->priority);
1491 init_backtrace (t);
1492 return t;
1493}
1494
1495
1516struct GNUNET_SCHEDULER_Task *
1518 struct GNUNET_NETWORK_Handle *rfd,
1520 void *task_cls)
1521{
1524 rfd, task, task_cls);
1525}
1526
1527
1550struct GNUNET_SCHEDULER_Task *
1553 priority,
1554 struct GNUNET_NETWORK_Handle *rfd,
1556 void *task_cls)
1557{
1559 rfd,
1560 GNUNET_YES,
1561 GNUNET_NO,
1562 task, task_cls);
1563}
1564
1565
1587struct GNUNET_SCHEDULER_Task *
1589 struct GNUNET_NETWORK_Handle *wfd,
1591 void *task_cls)
1592{
1595 wfd,
1597 task, task_cls);
1598}
1599
1600
1624struct GNUNET_SCHEDULER_Task *
1627 struct GNUNET_NETWORK_Handle *fd,
1628 int on_read,
1629 int on_write,
1631 void *task_cls)
1632{
1633 /* scheduler must be running */
1635 GNUNET_assert (on_read || on_write);
1637 return add_without_sets (delay, priority,
1638 on_read ? fd : NULL,
1639 on_write ? fd : NULL,
1640 NULL,
1641 NULL,
1642 task, task_cls);
1643}
1644
1645
1666struct GNUNET_SCHEDULER_Task *
1668 const struct GNUNET_DISK_FileHandle *rfd,
1670 void *task_cls)
1671{
1674 rfd, GNUNET_YES, GNUNET_NO,
1675 task, task_cls);
1676}
1677
1678
1699struct GNUNET_SCHEDULER_Task *
1701 const struct GNUNET_DISK_FileHandle *wfd,
1703 void *task_cls)
1704{
1707 wfd, GNUNET_NO, GNUNET_YES,
1708 task, task_cls);
1709}
1710
1711
1735struct GNUNET_SCHEDULER_Task *
1738 priority,
1739 const struct
1741 int on_read, int on_write,
1743 void *task_cls)
1744{
1745 /* scheduler must be running */
1747 GNUNET_assert (on_read || on_write);
1748 GNUNET_assert (fd->fd >= 0);
1749 return add_without_sets (delay, priority,
1750 NULL,
1751 NULL,
1752 on_read ? fd : NULL,
1753 on_write ? fd : NULL,
1754 task, task_cls);
1755}
1756
1757
1758static void
1760 const struct GNUNET_NETWORK_Handle ***ntarget,
1761 unsigned int *extracted_nhandles,
1762 const struct GNUNET_DISK_FileHandle ***ftarget,
1763 unsigned int *extracted_fhandles)
1764{
1765 // FIXME: this implementation only works for unix, for WIN32 the file handles
1766 // in fdset must be handled separately
1767 const struct GNUNET_NETWORK_Handle **nhandles;
1768 const struct GNUNET_DISK_FileHandle **fhandles;
1769 unsigned int nhandles_len;
1770 unsigned int fhandles_len;
1771
1772 nhandles = NULL;
1773 fhandles = NULL;
1774 nhandles_len = 0;
1775 fhandles_len = 0;
1776 for (int sock = 0; sock != fdset->nsds; ++sock)
1777 {
1778 if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock))
1779 {
1780 struct GNUNET_NETWORK_Handle *nhandle;
1781 struct GNUNET_DISK_FileHandle *fhandle;
1782
1783 nhandle = GNUNET_NETWORK_socket_box_native (sock);
1784 if (NULL != nhandle)
1785 {
1786 GNUNET_array_append (nhandles, nhandles_len, nhandle);
1787 }
1788 else
1789 {
1790 fhandle = GNUNET_DISK_get_handle_from_int_fd (sock);
1791 if (NULL != fhandle)
1792 {
1793 GNUNET_array_append (fhandles, fhandles_len, fhandle);
1794 }
1795 else
1796 {
1797 GNUNET_assert (0);
1798 }
1799 }
1800 }
1801 }
1802 *ntarget = nhandles_len > 0 ? nhandles : NULL;
1803 *ftarget = fhandles_len > 0 ? fhandles : NULL;
1804 *extracted_nhandles = nhandles_len;
1805 *extracted_fhandles = fhandles_len;
1806}
1807
1808
1840struct GNUNET_SCHEDULER_Task *
1842 struct GNUNET_TIME_Relative delay,
1843 const struct GNUNET_NETWORK_FDSet *rs,
1844 const struct GNUNET_NETWORK_FDSet *ws,
1846 void *task_cls)
1847{
1848 struct GNUNET_SCHEDULER_Task *t;
1849 const struct GNUNET_NETWORK_Handle **read_nhandles = NULL;
1850 const struct GNUNET_NETWORK_Handle **write_nhandles = NULL;
1851 const struct GNUNET_DISK_FileHandle **read_fhandles = NULL;
1852 const struct GNUNET_DISK_FileHandle **write_fhandles = NULL;
1853 unsigned int read_nhandles_len = 0;
1854 unsigned int write_nhandles_len = 0;
1855 unsigned int read_fhandles_len = 0;
1856 unsigned int write_fhandles_len = 0;
1857 int no_rs = (NULL == rs);
1858 int no_ws = (NULL == ws);
1859 int empty_rs = (NULL != rs) && (0 == rs->nsds);
1860 int empty_ws = (NULL != ws) && (0 == ws->nsds);
1861 int no_fds = (no_rs && no_ws) ||
1862 (empty_rs && empty_ws) ||
1863 (no_rs && empty_ws) ||
1864 (no_ws && empty_rs);
1865 int no_fds_extracted;
1866
1867 /* scheduler must be running */
1869 GNUNET_assert (NULL != task);
1870 if (! no_fds)
1871 {
1872 if (NULL != rs)
1873 {
1874 extract_handles (rs,
1875 &read_nhandles,
1876 &read_nhandles_len,
1877 &read_fhandles,
1878 &read_fhandles_len);
1879 }
1880 if (NULL != ws)
1881 {
1882 extract_handles (ws,
1883 &write_nhandles,
1884 &write_nhandles_len,
1885 &write_fhandles,
1886 &write_fhandles_len);
1887 }
1888 }
1896 no_fds_extracted = (0 == read_nhandles_len) &&
1897 (0 == read_fhandles_len) &&
1898 (0 == write_nhandles_len) &&
1899 (0 == write_fhandles_len);
1900 if (no_fds || no_fds_extracted)
1902 prio,
1903 task,
1904 task_cls);
1907 init_fd_info (t,
1908 read_nhandles,
1909 read_nhandles_len,
1910 write_nhandles,
1911 write_nhandles_len,
1912 read_fhandles,
1913 read_fhandles_len,
1914 write_fhandles,
1915 write_fhandles_len);
1916 t->callback = task;
1917 t->callback_cls = task_cls;
1919 /* free the arrays of pointers to network / file handles, the actual
1920 * handles will be freed in destroy_task */
1921 GNUNET_array_grow (read_nhandles, read_nhandles_len, 0);
1922 GNUNET_array_grow (write_nhandles, write_nhandles_len, 0);
1923 GNUNET_array_grow (read_fhandles, read_fhandles_len, 0);
1924 GNUNET_array_grow (write_fhandles, write_fhandles_len, 0);
1925#if PROFILE_DELAYS
1926 t->start_time = GNUNET_TIME_absolute_get ();
1927#endif
1929 t->priority =
1930 check_priority ((prio ==
1932 prio);
1936 t);
1939 t->priority);
1941 "Adding task %p\n",
1942 t);
1943 init_backtrace (t);
1944 return t;
1945}
1946
1947
1959void
1961 struct GNUNET_SCHEDULER_FdInfo *fdi)
1962{
1963 enum GNUNET_SCHEDULER_Reason reason;
1964
1965 reason = task->reason;
1966 if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1967 (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)))
1969 if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
1970 (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)))
1973 task->reason = reason;
1974 if (GNUNET_NO == task->in_ready_list)
1975 {
1978 task);
1979 queue_ready_task (task);
1980 }
1981}
1982
1983
2004int
2006{
2007 struct GNUNET_SCHEDULER_Task *pos;
2008 struct GNUNET_TIME_Absolute now;
2009
2010 /* check for tasks that reached the timeout! */
2011 now = GNUNET_TIME_absolute_get ();
2013 while (NULL != pos)
2014 {
2015 struct GNUNET_SCHEDULER_Task *next = pos->next;
2016 if (now.abs_value_us >= pos->timeout.abs_value_us)
2018 if (0 == pos->reason)
2019 break;
2022 pos);
2023 if (pending_timeout_last == pos)
2024 pending_timeout_last = NULL;
2025 queue_ready_task (pos);
2026 pos = next;
2027 }
2028 pos = pending_head;
2029 while (NULL != pos)
2030 {
2031 struct GNUNET_SCHEDULER_Task *next = pos->next;
2032 if (now.abs_value_us >= pos->timeout.abs_value_us)
2033 {
2037 pos);
2038 queue_ready_task (pos);
2039 }
2040 pos = next;
2041 }
2042
2043 if (0 == ready_count)
2044 {
2046
2047 if (timeout.abs_value_us > now.abs_value_us)
2048 {
2063 "GNUNET_SCHEDULER_do_work did not find any ready "
2064 "tasks and timeout has not been reached yet.\n");
2065 }
2066 else
2067 {
2072 GNUNET_assert (0);
2073 }
2074 }
2075 else
2076 {
2077 /* find out which task priority level we are going to
2078 process this time */
2081 /* yes, p>0 is correct, 0 is "KEEP" which should
2082 * always be an empty queue (see assertion)! */
2084 work_priority > 0;
2085 work_priority--)
2086 {
2088 if (NULL != pos)
2089 break;
2090 }
2091 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2092
2093 /* process all *existing* tasks at this priority
2094 level, then yield */
2096 while (NULL != (pos = ready_head[work_priority])
2097 && pos != &pass_end_marker)
2098 {
2101 pos);
2102 ready_count--;
2105 active_task = pos;
2106#if PROFILE_DELAYS
2107 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2108 DELAY_THRESHOLD.rel_value_us)
2109 {
2111 "Task %p took %s to be scheduled\n",
2112 pos,
2114 GNUNET_TIME_absolute_get_duration (pos->start_time),
2115 GNUNET_YES));
2116 }
2117#endif
2118 tc.reason = pos->reason;
2121 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2122 tc.fds_len = pos->fds_len;
2123 tc.fds = pos->fds;
2124 for (unsigned int i = 0; i != pos->fds_len; ++i)
2125 {
2126 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
2127 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
2128 {
2130 fdi->sock);
2131 }
2132 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
2133 {
2135 fdi->sock);
2136 }
2137 }
2138 tc.read_ready = sh->rs;
2139 tc.write_ready = sh->ws;
2140#if EXTRA_DEBUG
2142 "Running task %p\n",
2143 pos);
2144#endif
2145 GNUNET_assert (NULL != pos->callback);
2146 {
2147 struct GNUNET_AsyncScopeSave old_scope;
2148 if (pos->scope.have_scope)
2149 GNUNET_async_scope_enter (&pos->scope.scope_id, &old_scope);
2150 else
2151 GNUNET_async_scope_get (&old_scope);
2152 pos->callback (pos->callback_cls);
2153 GNUNET_async_scope_restore (&old_scope);
2154 }
2155 if (NULL != pos->fds)
2156 {
2157 int del_result = scheduler_driver->del (scheduler_driver->cls,
2158 pos);
2159 if (GNUNET_OK != del_result)
2160 {
2162 "driver could not delete task %p\n", pos);
2163 GNUNET_assert (0);
2164 }
2165 }
2166 active_task = NULL;
2167 dump_backtrace (pos);
2168 destroy_task (pos);
2169 }
2171 }
2173 if (0 == ready_count)
2174 {
2176 get_timeout ());
2177 return GNUNET_NO;
2178 }
2181 return GNUNET_YES;
2182}
2183
2184
2218{
2220 const struct GNUNET_DISK_FileHandle *pr;
2221
2222 /* scheduler must not be running */
2225 /* general set-up */
2231 my_pid = getpid ();
2232 scheduler_driver = driver;
2233
2234 /* install signal handlers */
2236 "Registering signal handlers\n");
2237 sh->shc_int = GNUNET_SIGNAL_handler_install (SIGINT,
2239 sh->shc_term = GNUNET_SIGNAL_handler_install (SIGTERM,
2241#if (SIGTERM != GNUNET_TERM_SIG)
2244#endif
2245 sh->shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE,
2247 sh->shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT,
2249 sh->shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP,
2251
2252 /* Setup initial tasks */
2255 /* ensure this task runs first, by using a priority level reserved for
2256 the scheduler (not really shutdown, but start-up ;-) */
2260 NULL);
2263 pr,
2265 NULL);
2268 get_timeout ());
2269 /* begin main event loop */
2273 return sh;
2274}
2275
2276
2291void
2293{
2294 GNUNET_break (NULL == pending_head);
2296 GNUNET_break (NULL == shutdown_head);
2297 for (int i = 0; i != GNUNET_SCHEDULER_PRIORITY_COUNT; ++i)
2298 {
2299 GNUNET_break (NULL == ready_head[i]);
2300 }
2303
2304 /* uninstall signal handlers */
2307#if (SIGTERM != GNUNET_TERM_SIG)
2309#endif
2314 shutdown_pipe_handle = NULL;
2315 scheduler_driver = NULL;
2316 GNUNET_free (sh);
2317}
2318
2319
2320static enum GNUNET_GenericReturnValue
2322 struct DriverContext *context)
2323{
2324 struct GNUNET_NETWORK_FDSet *rs;
2325 struct GNUNET_NETWORK_FDSet *ws;
2326 int select_result;
2327
2328 GNUNET_assert (NULL != context);
2331 while ((NULL != context->scheduled_head) ||
2332 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
2333 context->timeout.abs_value_us))
2334 {
2335 struct GNUNET_TIME_Relative time_remaining;
2336
2337#if EXTRA_DEBUG
2339 "select timeout = %s\n",
2341#endif
2344
2345 for (struct Scheduled *pos = context->scheduled_head;
2346 NULL != pos;
2347 pos = pos->next)
2348 {
2349 if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et))
2350 {
2351 GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock);
2352 }
2353 if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et))
2354 {
2355 GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock);
2356 }
2357 }
2358 time_remaining = GNUNET_TIME_absolute_get_remaining (context->timeout);
2359 if (0 < ready_count)
2360 time_remaining = GNUNET_TIME_UNIT_ZERO;
2361 if (NULL == scheduler_select)
2362 {
2363 select_result = GNUNET_NETWORK_socket_select (rs,
2364 ws,
2365 NULL,
2366 time_remaining);
2367 }
2368 else
2369 {
2370 select_result = scheduler_select (scheduler_select_cls,
2371 rs,
2372 ws,
2373 NULL,
2374 time_remaining);
2375 }
2376 if (select_result == GNUNET_SYSERR)
2377 {
2378 if (errno == EINTR)
2379 continue;
2380
2382 "select");
2383#if USE_LSOF
2384 char lsof[512];
2385
2386 snprintf (lsof,
2387 sizeof(lsof),
2388 "lsof -p %d",
2389 getpid ());
2390 (void) close (1);
2391 (void) dup2 (2, 1);
2392 if (0 != system (lsof))
2394 "system");
2395#endif
2396#if DEBUG_FDS
2397 for (struct Scheduled *s = context->scheduled_head;
2398 NULL != s;
2399 s = s->next)
2400 {
2401 int flags = fcntl (s->fdi->sock,
2402 F_GETFD);
2403
2404 if ((flags == -1) &&
2405 (EBADF == errno))
2406 {
2408 "Got invalid file descriptor %d!\n",
2409 s->fdi->sock);
2410#if EXECINFO
2411 dump_backtrace (s->task);
2412#endif
2413 }
2414 }
2415#endif
2416 GNUNET_assert (0);
2419 return GNUNET_SYSERR;
2420 }
2421 if (select_result > 0)
2422 {
2423 for (struct Scheduled *pos = context->scheduled_head;
2424 NULL != pos;
2425 pos = pos->next)
2426 {
2427 int is_ready = GNUNET_NO;
2428
2429 if ((0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) &&
2430 (GNUNET_YES ==
2432 pos->fdi->sock)) )
2433 {
2434 pos->fdi->et |= GNUNET_SCHEDULER_ET_IN;
2435 is_ready = GNUNET_YES;
2436 }
2437 if ((0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) &&
2438 (GNUNET_YES ==
2440 pos->fdi->sock)) )
2441 {
2442 pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT;
2443 is_ready = GNUNET_YES;
2444 }
2445 if (GNUNET_YES == is_ready)
2446 {
2447 GNUNET_SCHEDULER_task_ready (pos->task,
2448 pos->fdi);
2449 }
2450 }
2451 }
2453 {
2454#if EXTRA_DEBUG
2456 "scheduler has more tasks ready!\n");
2457#endif
2458 }
2459 }
2462
2463 if ( (NULL == context->scheduled_head) &&
2464 (NULL != pending_timeout_head) &&
2465 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us ==
2466 context->timeout.abs_value_us) )
2467 {
2468 /* Only remaining task has timeout of 'forever'.
2469 We exit here more as sanity measure, as just
2470 waiting forever isn't exactly useful. Still,
2471 this is indicative of a bug in the client code. */
2472 GNUNET_break (0);
2473 return GNUNET_NO;
2474 }
2475 return GNUNET_OK;
2476}
2477
2478
2479static int
2480select_add (void *cls,
2481 struct GNUNET_SCHEDULER_Task *task,
2482 struct GNUNET_SCHEDULER_FdInfo *fdi)
2483{
2484 struct DriverContext *context = cls;
2485 struct Scheduled *scheduled;
2486
2487 GNUNET_assert (NULL != context);
2488 GNUNET_assert (NULL != task);
2489 GNUNET_assert (NULL != fdi);
2491 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et));
2492
2493 if (! ((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0))
2494 {
2495 /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */
2496 return GNUNET_SYSERR;
2497 }
2498
2499 scheduled = GNUNET_new (struct Scheduled);
2500 scheduled->task = task;
2501 scheduled->fdi = fdi;
2502 scheduled->et = fdi->et;
2503
2504 GNUNET_CONTAINER_DLL_insert (context->scheduled_head,
2505 context->scheduled_tail,
2506 scheduled);
2507 return GNUNET_OK;
2508}
2509
2510
2511static int
2512select_del (void *cls,
2514{
2515 struct DriverContext *context;
2516 struct Scheduled *pos;
2517 int ret;
2518
2519 GNUNET_assert (NULL != cls);
2520
2521 context = cls;
2523 pos = context->scheduled_head;
2524 while (NULL != pos)
2525 {
2526 struct Scheduled *next = pos->next;
2527 if (pos->task == task)
2528 {
2529 GNUNET_CONTAINER_DLL_remove (context->scheduled_head,
2530 context->scheduled_tail,
2531 pos);
2532 GNUNET_free (pos);
2533 ret = GNUNET_OK;
2534 }
2535 pos = next;
2536 }
2537 return ret;
2538}
2539
2540
2541static void
2543 struct GNUNET_TIME_Absolute dt)
2544{
2545 struct DriverContext *context = cls;
2546
2547 GNUNET_assert (NULL != context);
2548 context->timeout = dt;
2549}
2550
2551
2559{
2560 struct GNUNET_SCHEDULER_Driver *select_driver;
2561
2562 select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver);
2563
2564 select_driver->add = &select_add;
2565 select_driver->del = &select_del;
2566 select_driver->set_wakeup = &select_set_wakeup;
2567
2568 return select_driver;
2569}
2570
2571
2584void
2586{
2587 struct GNUNET_AsyncScopeSave dummy_old_scope;
2588
2589 GNUNET_assert (NULL != active_task);
2590 /* Since we're in a task, the context will be automatically
2591 restored by the scheduler. */
2592 GNUNET_async_scope_enter (aid, &dummy_old_scope);
2593}
2594
2595
2596/* 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_SCHEDULER_Task * t
Main task.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition gnunet-uri.c:38
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:1702
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:745
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition disk.c:1523
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1670
enum GNUNET_GenericReturnValue GNUNET_DISK_handle_invalid(const struct GNUNET_DISK_FileHandle *h)
Checks whether a handle is invalid.
Definition disk.c:199
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition disk.c:1409
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:704
@ 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...
void GNUNET_SCHEDULER_shutdown()
Request the shutdown of a scheduler.
Definition scheduler.c:572
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:1517
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:1378
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition scheduler.c:731
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:1700
void GNUNET_SCHEDULER_driver_done(struct GNUNET_SCHEDULER_Handle *sh)
Counter-part of GNUNET_SCHEDULER_driver_init.
Definition scheduler.c:2292
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:1551
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:1960
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:1080
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:1667
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:2005
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:1588
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:1841
unsigned int GNUNET_SCHEDULER_get_load(enum GNUNET_SCHEDULER_Priority p)
Get information about the current load of this scheduler.
Definition scheduler.c:781
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:764
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:1736
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:1260
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:1345
struct GNUNET_SCHEDULER_Driver * GNUNET_SCHEDULER_driver_select()
Obtain the driver for using select() as the event loop.
Definition scheduler.c:2558
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:2585
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
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:452
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:1310
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:1625
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:1283
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:1213
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:1124
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:2217
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:1237
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:604
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:665
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
#define GNUNET_TERM_SIG
The termination signal.
Definition platform.h:235
static void sighandler_pipe()
Signal handler called for SIGPIPE.
Definition scheduler.c:678
static void dump_backtrace(struct GNUNET_SCHEDULER_Task *t)
Output stack trace of task t.
Definition scheduler.c:605
static void driver_add_multiple(struct GNUNET_SCHEDULER_Task *t)
calls the given function func on each FdInfo related to t.
Definition scheduler.c:920
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:398
static void select_set_wakeup(void *cls, struct GNUNET_TIME_Absolute dt)
Definition scheduler.c:2542
static void destroy_task(struct GNUNET_SCHEDULER_Task *t)
Destroy a task (release associated resources)
Definition scheduler.c:626
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:467
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:551
static int select_del(void *cls, struct GNUNET_SCHEDULER_Task *task)
Definition scheduler.c:2512
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:392
static struct GNUNET_SCHEDULER_Task * active_task
ID of the task that is running right now.
Definition scheduler.c:373
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:384
static enum GNUNET_SCHEDULER_Priority current_priority
Priority of the task running right now.
Definition scheduler.c:409
static struct GNUNET_SCHEDULER_Task * pending_head
Head of list of tasks waiting for an event.
Definition scheduler.c:329
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:482
static void remove_pass_end_marker()
Definition scheduler.c:520
#define DELAY_THRESHOLD
Task that were in the queue for longer than this are reported if PROFILE_DELAYS is active.
Definition scheduler.c:79
static unsigned int ready_count
Number of tasks on the ready list.
Definition scheduler.c:403
static struct GNUNET_DISK_PipeHandle * shutdown_pipe_handle
Pipe used to communicate shutdown via signal.
Definition scheduler.c:666
static const struct GNUNET_SCHEDULER_Driver * scheduler_driver
The driver used for the event loop.
Definition scheduler.c:324
static struct GNUNET_SCHEDULER_Task * pending_timeout_head
List of tasks waiting ONLY for a timeout event.
Definition scheduler.c:353
static void install_parent_control_handler(void *cls)
Definition scheduler.c:942
static int select_add(void *cls, struct GNUNET_SCHEDULER_Task *task, struct GNUNET_SCHEDULER_FdInfo *fdi)
Definition scheduler.c:2480
static GNUNET_SCHEDULER_select scheduler_select
Function to use as a select() in the scheduler.
Definition scheduler.c:431
static enum GNUNET_SCHEDULER_Priority work_priority
Priority used currently in GNUNET_SCHEDULER_do_work().
Definition scheduler.c:425
static void shutdown_if_no_lifeness(void)
Definition scheduler.c:705
static void * scheduler_select_cls
Closure for scheduler_select.
Definition scheduler.c:441
static struct GNUNET_SCHEDULER_Task * pending_timeout_tail
List of tasks waiting ONLY for a timeout event.
Definition scheduler.c:362
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:378
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:261
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:1445
static int current_lifeness
Value of the 'lifeness' flag for the current task.
Definition scheduler.c:420
static void set_work_priority(enum GNUNET_SCHEDULER_Priority p)
Definition scheduler.c:533
static void init_backtrace(struct GNUNET_SCHEDULER_Task *t)
Initialize backtrace data for task t.
Definition scheduler.c:1052
static enum GNUNET_SCHEDULER_Priority max_priority_added
Priority of the highest task added in the current select iteration.
Definition scheduler.c:415
static struct GNUNET_SCHEDULER_Task * pending_timeout_last
Last inserted task waiting ONLY for a timeout event.
Definition scheduler.c:368
static void sighandler_shutdown(void)
Signal handler called for signals that should cause us to shutdown.
Definition scheduler.c:688
#define LOG(kind,...)
Definition scheduler.c:37
static void shutdown_pipe_cb(void *cls)
Definition scheduler.c:951
#define LOG_STRERROR(kind, syscall)
Definition scheduler.c:39
static enum GNUNET_GenericReturnValue select_loop(struct GNUNET_SCHEDULER_Handle *sh, struct DriverContext *context)
Definition scheduler.c:2321
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:803
static struct GNUNET_SCHEDULER_Task * pending_tail
Tail of list of tasks waiting for an event.
Definition scheduler.c:334
static struct GNUNET_SCHEDULER_Task * shutdown_tail
Tail of list of tasks waiting for shutdown.
Definition scheduler.c:344
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition scheduler.c:436
static struct GNUNET_SCHEDULER_Task * shutdown_head
Head of list of tasks waiting for shutdown.
Definition scheduler.c:339
static pid_t my_pid
Process ID of this process at the time we installed the various signal handlers.
Definition scheduler.c:672
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:1759
Driver context used by GNUNET_SCHEDULER_run.
Definition scheduler.c:296
struct Scheduled * scheduled_head
the head of a DLL containing information about the events the select driver is waiting for
Definition scheduler.c:301
struct GNUNET_TIME_Absolute timeout
the time when the select driver will wake up again (after calling select)
Definition scheduler.c:313
struct Scheduled * scheduled_tail
the tail of a DLL containing information about the events the select driver is waiting for
Definition scheduler.c:307
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:88
struct GNUNET_NETWORK_FDSet * rs
Passed here to avoid constantly allocating/deallocating this element, but generally we want to get ri...
Definition scheduler.c:94
struct GNUNET_SIGNAL_Context * shc_quit
context of the SIGQUIT handler
Definition scheduler.c:123
struct GNUNET_SIGNAL_Context * shc_hup
context of the SIGHUP handler
Definition scheduler.c:128
struct GNUNET_SIGNAL_Context * shc_int
context of the SIGINT handler
Definition scheduler.c:106
struct GNUNET_SIGNAL_Context * shc_pipe
context of the SIGPIPE handler
Definition scheduler.c:133
struct GNUNET_NETWORK_FDSet * ws
Passed here to avoid constantly allocating/deallocating this element, but generally we want to get ri...
Definition scheduler.c:101
struct GNUNET_SIGNAL_Context * shc_term
context of the SIGTERM handler
Definition scheduler.c:111
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:141
enum GNUNET_SCHEDULER_Priority priority
Task priority.
Definition scheduler.c:209
struct GNUNET_SCHEDULER_Task * prev
This is a linked list.
Definition scheduler.c:150
void * callback_cls
Closure for the callback.
Definition scheduler.c:160
int in_ready_list
Is this task in the ready list?
Definition scheduler.c:235
int lifeness
Should the existence of this task in the queue be counted as reason to not shutdown the scheduler?
Definition scheduler.c:225
enum GNUNET_SCHEDULER_Reason reason
Why is the task ready? Set after task is added to ready queue.
Definition scheduler.c:204
int own_handles
Do we own the network and file handles referenced by the FdInfo structs in the fds array.
Definition scheduler.c:184
struct GNUNET_AsyncScopeSave scope
Asynchronous scope of the task that scheduled this scope,.
Definition scheduler.c:253
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition scheduler.c:145
int on_shutdown
Is this task run on shutdown?
Definition scheduler.c:230
struct GNUNET_SCHEDULER_FdInfo * fds
Information about which FDs are ready for this task (and why).
Definition scheduler.c:165
unsigned int fds_len
Size of the fds array.
Definition scheduler.c:177
struct GNUNET_TIME_Absolute timeout
Absolute timeout value for the task, or GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
Definition scheduler.c:190
GNUNET_SCHEDULER_TaskCallback callback
Function to run when ready.
Definition scheduler.c:155
int write_fd
Set if we only wait for writing to a single FD, otherwise -1.
Definition scheduler.c:219
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:172
int read_fd
Set if we only wait for reading from a single FD, otherwise -1.
Definition scheduler.c:214
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:268
struct Scheduled * next
Definition scheduler.c:271
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:288
struct Scheduled * prev
Definition scheduler.c:269
struct GNUNET_SCHEDULER_FdInfo * fdi
information about the network socket / file descriptor where the event is expected to occur
Definition scheduler.c:282
struct GNUNET_SCHEDULER_Task * task
the task, the event is related to
Definition scheduler.c:276