#include "gnunet_signal_lib.h"
#include "gnunet_time_lib.h"
#include "disk.h"
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
#ifdef LINUX
#include "execinfo.h"
+
/**
* Use lsof to generate file descriptor reports on select error?
* (turn off for stable releases).
/**
* Check each file descriptor before adding
*/
-#define DEBUG_FDS GNUNET_NO
+#define DEBUG_FDS GNUNET_EXTRA_LOGGING
/**
* Depth of the traces collected via EXECINFO.
#define MAX_TRACE_DEPTH 50
#endif
-#define DEBUG_TASKS GNUNET_NO
+#define DEBUG_TASKS GNUNET_EXTRA_LOGGING
/**
* Should we figure out which tasks are delayed for a while
while (pos != NULL)
{
#if DEBUG_TASKS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Checking readiness of task: %llu / %p\n", pos->id,
- pos->callback_cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking readiness of task: %llu / %p\n",
+ pos->id, pos->callback_cls);
#endif
next = pos->next;
if (GNUNET_YES == is_ready (pos, now, rs, ws))
if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value >
DELAY_THRESHOLD.rel_value)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Task %llu took %llums to be scheduled\n", pos->id,
- (unsigned long long)
- GNUNET_TIME_absolute_get_duration
- (pos->start_time).rel_value);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Task %llu took %llums to be scheduled\n",
+ pos->id,
+ (unsigned long long)
+ GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value);
}
#endif
tc.reason = pos->reason;
if (((tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) &&
(pos->write_fd != -1) &&
(!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd)))
- abort (); // added to ready in previous select loop!
+ GNUNET_abort (); // added to ready in previous select loop!
#if DEBUG_TASKS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running task: %llu / %p\n", pos->id,
- pos->callback_cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Running task: %llu / %p\n", pos->id,
+ pos->callback_cls);
#endif
pos->callback (pos->callback_cls, &tc);
#if EXECINFO
int i;
for (i = 0; i < pos->num_backtrace_strings; i++)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Task %llu trace %d: %s\n", pos->id,
- i, pos->backtrace_strings[i]);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Task %llu trace %d: %s\n", pos->id, i,
+ pos->backtrace_strings[i]);
#endif
active_task = NULL;
destroy_task (pos);
*/
static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle;
+/**
+ * Process ID of this process at the time we installed the various
+ * signal handlers.
+ */
+static pid_t my_pid;
+
/**
* Signal handler called for SIGPIPE.
*/
static char c;
int old_errno = errno; /* backup errno */
+ if (getpid () != my_pid)
+ exit (1); /* we have fork'ed since the signal handler was created,
+ * ignore the signal, see https://gnunet.org/vfork discussion */
GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
(shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE),
&c, sizeof (c));
rs = GNUNET_NETWORK_fdset_create ();
ws = GNUNET_NETWORK_fdset_create ();
GNUNET_assert (shutdown_pipe_handle == NULL);
- shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
+ shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
GNUNET_assert (shutdown_pipe_handle != NULL);
pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
GNUNET_DISK_PIPE_END_READ);
GNUNET_assert (pr != NULL);
+ my_pid = getpid ();
shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
#ifndef MINGW
if (errno == EINTR)
continue;
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select");
#ifndef MINGW
#if USE_LSOF
char lsof[512];
(void) close (1);
(void) dup2 (2, 1);
if (0 != system (lsof))
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "system");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "system");
#endif
#endif
- abort ();
+ GNUNET_abort ();
break;
}
if ((ret == 0) && (timeout.rel_value == 0) && (busy_wait_warning > 16))
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Looks like we're busy waiting...\n"));
+ LOG (GNUNET_ERROR_TYPE_WARNING, _("Looks like we're busy waiting...\n"));
sleep (1); /* mitigate */
}
check_ready (rs, ws);
p++;
if (p >= GNUNET_SCHEDULER_PRIORITY_COUNT)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Attempt to cancel dead task %llu!\n"),
- (unsigned long long) task);
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Attempt to cancel dead task %llu!\n"),
+ (unsigned long long) task);
GNUNET_assert (0);
}
prev = NULL;
}
ret = t->callback_cls;
#if DEBUG_TASKS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Canceling task: %llu / %p\n", task,
- t->callback_cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Canceling task: %llu / %p\n", task,
+ t->callback_cls);
#endif
destroy_task (t);
return ret;
* @param task main function of the task
* @param task_cls closure for 'main'
* @param reason reason for task invocation
+ * @param priority priority to use for the task
*/
void
-GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls,
- enum GNUNET_SCHEDULER_Reason reason)
+GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, void *task_cls,
+ enum GNUNET_SCHEDULER_Reason reason,
+ enum GNUNET_SCHEDULER_Priority priority)
{
struct Task *t;
t->start_time = GNUNET_TIME_absolute_get ();
#endif
t->reason = reason;
- t->priority = current_priority;
+ t->priority = priority;
t->lifeness = current_lifeness;
#if DEBUG_TASKS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding continuation task: %llu / %p\n",
- t->id, t->callback_cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding continuation task: %llu / %p\n", t->id,
+ t->callback_cls);
#endif
queue_ready_task (t);
}
+/**
+ * Continue the current execution with the given function. This is
+ * similar to the other "add" functions except that there is no delay
+ * and the reason code can be specified.
+ *
+ * @param task main function of the task
+ * @param task_cls closure for 'main'
+ * @param reason reason for task invocation
+ */
+void
+GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls,
+ enum GNUNET_SCHEDULER_Reason reason)
+{
+ GNUNET_SCHEDULER_add_continuation_with_priority (task, task_cls,
+ reason,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT);
+}
+
/**
* Schedule a new task to be run after the specified prerequisite task
- * has completed. It will be run with the priority of the calling
- * task.
+ * has completed. It will be run with the DEFAULT priority.
*
* @param prerequisite_task run this task after the task with the given
* task identifier completes (and any of our other
GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
GNUNET_SCHEDULER_Task task, void *task_cls)
{
- return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
+ return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
prerequisite_task, GNUNET_TIME_UNIT_ZERO,
NULL, NULL, task, task_cls);
}
/**
* Schedule a new task to be run with a specified delay. The task
- * will be scheduled for execution once the delay has expired. It
- * will be run with the priority of the calling task.
+ * will be scheduled for execution once the delay has expired.
*
* @param delay when should this operation time out? Use
* GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param priority priority to use for the task
* @param task main function of the task
* @param task_cls closure of task
* @return unique task identifier for the job
* only valid until "task" is started!
*/
GNUNET_SCHEDULER_TaskIdentifier
-GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
- GNUNET_SCHEDULER_Task task, void *task_cls)
+GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
+ enum GNUNET_SCHEDULER_Priority priority,
+ GNUNET_SCHEDULER_Task task, void *task_cls)
{
-#if 1
- /* new, optimized version */
struct Task *t;
struct Task *pos;
struct Task *prev;
t->start_time = GNUNET_TIME_absolute_get ();
#endif
t->timeout = GNUNET_TIME_relative_to_absolute (delay);
- t->priority = current_priority;
+ t->priority = priority;
t->lifeness = current_lifeness;
/* try tail first (optimization in case we are
* appending to a long list of tasks with timeouts) */
pending_timeout_last = t;
#if DEBUG_TASKS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
- t->callback_cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
+ t->callback_cls);
#endif
#if EXECINFO
int i;
for (i = 0; i < t->num_backtrace_strings; i++)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
- t->backtrace_strings[i]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
+ t->backtrace_strings[i]);
#endif
return t->id;
-
-#else
- /* unoptimized version */
- return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
- GNUNET_SCHEDULER_NO_TASK, delay, NULL,
- NULL, task, task_cls);
-#endif
}
+/**
+ * Schedule a new task to be run with a specified delay. The task
+ * will be scheduled for execution once the delay has expired. It
+ * will be run with the DEFAULT priority.
+ *
+ * @param delay when should this operation time out? Use
+ * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param task main function of the task
+ * @param task_cls closure of task
+ * @return unique task identifier for the job
+ * only valid until "task" is started!
+ */
+GNUNET_SCHEDULER_TaskIdentifier
+GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
+ GNUNET_SCHEDULER_Task task, void *task_cls)
+{
+ return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ task, task_cls);
+}
+
/**
* Schedule a new task to be run as soon as possible. The task
- * will be run with the priority of the calling task.
+ * will be run with the DEFAULT priority.
*
* @param task main function of the task
* @param task_cls closure of task
GNUNET_SCHEDULER_TaskIdentifier
GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls)
{
- return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
- GNUNET_SCHEDULER_NO_TASK,
- GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
- task_cls);
+ return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, task, task_cls);
}
GNUNET_SCHEDULER_TaskIdentifier ret;
ret =
- GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
GNUNET_SCHEDULER_NO_TASK,
GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
task_cls);
}
-
-
/**
* Schedule a new task to be run with a specified delay or when any of
* the specified file descriptor sets is ready. The delay can be used
*
* @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever",
* which means that the task will only be run after we receive SIGTERM
+ * @param priority priority to use
* @param rfd file descriptor we want to read (can be -1)
* @param wfd file descriptors we want to write (can be -1)
* @param task main function of the task
* only valid until "task" is started!
*/
#ifndef MINGW
-GNUNET_SCHEDULER_TaskIdentifier
-add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
+static GNUNET_SCHEDULER_TaskIdentifier
+add_without_sets (struct GNUNET_TIME_Relative delay,
+ enum GNUNET_SCHEDULER_Priority priority,
+ int rfd, int wfd,
GNUNET_SCHEDULER_Task task, void *task_cls)
{
struct Task *t;
{
int flags = fcntl (rfd, F_GETFD);
- if (flags == -1 && errno == EBADF)
+ if ((flags == -1) && (errno == EBADF))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n",
- rfd);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", rfd);
#if EXECINFO
int i;
for (i = 0; i < t->num_backtrace_strings; i++)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n",
- t->backtrace_strings[i]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]);
#endif
GNUNET_assert (0);
}
if (flags == -1 && errno == EBADF)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n",
- wfd);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", wfd);
#if EXECINFO
int i;
for (i = 0; i < t->num_backtrace_strings; i++)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n",
- t->backtrace_strings[i]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]);
#endif
GNUNET_assert (0);
}
#endif
t->prereq_id = GNUNET_SCHEDULER_NO_TASK;
t->timeout = GNUNET_TIME_relative_to_absolute (delay);
- t->priority = check_priority (current_priority);
+ t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : priority);
t->lifeness = current_lifeness;
t->next = pending;
pending = t;
max_priority_added = GNUNET_MAX (max_priority_added, t->priority);
#if DEBUG_TASKS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
- t->callback_cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
+ t->callback_cls);
#endif
#if EXECINFO
int i;
for (i = 0; i < t->num_backtrace_strings; i++)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
- t->backtrace_strings[i]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
+ t->backtrace_strings[i]);
#endif
return t->id;
}
* specified file descriptor is ready for reading. The delay can be
* used as a timeout on the socket being ready. The task will be
* scheduled for execution once either the delay has expired or the
- * socket operation is ready. It will be run with the priority of
- * the calling task.
+ * socket operation is ready. It will be run with the DEFAULT priority.
*
* @param delay when should this operation time out? Use
* GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
rs = GNUNET_NETWORK_fdset_create ();
GNUNET_NETWORK_fdset_set (rs, rfd);
ret =
- GNUNET_SCHEDULER_add_select (check_priority (current_priority),
- GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL,
- task, task_cls);
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL,
+ task, task_cls);
GNUNET_NETWORK_fdset_destroy (rs);
return ret;
#else
- return add_without_sets (delay, GNUNET_NETWORK_get_fd (rfd), -1, task,
+ return add_without_sets (delay,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_NETWORK_get_fd (rfd), -1, task,
task_cls);
#endif
}
ws = GNUNET_NETWORK_fdset_create ();
GNUNET_NETWORK_fdset_set (ws, wfd);
ret =
- GNUNET_SCHEDULER_add_select (check_priority (current_priority),
- GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws,
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws,
task, task_cls);
GNUNET_NETWORK_fdset_destroy (ws);
return ret;
#else
GNUNET_assert (GNUNET_NETWORK_get_fd (wfd) >= 0);
- return add_without_sets (delay, -1, GNUNET_NETWORK_get_fd (wfd), task,
+ return add_without_sets (delay,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ -1, GNUNET_NETWORK_get_fd (wfd), task,
task_cls);
#endif
}
* specified file descriptor is ready for reading. The delay can be
* used as a timeout on the socket being ready. The task will be
* scheduled for execution once either the delay has expired or the
- * socket operation is ready. It will be run with the priority of
- * the calling task.
+ * socket operation is ready. It will be run with the DEFAULT priority.
*
* @param delay when should this operation time out? Use
* GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
rs = GNUNET_NETWORK_fdset_create ();
GNUNET_NETWORK_fdset_handle_set (rs, rfd);
ret =
- GNUNET_SCHEDULER_add_select (check_priority (current_priority),
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL,
task, task_cls);
GNUNET_NETWORK_fdset_destroy (rs);
int fd;
GNUNET_DISK_internal_file_handle_ (rfd, &fd, sizeof (int));
- return add_without_sets (delay, fd, -1, task, task_cls);
+ return add_without_sets (delay,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ fd, -1, task, task_cls);
#endif
}
* specified file descriptor is ready for writing. The delay can be
* used as a timeout on the socket being ready. The task will be
* scheduled for execution once either the delay has expired or the
- * socket operation is ready. It will be run with the priority of
- * the calling task.
+ * socket operation is ready. It will be run with the DEFAULT priority.
*
* @param delay when should this operation time out? Use
* GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
ws = GNUNET_NETWORK_fdset_create ();
GNUNET_NETWORK_fdset_handle_set (ws, wfd);
ret =
- GNUNET_SCHEDULER_add_select (check_priority (current_priority),
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws,
task, task_cls);
GNUNET_NETWORK_fdset_destroy (ws);
GNUNET_DISK_internal_file_handle_ (wfd, &fd, sizeof (int));
GNUNET_assert (fd >= 0);
- return add_without_sets (delay, -1, fd, task, task_cls);
+ return add_without_sets (delay,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ -1, fd, task, task_cls);
#endif
}
pending = t;
max_priority_added = GNUNET_MAX (max_priority_added, t->priority);
#if DEBUG_TASKS
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
- t->callback_cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
+ t->callback_cls);
#endif
#if EXECINFO
int i;
for (i = 0; i < t->num_backtrace_strings; i++)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
- t->backtrace_strings[i]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
+ t->backtrace_strings[i]);
#endif
return t->id;
}