-/* 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 */ \
- silc_gettimeofday(&curtime); \
- 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; \
- if (queue->timeout.tv_sec < 0) \
- queue->timeout.tv_sec = 0; \
- \
- /* We wouldn't want to go under zero, check for it. */ \
- if (queue->timeout.tv_usec < 0) { \
- queue->timeout.tv_sec -= 1; \
- if (queue->timeout.tv_sec < 0) \
- queue->timeout.tv_sec = 0; \
- 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")); \
- silc_mutex_lock(schedule->lock); \
- 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))) { \
- silc_mutex_unlock(schedule->lock); \
- task->callback(queue, SILC_TASK_READ, \
- task->context, i); \
- silc_mutex_lock(schedule->lock); \
- } \
- } \
- \
- if (task->valid && schedule->fd_list.fd[i] != -1) { \
- /* Task ready for writing */ \
- if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_WRITE))) { \
- silc_mutex_unlock(schedule->lock); \
- task->callback(queue, SILC_TASK_WRITE, \
- task->context, i); \
- silc_mutex_lock(schedule->lock); \
- } \
- } \
- \
- 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; \
- } \
- } \
- } \
- } \
- silc_mutex_unlock(schedule->lock); \
- } \
-} while(0)
-
-bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
+#ifdef SILC_SYMBIAN
+ /* On symbian we wakeup scheduler immediately after adding timeout task
+ in case the task is added outside the scheduler loop (in some active
+ object). */
+ if (task && task->type == 1)
+ silc_schedule_wakeup(schedule);
+#endif /* SILC_SYMBIAN */
+
+ return task;
+}
+
+/* Invalidates task */
+
+SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task)
+{
+ SilcSchedule parent;
+
+ if (!schedule) {
+ schedule = silc_schedule_get_global();
+ SILC_VERIFY(schedule);
+ if (!schedule) {
+ silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+ return FALSE;
+ }
+ }
+
+ if (silc_unlikely(task == SILC_ALL_TASKS)) {
+ SilcHashTableList htl;
+
+ SILC_LOG_DEBUG(("Unregister all tasks"));
+
+ SILC_SCHEDULE_LOCK(schedule);
+
+ /* Delete from fd queue */
+ silc_hash_table_list(schedule->fd_queue, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&task)) {
+ task->valid = FALSE;
+
+ /* Call notify callback */
+ if (schedule->notify)
+ schedule->notify(schedule, FALSE, task, TRUE,
+ ((SilcTaskFd)task)->fd, 0, 0, 0,
+ schedule->notify_context);
+ }
+ silc_hash_table_list_reset(&htl);
+
+ /* Delete from timeout queue */
+ silc_list_start(schedule->timeout_queue);
+ while ((task = (SilcTask)silc_list_get(schedule->timeout_queue))) {
+ task->valid = FALSE;
+
+ /* Call notify callback */
+ if (schedule->notify)
+ schedule->notify(schedule, FALSE, task, FALSE, 0, 0, 0, 0,
+ schedule->notify_context);
+ }
+
+ /* Delete even tasks */
+ parent = silc_schedule_get_parent(schedule);
+ silc_hash_table_list(parent->events, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&task))
+ task->valid = FALSE;
+ silc_hash_table_list_reset(&htl);
+
+ SILC_SCHEDULE_UNLOCK(schedule);
+ return TRUE;
+ }
+
+ SILC_LOG_DEBUG(("Unregistering task %p, type %d", task, task->type));
+ SILC_SCHEDULE_LOCK(schedule);
+ task->valid = FALSE;
+
+ /* Call notify callback */
+ if (schedule->notify && task->type != SILC_TASK_EVENT)
+ schedule->notify(schedule, FALSE, task, task->type == SILC_TASK_FD,
+ 0, 0, 0, 0, schedule->notify_context);
+ SILC_SCHEDULE_UNLOCK(schedule);
+
+ if (task->type == SILC_TASK_EVENT) {
+ /* Schedule removal of deleted event task */
+ parent = silc_schedule_get_parent(schedule);
+ silc_schedule_task_add_timeout(parent, silc_schedule_event_del_timeout,
+ task, 0, 1);
+ }
+
+ return TRUE;
+}
+
+/* Invalidate task by fd */
+
+SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd)
+{
+ SilcTask task = NULL;
+ SilcBool ret = FALSE;
+
+ SILC_LOG_DEBUG(("Unregister task by fd %d", fd));
+
+ if (!schedule) {
+ schedule = silc_schedule_get_global();
+ SILC_VERIFY(schedule);
+ if (!schedule) {
+ silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+ return FALSE;
+ }
+ }
+
+ SILC_SCHEDULE_LOCK(schedule);
+
+ /* fd is unique, so there is only one task with this fd in the table */
+ if (silc_likely(silc_hash_table_find(schedule->fd_queue,
+ SILC_32_TO_PTR(fd), NULL,
+ (void *)&task))) {
+ SILC_LOG_DEBUG(("Deleting task %p", task));
+ task->valid = FALSE;
+
+ /* Call notify callback */
+ if (schedule->notify)
+ schedule->notify(schedule, FALSE, task, TRUE, fd, 0, 0, 0,
+ schedule->notify_context);
+ ret = TRUE;
+ }
+
+ SILC_SCHEDULE_UNLOCK(schedule);
+
+ /* If it is signal, remove it */
+ if (silc_unlikely(!task)) {
+ schedule_ops.signal_unregister(schedule, schedule->internal, fd);
+ ret = TRUE;
+ }
+
+ if (ret == FALSE)
+ silc_set_errno(SILC_ERR_NOT_FOUND);
+
+ return ret;
+}
+
+/* Invalidate task by task callback. */
+
+SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule,
+ SilcTaskCallback callback)