-/* Executes all tasks whose timeout has expired. The task is removed from
- the task queue after the callback function has returned. Also, invalid
- tasks are removed here. The current time must be get before calling this
- macro. This macro is used by silc_schedule function. We don't have to
- care about priorities because tasks are already sorted in their priority
- order at the registration phase. */
-
-#define SILC_SCHEDULE_RUN_TIMEOUT_TASKS \
-do { \
- queue = schedule.timeout_queue; \
- if (queue && queue->valid == TRUE && queue->task) { \
- task = queue->task; \
- \
- /* Walk thorugh all tasks in the particular task queue \
- and run all the expired tasks. */ \
- while(1) { \
- /* Execute the task if the timeout has expired */ \
- if (silc_task_timeout_compare(&task->timeout, &curtime)) { \
- \
- /* Task ready for reading */ \
- if (task->valid) { \
- if ((task->iomask & (1L << SILC_TASK_READ))) \
- task->callback(queue, SILC_TASK_READ, \
- task->context, task->fd); \
- } \
- \
- /* Task ready for writing */ \
- if (task->valid) { \
- if ((task->iomask & (1L << SILC_TASK_WRITE))) \
- task->callback(queue, SILC_TASK_WRITE, \
- task->context, task->fd); \
- } \
- \
- /* Break if there isn't more tasks in the queue */ \
- if (queue->task == task->next) { \
- /* Remove the task from queue */ \
- silc_task_remove(queue, task); \
- break; \
- } \
- \
- task = task->next; \
- \
- /* Remove the task from queue */ \
- silc_task_remove(queue, task->prev); \
- } else { \
- /* The timeout hasn't expired, check for next one */ \
- \
- /* Break if there isn't more tasks in the queue */ \
- if (queue->task == task->next) \
- break; \
- \
- task = task->next; \
- } \
- } \
- } \
-} while(0)
-
-/* Calculates next timeout for select(). This is the timeout value
- when at earliest some of the timeout tasks expire. If this is in the
- past, they will be run now. This macro is used by the silc_schedule
- function. */
-
-#define SILC_SCHEDULE_SELECT_TIMEOUT \
-do { \
- if (schedule.timeout_queue && schedule.timeout_queue->valid == TRUE) { \
- queue = schedule.timeout_queue; \
- task = NULL; \
- \
- /* Get the current time */ \
- gettimeofday(&curtime, NULL); \
- schedule.timeout = NULL; \
- \
- /* First task in the task queue has always the smallest timeout. */ \
- task = queue->task; \
- while(1) { \
- if (task && task->valid == TRUE) { \
- \
- /* If the timeout is in past, we will run the task and all other \
- timeout tasks from the past. */ \
- if (silc_task_timeout_compare(&task->timeout, &curtime)) { \
- SILC_SCHEDULE_RUN_TIMEOUT_TASKS; \
- \
- /* The task(s) has expired and doesn't exist on the task queue \
- anymore. We continue with new timeout. */ \
- queue = schedule.timeout_queue; \
- task = queue->task; \
- if (task == NULL || task->valid == FALSE) \
- break; \
- goto cont; \
- } else { \
- cont: \
- /* Calculate the next timeout for select() */ \
- queue->timeout.tv_sec = task->timeout.tv_sec - curtime.tv_sec; \
- queue->timeout.tv_usec = task->timeout.tv_usec - curtime.tv_usec; \
- \
- /* We wouldn't want to go under zero, check for it. */ \
- if (queue->timeout.tv_usec < 0) { \
- queue->timeout.tv_sec -= 1; \
- queue->timeout.tv_usec += 1000000L; \
- } \
- } \
- /* We've got the timeout value */ \
- break; \
- } else { \
- /* Task is not valid, remove it and try next one. */ \
- silc_task_remove(queue, task); \
- task = queue->task; \
- if (queue->task == NULL) \
- break; \
- } \
- } \
- /* Save the timeout */ \
- if (task) \
- schedule.timeout = &queue->timeout; \
- } \
-} while(0)
-
-/* Execute generic tasks. These are executed only and only if for the
- specific fd there wasn't other non-timeout tasks. This checks the earlier
- set fd list, thus the generic tasks apply to all specified fd's. All the
- generic tasks are executed at once. */
-
-#define SILC_SCHEDULE_RUN_GENERIC_TASKS \
-do { \
- if (is_run == FALSE) { \
- SILC_LOG_DEBUG(("Running generic tasks")); \
- for (i = 0; i <= schedule.fd_list.last_fd; i++) \
- if (schedule.fd_list.fd[i] != -1) { \
- \
- /* Check whether this fd is select()ed. */ \
- if ((FD_ISSET(i, &schedule.in)) || (FD_ISSET(i, &schedule.out))) { \
- \
- /* It was selected. Now find the tasks from task queue and execute \
- all generic tasks. */ \
- if (schedule.generic_queue && schedule.generic_queue->valid) { \
- queue = schedule.generic_queue; \
- \
- if (!queue->task) \
- break; \
- \
- task = queue->task; \
- \
- while(1) { \
- /* Validity of the task is checked always before and after \
- execution beacuse the task might have been unregistered \
- in the callback function, ie. it is not valid anymore. */ \
- \
- if (task->valid && schedule.fd_list.fd[i] != -1) { \
- /* Task ready for reading */ \
- if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_READ))) \
- task->callback(queue, SILC_TASK_READ, \
- task->context, i); \
- } \
- \
- if (task->valid && schedule.fd_list.fd[i] != -1) { \
- /* Task ready for writing */ \
- if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_WRITE))) \
- task->callback(queue, SILC_TASK_WRITE, \
- task->context, i); \
- } \
- \
- if (!task->valid) { \
- /* Invalid (unregistered) tasks are removed from the \
- task queue. */ \
- if (queue->task == task->next) { \
- silc_task_remove(queue, task); \
- break; \
- } \
- \
- task = task->next; \
- silc_task_remove(queue, task->prev); \
- continue; \
- } \
- \
- /* Break if there isn't more tasks in the queue */ \
- if (queue->task == task->next) \
- break; \
- \
- task = task->next; \
- } \
- } \
- } \
- } \
- } \
-} while(0)
+SilcBool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
+{
+ struct timeval timeout;
+ int ret;
+
+ SILC_LOG_DEBUG(("In scheduler loop"));
+
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_LOCK(schedule);
+
+ /* Deliver signals if any has been set to be called */
+ if (schedule->signal_tasks) {
+ SILC_SCHEDULE_UNLOCK(schedule);
+ schedule_ops.signals_call(schedule, schedule->internal);
+ schedule->signal_tasks = FALSE;
+ SILC_SCHEDULE_LOCK(schedule);
+ }
+
+ /* Check if scheduler is valid */
+ if (schedule->valid == FALSE) {
+ SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_UNLOCK(schedule);
+ return FALSE;
+ }
+
+ /* Calculate next timeout for silc_select(). This is the timeout value
+ when at earliest some of the timeout tasks expire. This may dispatch
+ already expired timeouts. */
+ silc_schedule_select_timeout(schedule);
+
+ /* Check if scheduler is valid */
+ if (schedule->valid == FALSE) {
+ SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_UNLOCK(schedule);
+ return FALSE;
+ }
+
+ if (timeout_usecs >= 0) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = timeout_usecs;
+ schedule->timeout = timeout;
+ schedule->has_timeout = TRUE;
+ }
+
+ /* This is the main silc_select(). The program blocks here until some
+ of the selected file descriptors change status or the selected
+ timeout expires. */
+ SILC_LOG_DEBUG(("Select"));
+ ret = schedule_ops.select(schedule, schedule->internal);
+
+ switch (ret) {
+ case 0:
+ /* Timeout */
+ SILC_LOG_DEBUG(("Running timeout tasks"));
+ silc_schedule_dispatch_timeout(schedule, FALSE);
+ break;
+ case -1:
+ /* Error */
+ if (errno == EINTR)
+ break;
+ SILC_LOG_ERROR(("Error in select(): %s", strerror(errno)));
+ break;
+ default:
+ /* There is some data available now */
+ SILC_LOG_DEBUG(("Running fd tasks"));
+ silc_schedule_dispatch_fd(schedule);
+ break;
+ }
+
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_UNLOCK(schedule);
+
+ return TRUE;
+}