GNUnet 0.22.0
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 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28// DEBUG
29#include <inttypes.h>
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__)
32
33#define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
34 "util-scheduler", \
35 syscall)
36
37
38#if HAVE_EXECINFO_H
39#include "execinfo.h"
40
45#define USE_LSOF GNUNET_NO
46
50#define EXECINFO GNUNET_NO
51
55#define DEBUG_FDS GNUNET_NO
56
60#define MAX_TRACE_DEPTH 50
61#endif
62
67#define PROFILE_DELAYS GNUNET_NO
68
73#define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS
74
75
82{
89
96
101
106
107#if (SIGTERM != GNUNET_TERM_SIG)
111 struct GNUNET_SIGNAL_Context *shc_gterm;
112#endif
113
118
123
128};
129
130
135{
140
145
150
155
160
167
171 unsigned int fds_len;
172
179
185
186#if PROFILE_DELAYS
191#endif
192
199
204
209
214
220
225
230
231#if EXECINFO
236 char **backtrace_strings;
237
241 int num_backtrace_strings;
242#endif
243
248};
249
256
257
262{
264
266
271
277
283};
284
285
290{
296
302
308};
309
310
319
324
329
334
339
348
357
363
368
372static struct
374
378static struct
380
387
393
397static unsigned int ready_count;
398
404
410
415
420
426
431
436
437
445void
447 void *new_select_cls)
448{
449 scheduler_select = new_select;
450 scheduler_select_cls = new_select_cls;
451}
452
453
462{
463 if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
464 return p;
465 GNUNET_assert (0);
466 return 0; /* make compiler happy */
467}
468
469
475static struct GNUNET_TIME_Absolute
477{
478 struct GNUNET_SCHEDULER_Task *pos;
479 struct GNUNET_TIME_Absolute now;
481
485 if (NULL != pos)
486 {
487 if (0 != pos->reason)
488 {
489 return now;
490 }
491 else
492 {
493 timeout = pos->timeout;
494 }
495 }
496 for (pos = pending_head; NULL != pos; pos = pos->next)
497 {
498 if (0 != pos->reason)
499 {
500 return now;
501 }
502 else if ((pos->timeout.abs_value_us !=
503 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) &&
504 (timeout.abs_value_us > pos->timeout.abs_value_us))
505 {
506 timeout = pos->timeout;
507 }
508 }
509 return timeout;
510}
511
512
513static void
515{
517 {
522 }
523}
524
525
526static void
528{
531 ready_tail[p],
536}
537
538
544static void
546{
548
550 ready_tail[p],
551 task);
552 if (p > work_priority)
555 ready_count++;
556}
557
558
565void
567{
568 struct GNUNET_SCHEDULER_Task *pos;
569
571 "GNUNET_SCHEDULER_shutdown\n");
572 if (NULL != install_parent_control_task)
573 {
576 }
577 if (NULL != shutdown_pipe_task)
578 {
580 shutdown_pipe_task = NULL;
581 }
582 while (NULL != (pos = shutdown_head))
583 {
586 pos);
588 queue_ready_task (pos);
589 }
590}
591
592
598static void
600{
601#if EXECINFO
602 for (unsigned int i = 0; i < t->num_backtrace_strings; i++)
604 "Task %p trace %u: %s\n",
605 t,
606 i,
607 t->backtrace_strings[i]);
608#else
609 (void) t;
610#endif
611}
612
613
619static void
621{
623 "destroying task %p\n",
624 t);
625
626 if (GNUNET_YES == t->own_handles)
627 {
628 for (unsigned int i = 0; i != t->fds_len; ++i)
629 {
630 const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd;
631 const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh;
632 if (fd)
633 {
635 (struct GNUNET_NETWORK_Handle *) fd);
636 }
637 if (fh)
638 {
639 // FIXME: on WIN32 this is not enough! A function
640 // GNUNET_DISK_file_free_memory_only would be nice
641 GNUNET_free_nz ((void *) fh);
642 }
643 }
644 }
645 if (t->fds_len > 1)
646 {
648 }
649#if EXECINFO
650 GNUNET_free (t->backtrace_strings);
651#endif
652 GNUNET_free (t);
653}
654
655
660
665static pid_t my_pid;
666
670static void
672{
673 return;
674}
675
676
680static void
682{
683 static char c;
684 int old_errno = errno; /* backup errno */
685
686 if (getpid () != my_pid)
687 _exit (1); /* we have fork'ed since the signal handler was created,
688 * ignore the signal, see https://gnunet.org/vfork discussion */
692 &c, sizeof(c));
693 errno = old_errno;
694}
695
696
697static void
699{
700 struct GNUNET_SCHEDULER_Task *t;
701
702 if (ready_count > 0)
703 return;
704 for (t = pending_head; NULL != t; t = t->next)
705 if (GNUNET_YES == t->lifeness)
706 return;
707 for (t = shutdown_head; NULL != t; t = t->next)
708 if (GNUNET_YES == t->lifeness)
709 return;
710 for (t = pending_timeout_head; NULL != t; t = t->next)
711 if (GNUNET_YES == t->lifeness)
712 return;
713 /* No lifeness! */
715}
716
717
720 struct DriverContext *context);
721
722
723void
725 void *task_cls)
726{
728 struct GNUNET_SCHEDULER_Driver *driver;
729 struct DriverContext context = {
730 .scheduled_head = NULL,
731 .scheduled_tail = NULL,
732 .timeout = GNUNET_TIME_absolute_get ()
733 };
734
736 driver->cls = &context;
739 task_cls,
744 &context));
746 GNUNET_free (driver);
747}
748
749
756const struct GNUNET_SCHEDULER_TaskContext *
758{
759 GNUNET_assert (NULL != active_task);
760 return &tc;
761}
762
763
773unsigned int
775{
776 unsigned int ret;
777
778 GNUNET_assert (NULL != active_task);
780 return ready_count;
783 ret = 0;
784 for (struct GNUNET_SCHEDULER_Task *pos = ready_head[check_priority (p)];
785 NULL != pos;
786 pos = pos->next)
787 ret++;
789 // Don't count the dummy marker
790 ret--;
791 return ret;
792}
793
794
795static void
797 const struct GNUNET_NETWORK_Handle *const *read_nh,
798 unsigned int read_nh_len,
799 const struct GNUNET_NETWORK_Handle *const *write_nh,
800 unsigned int write_nh_len,
801 const struct GNUNET_DISK_FileHandle *const *read_fh,
802 unsigned int read_fh_len,
803 const struct GNUNET_DISK_FileHandle *const *write_fh,
804 unsigned int write_fh_len)
805{
806 // FIXME: if we have exactly two network handles / exactly two file handles
807 // and they are equal, we can make one FdInfo with both
808 // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set.
809 struct GNUNET_SCHEDULER_FdInfo *fdi;
810
811 t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len;
812 if (1 == t->fds_len)
813 {
814 fdi = &t->fdx;
815 t->fds = fdi;
816 if (1 == read_nh_len)
817 {
818 GNUNET_assert (NULL != read_nh);
819 GNUNET_assert (NULL != *read_nh);
820 fdi->fd = *read_nh;
822 fdi->sock = GNUNET_NETWORK_get_fd (*read_nh);
823 t->read_fd = fdi->sock;
824 t->write_fd = -1;
825 }
826 else if (1 == write_nh_len)
827 {
828 GNUNET_assert (NULL != write_nh);
829 GNUNET_assert (NULL != *write_nh);
830 fdi->fd = *write_nh;
832 fdi->sock = GNUNET_NETWORK_get_fd (*write_nh);
833 t->read_fd = -1;
834 t->write_fd = fdi->sock;
835 }
836 else if (1 == read_fh_len)
837 {
838 GNUNET_assert (NULL != read_fh);
839 GNUNET_assert (NULL != *read_fh);
840 fdi->fh = *read_fh;
842 fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32
843 t->read_fd = fdi->sock;
844 t->write_fd = -1;
845 }
846 else
847 {
848 GNUNET_assert (NULL != write_fh);
849 GNUNET_assert (NULL != *write_fh);
850 fdi->fh = *write_fh;
852 fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32
853 t->read_fd = -1;
854 t->write_fd = fdi->sock;
855 }
856 }
857 else
858 {
860 t->fds = fdi;
861 t->read_fd = -1;
862 t->write_fd = -1;
863 for (int i = 0; i != read_nh_len; ++i)
864 {
865 fdi->fd = read_nh[i];
866 GNUNET_assert (NULL != fdi->fd);
868 fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]);
869 ++fdi;
870 }
871 for (int i = 0; i != write_nh_len; ++i)
872 {
873 fdi->fd = write_nh[i];
874 GNUNET_assert (NULL != fdi->fd);
876 fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]);
877 ++fdi;
878 }
879 for (int i = 0; i != read_fh_len; ++i)
880 {
881 fdi->fh = read_fh[i];
882 GNUNET_assert (NULL != fdi->fh);
884 fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32
885 ++fdi;
886 }
887 for (int i = 0; i != write_fh_len; ++i)
888 {
889 fdi->fh = write_fh[i];
890 GNUNET_assert (NULL != fdi->fh);
892 fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32
893 ++fdi;
894 }
895 }
896}
897
898
912static void
914{
915 struct GNUNET_SCHEDULER_FdInfo *fdi;
916 int success = GNUNET_YES;
917
918 for (unsigned int i = 0; i != t->fds_len; ++i)
919 {
920 fdi = &t->fds[i];
922 t,
923 fdi) && success;
925 }
926 if (GNUNET_YES != success)
927 {
929 "driver could not add task\n");
930 }
931}
932
933
934static void
936{
937 (void) cls;
940}
941
942
943static void
945{
946 char c;
947 const struct GNUNET_DISK_FileHandle *pr;
948
949 (void) cls;
950 shutdown_pipe_task = NULL;
954 /* consume the signal */
955 GNUNET_DISK_file_read (pr, &c, sizeof(c));
956 /* mark all active tasks as ready due to shutdown */
960 pr,
962 NULL);
963}
964
965
978void *
980{
982 int is_fd_task;
983 void *ret;
984
986 "canceling task %p\n",
987 task);
988
989 /* scheduler must be running */
991 is_fd_task = (NULL != task->fds);
992 if (is_fd_task)
993 {
994 int del_result = scheduler_driver->del (scheduler_driver->cls, task);
995 if (GNUNET_OK != del_result)
996 {
998 "driver could not delete task\n");
999 GNUNET_assert (0);
1000 }
1001 }
1002 if (! task->in_ready_list)
1003 {
1004 if (is_fd_task)
1005 {
1008 task);
1009 }
1010 else if (GNUNET_YES == task->on_shutdown)
1011 {
1014 task);
1015 }
1016 else
1017 {
1020 task);
1021 if (pending_timeout_last == task)
1022 pending_timeout_last = NULL;
1023 }
1024 }
1025 else
1026 {
1027 p = check_priority (task->priority);
1029 ready_tail[p],
1030 task);
1031 ready_count--;
1032 }
1033 ret = task->callback_cls;
1034 destroy_task (task);
1035 return ret;
1036}
1037
1038
1044static void
1046{
1047#if EXECINFO
1048 void *backtrace_array[MAX_TRACE_DEPTH];
1049
1050 t->num_backtrace_strings
1051 = backtrace (backtrace_array, MAX_TRACE_DEPTH);
1052 t->backtrace_strings =
1053 backtrace_symbols (backtrace_array,
1054 t->num_backtrace_strings);
1055 dump_backtrace (t);
1056#else
1057 (void) t;
1058#endif
1059}
1060
1061
1072void
1074 task,
1075 void *task_cls,
1077 reason,
1079 priority)
1080{
1081 struct GNUNET_SCHEDULER_Task *t;
1082
1083 /* scheduler must be running */
1085 GNUNET_assert (NULL != task);
1087 t->read_fd = -1;
1088 t->write_fd = -1;
1089 t->callback = task;
1090 t->callback_cls = task_cls;
1091#if PROFILE_DELAYS
1092 t->start_time = GNUNET_TIME_absolute_get ();
1093#endif
1094 t->reason = reason;
1098 "Adding continuation task %p\n",
1099 t);
1100 init_backtrace (t);
1102}
1103
1104
1116struct GNUNET_SCHEDULER_Task *
1120 void *task_cls)
1121{
1122 struct GNUNET_SCHEDULER_Task *t;
1123 struct GNUNET_SCHEDULER_Task *pos;
1125 struct GNUNET_TIME_Relative left;
1126
1127 /* scheduler must be running */
1129 GNUNET_assert (NULL != task);
1132 t->callback = task;
1133 t->callback_cls = task_cls;
1134 t->read_fd = -1;
1135 t->write_fd = -1;
1136#if PROFILE_DELAYS
1137 t->start_time = GNUNET_TIME_absolute_get ();
1138#endif
1139 t->timeout = at;
1140 t->priority = check_priority (priority);
1142 init_backtrace (t);
1143
1145 if (0 == left.rel_value_us)
1146 {
1148 if (priority > work_priority)
1149 work_priority = priority;
1150 return t;
1151 }
1152
1153 /* try tail first (optimization in case we are
1154 * appending to a long list of tasks with timeouts) */
1155 if ((NULL == pending_timeout_head) ||
1157 {
1160 t);
1161 }
1162 else
1163 {
1164 /* first move from heuristic start backwards to before start time */
1165 prev = pending_timeout_last;
1166 while ((NULL != prev) &&
1168 prev = prev->prev;
1169 /* now, move from heuristic start (or head of list) forward to insertion point */
1170 if (NULL == prev)
1172 else
1173 pos = prev->next;
1174 while ((NULL != pos) && (pos->timeout.abs_value_us <=
1176 {
1177 prev = pos;
1178 pos = pos->next;
1179 }
1182 prev,
1183 t);
1184 }
1185 /* finally, update heuristic insertion point to last insertion... */
1188 "Adding task %p\n",
1189 t);
1190 return t;
1191}
1192
1193
1205struct GNUNET_SCHEDULER_Task *
1208 priority,
1210 void *task_cls)
1211{
1214 priority,
1215 task,
1216 task_cls);
1217}
1218
1219
1229struct GNUNET_SCHEDULER_Task *
1232 void *task_cls)
1233{
1235 prio,
1236 task,
1237 task_cls);
1238}
1239
1240
1252struct GNUNET_SCHEDULER_Task *
1255 void *task_cls)
1256{
1259 task,
1260 task_cls);
1261}
1262
1263
1275struct GNUNET_SCHEDULER_Task *
1278 void *task_cls)
1279{
1282 task,
1283 task_cls);
1284}
1285
1286
1302struct GNUNET_SCHEDULER_Task *
1304 void *task_cls)
1305{
1306 struct GNUNET_SCHEDULER_Task *t;
1307
1310 t->callback = task;
1311 t->callback_cls = task_cls;
1312 t->read_fd = -1;
1313 t->write_fd = -1;
1314#if PROFILE_DELAYS
1315 t->start_time = GNUNET_TIME_absolute_get ();
1316#endif
1322 init_backtrace (t);
1323 return t;
1324}
1325
1326
1337struct GNUNET_SCHEDULER_Task *
1339 void *task_cls)
1340{
1341 struct GNUNET_SCHEDULER_Task *t;
1342
1343 /* scheduler must be running */
1345 GNUNET_assert (NULL != task);
1348 t->callback = task;
1349 t->callback_cls = task_cls;
1350 t->read_fd = -1;
1351 t->write_fd = -1;
1352#if PROFILE_DELAYS
1353 t->start_time = GNUNET_TIME_absolute_get ();
1354#endif
1358 t->lifeness = GNUNET_NO;
1361 t);
1363 "Adding shutdown task %p\n",
1364 t);
1365 init_backtrace (t);
1366 return t;
1367}
1368
1369
1370struct GNUNET_SCHEDULER_Task *
1373 void *task_cls)
1374{
1375 struct GNUNET_SCHEDULER_Task *ret;
1376
1377 ret = GNUNET_SCHEDULER_add_now (task, task_cls);
1378 ret->lifeness = lifeness;
1379 return ret;
1380}
1381
1382
1383#if DEBUG_FDS
1390void
1391check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd)
1392{
1393 if (-1 != raw_fd)
1394 {
1395 int flags = fcntl (raw_fd, F_GETFD);
1396
1397 if ((flags == -1) && (errno == EBADF))
1398 {
1400 "Got invalid file descriptor %d!\n",
1401 raw_fd);
1402 init_backtrace (t);
1403 GNUNET_assert (0);
1404 }
1405 }
1406}
1407
1408
1409#endif
1410
1411
1437static struct GNUNET_SCHEDULER_Task *
1440 const struct GNUNET_NETWORK_Handle *read_nh,
1441 const struct GNUNET_NETWORK_Handle *write_nh,
1442 const struct GNUNET_DISK_FileHandle *read_fh,
1443 const struct GNUNET_DISK_FileHandle *write_fh,
1445 void *task_cls)
1446{
1447 struct GNUNET_SCHEDULER_Task *t;
1448
1449 /* scheduler must be running */
1451 GNUNET_assert (NULL != task);
1454 init_fd_info (t,
1455 &read_nh,
1456 read_nh ? 1 : 0,
1457 &write_nh,
1458 write_nh ? 1 : 0,
1459 &read_fh,
1460 read_fh ? 1 : 0,
1461 &write_fh,
1462 write_fh ? 1 : 0);
1463 t->callback = task;
1464 t->callback_cls = task_cls;
1465#if DEBUG_FDS
1466 check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1);
1467 check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1);
1468 check_fd (t, NULL != read_fh ? read_fh->fd : -1);
1469 check_fd (t, NULL != write_fh ? write_fh->fd : -1);
1470#endif
1471#if PROFILE_DELAYS
1472 t->start_time = GNUNET_TIME_absolute_get ();
1473#endif
1480 t);
1483 t->priority);
1484 init_backtrace (t);
1485 return t;
1486}
1487
1488
1509struct GNUNET_SCHEDULER_Task *
1511 struct GNUNET_NETWORK_Handle *rfd,
1513 void *task_cls)
1514{
1517 rfd, task, task_cls);
1518}
1519
1520
1543struct GNUNET_SCHEDULER_Task *
1546 priority,
1547 struct GNUNET_NETWORK_Handle *rfd,
1549 void *task_cls)
1550{
1552 rfd,
1553 GNUNET_YES,
1554 GNUNET_NO,
1555 task, task_cls);
1556}
1557
1558
1580struct GNUNET_SCHEDULER_Task *
1582 struct GNUNET_NETWORK_Handle *wfd,
1584 void *task_cls)
1585{
1588 wfd,
1590 task, task_cls);
1591}
1592
1593
1617struct GNUNET_SCHEDULER_Task *
1620 struct GNUNET_NETWORK_Handle *fd,
1621 int on_read,
1622 int on_write,
1624 void *task_cls)
1625{
1626 /* scheduler must be running */
1628 GNUNET_assert (on_read || on_write);
1630 return add_without_sets (delay, priority,
1631 on_read ? fd : NULL,
1632 on_write ? fd : NULL,
1633 NULL,
1634 NULL,
1635 task, task_cls);
1636}
1637
1638
1659struct GNUNET_SCHEDULER_Task *
1661 const struct GNUNET_DISK_FileHandle *rfd,
1663 void *task_cls)
1664{
1667 rfd, GNUNET_YES, GNUNET_NO,
1668 task, task_cls);
1669}
1670
1671
1692struct GNUNET_SCHEDULER_Task *
1694 const struct GNUNET_DISK_FileHandle *wfd,
1696 void *task_cls)
1697{
1700 wfd, GNUNET_NO, GNUNET_YES,
1701 task, task_cls);
1702}
1703
1704
1728struct GNUNET_SCHEDULER_Task *
1731 priority,
1732 const struct
1734 int on_read, int on_write,
1736 void *task_cls)
1737{
1738 /* scheduler must be running */
1740 GNUNET_assert (on_read || on_write);
1741 GNUNET_assert (fd->fd >= 0);
1742 return add_without_sets (delay, priority,
1743 NULL,
1744 NULL,
1745 on_read ? fd : NULL,
1746 on_write ? fd : NULL,
1747 task, task_cls);
1748}
1749
1750
1751static void
1753 const struct GNUNET_NETWORK_Handle ***ntarget,
1754 unsigned int *extracted_nhandles,
1755 const struct GNUNET_DISK_FileHandle ***ftarget,
1756 unsigned int *extracted_fhandles)
1757{
1758 // FIXME: this implementation only works for unix, for WIN32 the file handles
1759 // in fdset must be handled separately
1760 const struct GNUNET_NETWORK_Handle **nhandles;
1761 const struct GNUNET_DISK_FileHandle **fhandles;
1762 unsigned int nhandles_len;
1763 unsigned int fhandles_len;
1764
1765 nhandles = NULL;
1766 fhandles = NULL;
1767 nhandles_len = 0;
1768 fhandles_len = 0;
1769 for (int sock = 0; sock != fdset->nsds; ++sock)
1770 {
1771 if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock))
1772 {
1773 struct GNUNET_NETWORK_Handle *nhandle;
1774 struct GNUNET_DISK_FileHandle *fhandle;
1775
1776 nhandle = GNUNET_NETWORK_socket_box_native (sock);
1777 if (NULL != nhandle)
1778 {
1779 GNUNET_array_append (nhandles, nhandles_len, nhandle);
1780 }
1781 else
1782 {
1783 fhandle = GNUNET_DISK_get_handle_from_int_fd (sock);
1784 if (NULL != fhandle)
1785 {
1786 GNUNET_array_append (fhandles, fhandles_len, fhandle);
1787 }
1788 else
1789 {
1790 GNUNET_assert (0);
1791 }
1792 }
1793 }
1794 }
1795 *ntarget = nhandles_len > 0 ? nhandles : NULL;
1796 *ftarget = fhandles_len > 0 ? fhandles : NULL;
1797 *extracted_nhandles = nhandles_len;
1798 *extracted_fhandles = fhandles_len;
1799}
1800
1801
1833struct GNUNET_SCHEDULER_Task *
1835 struct GNUNET_TIME_Relative delay,
1836 const struct GNUNET_NETWORK_FDSet *rs,
1837 const struct GNUNET_NETWORK_FDSet *ws,
1839 void *task_cls)
1840{
1841 struct GNUNET_SCHEDULER_Task *t;
1842 const struct GNUNET_NETWORK_Handle **read_nhandles = NULL;
1843 const struct GNUNET_NETWORK_Handle **write_nhandles = NULL;
1844 const struct GNUNET_DISK_FileHandle **read_fhandles = NULL;
1845 const struct GNUNET_DISK_FileHandle **write_fhandles = NULL;
1846 unsigned int read_nhandles_len = 0;
1847 unsigned int write_nhandles_len = 0;
1848 unsigned int read_fhandles_len = 0;
1849 unsigned int write_fhandles_len = 0;
1850 int no_rs = (NULL == rs);
1851 int no_ws = (NULL == ws);
1852 int empty_rs = (NULL != rs) && (0 == rs->nsds);
1853 int empty_ws = (NULL != ws) && (0 == ws->nsds);
1854 int no_fds = (no_rs && no_ws) ||
1855 (empty_rs && empty_ws) ||
1856 (no_rs && empty_ws) ||
1857 (no_ws && empty_rs);
1858 int no_fds_extracted;
1859
1860 /* scheduler must be running */
1862 GNUNET_assert (NULL != task);
1863 if (! no_fds)
1864 {
1865 if (NULL != rs)
1866 {
1867 extract_handles (rs,
1868 &read_nhandles,
1869 &read_nhandles_len,
1870 &read_fhandles,
1871 &read_fhandles_len);
1872 }
1873 if (NULL != ws)
1874 {
1875 extract_handles (ws,
1876 &write_nhandles,
1877 &write_nhandles_len,
1878 &write_fhandles,
1879 &write_fhandles_len);
1880 }
1881 }
1889 no_fds_extracted = (0 == read_nhandles_len) &&
1890 (0 == read_fhandles_len) &&
1891 (0 == write_nhandles_len) &&
1892 (0 == write_fhandles_len);
1893 if (no_fds || no_fds_extracted)
1895 prio,
1896 task,
1897 task_cls);
1900 init_fd_info (t,
1901 read_nhandles,
1902 read_nhandles_len,
1903 write_nhandles,
1904 write_nhandles_len,
1905 read_fhandles,
1906 read_fhandles_len,
1907 write_fhandles,
1908 write_fhandles_len);
1909 t->callback = task;
1910 t->callback_cls = task_cls;
1912 /* free the arrays of pointers to network / file handles, the actual
1913 * handles will be freed in destroy_task */
1914 GNUNET_array_grow (read_nhandles, read_nhandles_len, 0);
1915 GNUNET_array_grow (write_nhandles, write_nhandles_len, 0);
1916 GNUNET_array_grow (read_fhandles, read_fhandles_len, 0);
1917 GNUNET_array_grow (write_fhandles, write_fhandles_len, 0);
1918#if PROFILE_DELAYS
1919 t->start_time = GNUNET_TIME_absolute_get ();
1920#endif
1922 t->priority =
1923 check_priority ((prio ==
1925 prio);
1929 t);
1932 t->priority);
1934 "Adding task %p\n",
1935 t);
1936 init_backtrace (t);
1937 return t;
1938}
1939
1940
1952void
1954 struct GNUNET_SCHEDULER_FdInfo *fdi)
1955{
1956 enum GNUNET_SCHEDULER_Reason reason;
1957
1958 reason = task->reason;
1959 if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1960 (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)))
1962 if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
1963 (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)))
1966 task->reason = reason;
1967 if (GNUNET_NO == task->in_ready_list)
1968 {
1971 task);
1972 queue_ready_task (task);
1973 }
1974}
1975
1976
1997int
1999{
2000 struct GNUNET_SCHEDULER_Task *pos;
2001 struct GNUNET_TIME_Absolute now;
2002
2003 /* check for tasks that reached the timeout! */
2004 now = GNUNET_TIME_absolute_get ();
2006 while (NULL != pos)
2007 {
2008 struct GNUNET_SCHEDULER_Task *next = pos->next;
2009 if (now.abs_value_us >= pos->timeout.abs_value_us)
2011 if (0 == pos->reason)
2012 break;
2015 pos);
2016 if (pending_timeout_last == pos)
2017 pending_timeout_last = NULL;
2018 queue_ready_task (pos);
2019 pos = next;
2020 }
2021 pos = pending_head;
2022 while (NULL != pos)
2023 {
2024 struct GNUNET_SCHEDULER_Task *next = pos->next;
2025 if (now.abs_value_us >= pos->timeout.abs_value_us)
2026 {
2030 pos);
2031 queue_ready_task (pos);
2032 }
2033 pos = next;
2034 }
2035
2036 if (0 == ready_count)
2037 {
2039
2040 if (timeout.abs_value_us > now.abs_value_us)
2041 {
2056 "GNUNET_SCHEDULER_do_work did not find any ready "
2057 "tasks and timeout has not been reached yet.\n");
2058 }
2059 else
2060 {
2065 GNUNET_assert (0);
2066 }
2067 }
2068 else
2069 {
2070 /* find out which task priority level we are going to
2071 process this time */
2074 /* yes, p>0 is correct, 0 is "KEEP" which should
2075 * always be an empty queue (see assertion)! */
2077 work_priority > 0;
2078 work_priority--)
2079 {
2081 if (NULL != pos)
2082 break;
2083 }
2084 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2085
2086 /* process all *existing* tasks at this priority
2087 level, then yield */
2089 while (NULL != (pos = ready_head[work_priority])
2090 && pos != &pass_end_marker)
2091 {
2094 pos);
2095 ready_count--;
2098 active_task = pos;
2099#if PROFILE_DELAYS
2100 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2101 DELAY_THRESHOLD.rel_value_us)
2102 {
2104 "Task %p took %s to be scheduled\n",
2105 pos,
2107 GNUNET_TIME_absolute_get_duration (pos->start_time),
2108 GNUNET_YES));
2109 }
2110#endif
2111 tc.reason = pos->reason;
2114 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2115 tc.fds_len = pos->fds_len;
2116 tc.fds = pos->fds;
2117 for (unsigned int i = 0; i != pos->fds_len; ++i)
2118 {
2119 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
2120 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
2121 {
2123 fdi->sock);
2124 }
2125 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
2126 {
2128 fdi->sock);
2129 }
2130 }
2131 tc.read_ready = sh->rs;
2132 tc.write_ready = sh->ws;
2134 "Running task %p\n",
2135 pos);
2136 GNUNET_assert (NULL != pos->callback);
2137 {
2138 struct GNUNET_AsyncScopeSave old_scope;
2139 if (pos->scope.have_scope)
2140 GNUNET_async_scope_enter (&pos->scope.scope_id, &old_scope);
2141 else
2142 GNUNET_async_scope_get (&old_scope);
2143 pos->callback (pos->callback_cls);
2144 GNUNET_async_scope_restore (&old_scope);
2145 }
2146 if (NULL != pos->fds)
2147 {
2148 int del_result = scheduler_driver->del (scheduler_driver->cls,
2149 pos);
2150 if (GNUNET_OK != del_result)
2151 {
2153 "driver could not delete task %p\n", pos);
2154 GNUNET_assert (0);
2155 }
2156 }
2157 active_task = NULL;
2158 dump_backtrace (pos);
2159 destroy_task (pos);
2160 }
2162 }
2164 if (0 == ready_count)
2165 {
2167 get_timeout ());
2168 return GNUNET_NO;
2169 }
2172 return GNUNET_YES;
2173}
2174
2175
2209{
2211 const struct GNUNET_DISK_FileHandle *pr;
2212
2213 /* scheduler must not be running */
2216 /* general set-up */
2222 my_pid = getpid ();
2223 scheduler_driver = driver;
2224
2225 /* install signal handlers */
2227 "Registering signal handlers\n");
2228 sh->shc_int = GNUNET_SIGNAL_handler_install (SIGINT,
2230 sh->shc_term = GNUNET_SIGNAL_handler_install (SIGTERM,
2232#if (SIGTERM != GNUNET_TERM_SIG)
2235#endif
2236 sh->shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE,
2238 sh->shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT,
2240 sh->shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP,
2242
2243 /* Setup initial tasks */
2246 /* ensure this task runs first, by using a priority level reserved for
2247 the scheduler (not really shutdown, but start-up ;-) */
2251 NULL);
2254 pr,
2256 NULL);
2259 get_timeout ());
2260 /* begin main event loop */
2264 return sh;
2265}
2266
2267
2282void
2284{
2285 GNUNET_break (NULL == pending_head);
2287 GNUNET_break (NULL == shutdown_head);
2288 for (int i = 0; i != GNUNET_SCHEDULER_PRIORITY_COUNT; ++i)
2289 {
2290 GNUNET_break (NULL == ready_head[i]);
2291 }
2294
2295 /* uninstall signal handlers */
2298#if (SIGTERM != GNUNET_TERM_SIG)
2300#endif
2305 shutdown_pipe_handle = NULL;
2306 scheduler_driver = NULL;
2307 GNUNET_free (sh);
2308}
2309
2310
2311static enum GNUNET_GenericReturnValue
2313 struct DriverContext *context)
2314{
2315 struct GNUNET_NETWORK_FDSet *rs;
2316 struct GNUNET_NETWORK_FDSet *ws;
2317 int select_result;
2318
2319 GNUNET_assert (NULL != context);
2322 while ((NULL != context->scheduled_head) ||
2323 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
2324 context->timeout.abs_value_us))
2325 {
2326 struct GNUNET_TIME_Relative time_remaining;
2327
2329 "select timeout = %s\n",
2331
2334
2335 for (struct Scheduled *pos = context->scheduled_head;
2336 NULL != pos;
2337 pos = pos->next)
2338 {
2339 if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et))
2340 {
2341 GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock);
2342 }
2343 if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et))
2344 {
2345 GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock);
2346 }
2347 }
2348 time_remaining = GNUNET_TIME_absolute_get_remaining (context->timeout);
2349 if (0 < ready_count)
2350 time_remaining = GNUNET_TIME_UNIT_ZERO;
2351 if (NULL == scheduler_select)
2352 {
2353 select_result = GNUNET_NETWORK_socket_select (rs,
2354 ws,
2355 NULL,
2356 time_remaining);
2357 }
2358 else
2359 {
2360 select_result = scheduler_select (scheduler_select_cls,
2361 rs,
2362 ws,
2363 NULL,
2364 time_remaining);
2365 }
2366 if (select_result == GNUNET_SYSERR)
2367 {
2368 if (errno == EINTR)
2369 continue;
2370
2372 "select");
2373#if USE_LSOF
2374 char lsof[512];
2375
2376 snprintf (lsof,
2377 sizeof(lsof),
2378 "lsof -p %d",
2379 getpid ());
2380 (void) close (1);
2381 (void) dup2 (2, 1);
2382 if (0 != system (lsof))
2384 "system");
2385#endif
2386#if DEBUG_FDS
2387 for (struct Scheduled *s = context->scheduled_head;
2388 NULL != s;
2389 s = s->next)
2390 {
2391 int flags = fcntl (s->fdi->sock,
2392 F_GETFD);
2393
2394 if ((flags == -1) &&
2395 (EBADF == errno))
2396 {
2398 "Got invalid file descriptor %d!\n",
2399 s->fdi->sock);
2400#if EXECINFO
2401 dump_backtrace (s->task);
2402#endif
2403 }
2404 }
2405#endif
2406 GNUNET_assert (0);
2409 return GNUNET_SYSERR;
2410 }
2411 if (select_result > 0)
2412 {
2413 for (struct Scheduled *pos = context->scheduled_head;
2414 NULL != pos;
2415 pos = pos->next)
2416 {
2417 int is_ready = GNUNET_NO;
2418
2419 if ((0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) &&
2420 (GNUNET_YES ==
2422 pos->fdi->sock)) )
2423 {
2424 pos->fdi->et |= GNUNET_SCHEDULER_ET_IN;
2425 is_ready = GNUNET_YES;
2426 }
2427 if ((0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) &&
2428 (GNUNET_YES ==
2430 pos->fdi->sock)) )
2431 {
2432 pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT;
2433 is_ready = GNUNET_YES;
2434 }
2435 if (GNUNET_YES == is_ready)
2436 {
2437 GNUNET_SCHEDULER_task_ready (pos->task,
2438 pos->fdi);
2439 }
2440 }
2441 }
2443 {
2445 "scheduler has more tasks ready!\n");
2446 }
2447 }
2450
2451 if ( (NULL == context->scheduled_head) &&
2452 (NULL != pending_timeout_head) &&
2453 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us ==
2454 context->timeout.abs_value_us) )
2455 {
2456 /* Only remaining task has timeout of 'forever'.
2457 We exit here more as sanity measure, as just
2458 waiting forever isn't exactly useful. Still,
2459 this is indicative of a bug in the client code. */
2460 GNUNET_break (0);
2461 return GNUNET_NO;
2462 }
2463 return GNUNET_OK;
2464}
2465
2466
2467static int
2468select_add (void *cls,
2469 struct GNUNET_SCHEDULER_Task *task,
2470 struct GNUNET_SCHEDULER_FdInfo *fdi)
2471{
2472 struct DriverContext *context = cls;
2473 struct Scheduled *scheduled;
2474
2475 GNUNET_assert (NULL != context);
2476 GNUNET_assert (NULL != task);
2477 GNUNET_assert (NULL != fdi);
2479 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et));
2480
2481 if (! ((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0))
2482 {
2483 /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */
2484 return GNUNET_SYSERR;
2485 }
2486
2487 scheduled = GNUNET_new (struct Scheduled);
2488 scheduled->task = task;
2489 scheduled->fdi = fdi;
2490 scheduled->et = fdi->et;
2491
2492 GNUNET_CONTAINER_DLL_insert (context->scheduled_head,
2493 context->scheduled_tail,
2494 scheduled);
2495 return GNUNET_OK;
2496}
2497
2498
2499static int
2500select_del (void *cls,
2502{
2503 struct DriverContext *context;
2504 struct Scheduled *pos;
2505 int ret;
2506
2507 GNUNET_assert (NULL != cls);
2508
2509 context = cls;
2511 pos = context->scheduled_head;
2512 while (NULL != pos)
2513 {
2514 struct Scheduled *next = pos->next;
2515 if (pos->task == task)
2516 {
2517 GNUNET_CONTAINER_DLL_remove (context->scheduled_head,
2518 context->scheduled_tail,
2519 pos);
2520 GNUNET_free (pos);
2521 ret = GNUNET_OK;
2522 }
2523 pos = next;
2524 }
2525 return ret;
2526}
2527
2528
2529static void
2531 struct GNUNET_TIME_Absolute dt)
2532{
2533 struct DriverContext *context = cls;
2534
2535 GNUNET_assert (NULL != context);
2536 context->timeout = dt;
2537}
2538
2539
2547{
2548 struct GNUNET_SCHEDULER_Driver *select_driver;
2549
2550 select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver);
2551
2552 select_driver->add = &select_add;
2553 select_driver->del = &select_del;
2554 select_driver->set_wakeup = &select_set_wakeup;
2555
2556 return select_driver;
2557}
2558
2559
2572void
2574{
2575 struct GNUNET_AsyncScopeSave dummy_old_scope;
2576
2577 GNUNET_assert (NULL != active_task);
2578 /* Since we're in a task, the context will be automatically
2579 restored by the scheduler. */
2580 GNUNET_async_scope_enter (aid, &dummy_old_scope);
2581}
2582
2583
2584/* 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:1618
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:687
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1445
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1588
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:1331
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:623
@ 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:1187
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:1171
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:1261
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:566
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:1510
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:1371
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:724
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:1693
void GNUNET_SCHEDULER_driver_done(struct GNUNET_SCHEDULER_Handle *sh)
Counter-part of GNUNET_SCHEDULER_driver_init.
Definition: scheduler.c:2283
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:1544
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:1953
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:1073
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:1660
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:1998
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:1581
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:1834
unsigned int GNUNET_SCHEDULER_get_load(enum GNUNET_SCHEDULER_Priority p)
Get information about the current load of this scheduler.
Definition: scheduler.c:774
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:757
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:1729
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:1253
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:1338
struct GNUNET_SCHEDULER_Driver * GNUNET_SCHEDULER_driver_select()
Obtain the driver for using select() as the event loop.
Definition: scheduler.c:2546
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:2573
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:979
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:446
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:1303
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:1618
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:1276
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:1206
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:1117
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:2208
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:1230
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:570
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:617
#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:671
static void dump_backtrace(struct GNUNET_SCHEDULER_Task *t)
Output stack trace of task t.
Definition: scheduler.c:599
static void driver_add_multiple(struct GNUNET_SCHEDULER_Task *t)
calls the given function func on each FdInfo related to t.
Definition: scheduler.c:913
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:392
static void select_set_wakeup(void *cls, struct GNUNET_TIME_Absolute dt)
Definition: scheduler.c:2530
static void destroy_task(struct GNUNET_SCHEDULER_Task *t)
Destroy a task (release associated resources)
Definition: scheduler.c:620
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:461
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:545
static int select_del(void *cls, struct GNUNET_SCHEDULER_Task *task)
Definition: scheduler.c:2500
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:386
static struct GNUNET_SCHEDULER_Task * active_task
ID of the task that is running right now.
Definition: scheduler.c:367
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:378
static enum GNUNET_SCHEDULER_Priority current_priority
Priority of the task running right now.
Definition: scheduler.c:403
static struct GNUNET_SCHEDULER_Task * pending_head
Head of list of tasks waiting for an event.
Definition: scheduler.c:323
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:476
static void remove_pass_end_marker()
Definition: scheduler.c:514
#define DELAY_THRESHOLD
Task that were in the queue for longer than this are reported if PROFILE_DELAYS is active.
Definition: scheduler.c:73
static unsigned int ready_count
Number of tasks on the ready list.
Definition: scheduler.c:397
static struct GNUNET_DISK_PipeHandle * shutdown_pipe_handle
Pipe used to communicate shutdown via signal.
Definition: scheduler.c:659
static const struct GNUNET_SCHEDULER_Driver * scheduler_driver
The driver used for the event loop.
Definition: scheduler.c:318
static struct GNUNET_SCHEDULER_Task * pending_timeout_head
List of tasks waiting ONLY for a timeout event.
Definition: scheduler.c:347
static void install_parent_control_handler(void *cls)
Definition: scheduler.c:935
static int select_add(void *cls, struct GNUNET_SCHEDULER_Task *task, struct GNUNET_SCHEDULER_FdInfo *fdi)
Definition: scheduler.c:2468
static GNUNET_SCHEDULER_select scheduler_select
Function to use as a select() in the scheduler.
Definition: scheduler.c:425
static enum GNUNET_SCHEDULER_Priority work_priority
Priority used currently in GNUNET_SCHEDULER_do_work().
Definition: scheduler.c:419
static void shutdown_if_no_lifeness(void)
Definition: scheduler.c:698
static void * scheduler_select_cls
Closure for scheduler_select.
Definition: scheduler.c:435
static struct GNUNET_SCHEDULER_Task * pending_timeout_tail
List of tasks waiting ONLY for a timeout event.
Definition: scheduler.c:356
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:372
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:255
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:1438
static int current_lifeness
Value of the 'lifeness' flag for the current task.
Definition: scheduler.c:414
static void set_work_priority(enum GNUNET_SCHEDULER_Priority p)
Definition: scheduler.c:527
static void init_backtrace(struct GNUNET_SCHEDULER_Task *t)
Initialize backtrace data for task t.
Definition: scheduler.c:1045
static enum GNUNET_SCHEDULER_Priority max_priority_added
Priority of the highest task added in the current select iteration.
Definition: scheduler.c:409
static struct GNUNET_SCHEDULER_Task * pending_timeout_last
Last inserted task waiting ONLY for a timeout event.
Definition: scheduler.c:362
static void sighandler_shutdown(void)
Signal handler called for signals that should cause us to shutdown.
Definition: scheduler.c:681
#define LOG(kind,...)
Definition: scheduler.c:31
static void shutdown_pipe_cb(void *cls)
Definition: scheduler.c:944
#define LOG_STRERROR(kind, syscall)
Definition: scheduler.c:33
static enum GNUNET_GenericReturnValue select_loop(struct GNUNET_SCHEDULER_Handle *sh, struct DriverContext *context)
Definition: scheduler.c:2312
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:796
static struct GNUNET_SCHEDULER_Task * pending_tail
Tail of list of tasks waiting for an event.
Definition: scheduler.c:328
static struct GNUNET_SCHEDULER_Task * shutdown_tail
Tail of list of tasks waiting for shutdown.
Definition: scheduler.c:338
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:430
static struct GNUNET_SCHEDULER_Task * shutdown_head
Head of list of tasks waiting for shutdown.
Definition: scheduler.c:333
static pid_t my_pid
Process ID of this process at the time we installed the various signal handlers.
Definition: scheduler.c:665
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:1752
Driver context used by GNUNET_SCHEDULER_run.
Definition: scheduler.c:290
struct Scheduled * scheduled_head
the head of a DLL containing information about the events the select driver is waiting for
Definition: scheduler.c:295
struct GNUNET_TIME_Absolute timeout
the time when the select driver will wake up again (after calling select)
Definition: scheduler.c:307
struct Scheduled * scheduled_tail
the tail of a DLL containing information about the events the select driver is waiting for
Definition: scheduler.c:301
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:82
struct GNUNET_NETWORK_FDSet * rs
Passed here to avoid constantly allocating/deallocating this element, but generally we want to get ri...
Definition: scheduler.c:88
struct GNUNET_SIGNAL_Context * shc_quit
context of the SIGQUIT handler
Definition: scheduler.c:117
struct GNUNET_SIGNAL_Context * shc_hup
context of the SIGHUP handler
Definition: scheduler.c:122
struct GNUNET_SIGNAL_Context * shc_int
context of the SIGINT handler
Definition: scheduler.c:100
struct GNUNET_SIGNAL_Context * shc_pipe
context of the SIGPIPE handler
Definition: scheduler.c:127
struct GNUNET_NETWORK_FDSet * ws
Passed here to avoid constantly allocating/deallocating this element, but generally we want to get ri...
Definition: scheduler.c:95
struct GNUNET_SIGNAL_Context * shc_term
context of the SIGTERM handler
Definition: scheduler.c:105
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:135
enum GNUNET_SCHEDULER_Priority priority
Task priority.
Definition: scheduler.c:203
struct GNUNET_SCHEDULER_Task * prev
This is a linked list.
Definition: scheduler.c:144
void * callback_cls
Closure for the callback.
Definition: scheduler.c:154
int in_ready_list
Is this task in the ready list?
Definition: scheduler.c:229
int lifeness
Should the existence of this task in the queue be counted as reason to not shutdown the scheduler?
Definition: scheduler.c:219
enum GNUNET_SCHEDULER_Reason reason
Why is the task ready? Set after task is added to ready queue.
Definition: scheduler.c:198
int own_handles
Do we own the network and file handles referenced by the FdInfo structs in the fds array.
Definition: scheduler.c:178
struct GNUNET_AsyncScopeSave scope
Asynchronous scope of the task that scheduled this scope,.
Definition: scheduler.c:247
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition: scheduler.c:139
int on_shutdown
Is this task run on shutdown?
Definition: scheduler.c:224
struct GNUNET_SCHEDULER_FdInfo * fds
Information about which FDs are ready for this task (and why).
Definition: scheduler.c:159
unsigned int fds_len
Size of the fds array.
Definition: scheduler.c:171
struct GNUNET_TIME_Absolute timeout
Absolute timeout value for the task, or GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
Definition: scheduler.c:184
GNUNET_SCHEDULER_TaskCallback callback
Function to run when ready.
Definition: scheduler.c:149
int write_fd
Set if we only wait for writing to a single FD, otherwise -1.
Definition: scheduler.c:213
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:166
int read_fd
Set if we only wait for reading from a single FD, otherwise -1.
Definition: scheduler.c:208
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:262
struct Scheduled * next
Definition: scheduler.c:265
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:282
struct Scheduled * prev
Definition: scheduler.c:263
struct GNUNET_SCHEDULER_FdInfo * fdi
information about the network socket / file descriptor where the event is expected to occur
Definition: scheduler.c:276
struct GNUNET_SCHEDULER_Task * task
the task, the event is related to
Definition: scheduler.c:270