X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcschedule.c;h=5ca563035b4aa6b3008d82a48e04da47628873ac;hp=af37e9fc10729166dfd591d78ed0d5e3bdae2d50;hb=413da0f8686910f5e627393157566ae729ca99c4;hpb=4a0081751a282b29d525b5f9a3312628aed24a2f diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c index af37e9fc..5ca56303 100644 --- a/lib/silcutil/silcschedule.c +++ b/lib/silcutil/silcschedule.c @@ -1,16 +1,15 @@ /* - silcschedule.c + silcschedule.c Author: Pekka Riikonen - Copyright (C) 1998 - 2001 Pekka Riikonen + Copyright (C) 1998 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -81,8 +80,6 @@ static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first); static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask, SilcTaskPriority priority); static int silc_schedule_task_remove(SilcTaskQueue queue, SilcTask task); -static int silc_schedule_task_timeout_compare(struct timeval *smaller, - struct timeval *bigger); static void silc_task_del_by_context(SilcTaskQueue queue, void *context); static void silc_task_del_by_callback(SilcTaskQueue queue, SilcTaskCallback callback); @@ -277,16 +274,16 @@ bool silc_schedule_uninit(SilcSchedule schedule) return FALSE; /* Dispatch all timeouts before going away */ + SILC_SCHEDULE_LOCK(schedule); silc_mutex_lock(schedule->timeout_queue->lock); silc_schedule_dispatch_timeout(schedule, TRUE); silc_mutex_unlock(schedule->timeout_queue->lock); + SILC_SCHEDULE_UNLOCK(schedule); /* Deliver signals before going away */ if (schedule->signal_tasks) { - SILC_SCHEDULE_UNLOCK(schedule); silc_schedule_internal_signals_call(schedule->internal, schedule); schedule->signal_tasks = FALSE; - SILC_SCHEDULE_LOCK(schedule); } /* Unregister all tasks */ @@ -345,18 +342,19 @@ void silc_schedule_stop(SilcSchedule schedule) static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule) { SilcTask task; - int i, last_fd = schedule->last_fd; - SilcUInt32 fd; + int i; + SilcUInt32 fd, last_fd = schedule->last_fd; + SilcUInt16 revents; for (i = 0; i <= last_fd; i++) { if (schedule->fd_list[i].events == 0) continue; - fd = schedule->fd_list[i].fd; - /* First check whether this fd has task in the fd queue */ silc_mutex_lock(schedule->fd_queue->lock); + fd = schedule->fd_list[i].fd; task = silc_task_find(schedule->fd_queue, fd); + revents = schedule->fd_list[i].revents; /* If the task was found then execute its callbacks. If not then execute all generic tasks for that fd. */ @@ -366,7 +364,7 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule) in the callback function, ie. it is not valid anymore. */ /* Is the task ready for reading */ - if (task->valid && schedule->fd_list[i].revents & SILC_TASK_READ) { + if (task->valid && revents & SILC_TASK_READ) { silc_mutex_unlock(schedule->fd_queue->lock); SILC_SCHEDULE_UNLOCK(schedule); task->callback(schedule, schedule->app_context, @@ -376,7 +374,7 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule) } /* Is the task ready for writing */ - if (task->valid && schedule->fd_list[i].revents & SILC_TASK_WRITE) { + if (task->valid && revents & SILC_TASK_WRITE) { silc_mutex_unlock(schedule->fd_queue->lock); SILC_SCHEDULE_UNLOCK(schedule); task->callback(schedule, schedule->app_context, @@ -402,12 +400,13 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule) task = schedule->generic_queue->task; while(1) { - /* Validity of the task is checked always before and after + /* Validity of the task and fd is checked always before and after execution beacuse the task might have been unregistered in the callback function, ie. it is not valid anymore. */ /* Is the task ready for reading */ - if (task->valid && schedule->fd_list[i].revents & SILC_TASK_READ) { + if (task->valid && revents & SILC_TASK_READ && + fd == schedule->fd_list[i].fd) { silc_mutex_unlock(schedule->generic_queue->lock); SILC_SCHEDULE_UNLOCK(schedule); task->callback(schedule, schedule->app_context, @@ -417,7 +416,8 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule) } /* Is the task ready for writing */ - if (task->valid && schedule->fd_list[i].revents & SILC_TASK_WRITE) { + if (task->valid && revents & SILC_TASK_WRITE && + fd == schedule->fd_list[i].fd) { silc_mutex_unlock(schedule->generic_queue->lock); SILC_SCHEDULE_UNLOCK(schedule); task->callback(schedule, schedule->app_context, @@ -479,7 +479,7 @@ static void silc_schedule_dispatch_timeout(SilcSchedule schedule, while(1) { /* Execute the task if the timeout has expired */ if (dispatch_all || - silc_schedule_task_timeout_compare(&task->timeout, &curtime)) { + silc_compare_timeval(&task->timeout, &curtime)) { if (task->valid) { silc_mutex_unlock(queue->lock); SILC_SCHEDULE_UNLOCK(schedule); @@ -533,7 +533,7 @@ static void silc_schedule_select_timeout(SilcSchedule schedule) 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_schedule_task_timeout_compare(&task->timeout, &curtime)) { + if (silc_compare_timeval(&task->timeout, &curtime)) { silc_schedule_dispatch_timeout(schedule, FALSE); /* The task(s) has expired and doesn't exist on the task queue @@ -721,9 +721,6 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, if (!schedule->valid) return NULL; - SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d", fd, - type, priority)); - queue = SILC_SCHEDULE_GET_QUEUE(type); /* If the task is generic task, we check whether this task has already @@ -732,6 +729,9 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, if (type == SILC_TASK_GENERIC) { silc_mutex_lock(queue->lock); + SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d", fd, + type, priority)); + if (queue->task) { SilcTask task = queue->task; while(1) { @@ -742,7 +742,7 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, /* Add the fd to be listened, the task found now applies to this fd as well. */ - silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ); + silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ, FALSE); return task; } @@ -757,6 +757,12 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, } newtask = silc_calloc(1, sizeof(*newtask)); + if (!newtask) + return NULL; + + SILC_LOG_DEBUG(("Registering new task %p, fd=%d type=%d priority=%d", + newtask, fd, type, priority)); + newtask->fd = fd; newtask->context = context; newtask->callback = callback; @@ -781,7 +787,7 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, /* If the task is non-timeout task we have to tell the scheduler that we would like to have these tasks scheduled at some odd distant future. */ if (type != SILC_TASK_TIMEOUT) - silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ); + silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ, FALSE); silc_mutex_lock(queue->lock); @@ -882,8 +888,8 @@ void silc_schedule_task_del_by_context(SilcSchedule schedule, void *context) call this directly if wanted. This can be called multiple times for one file descriptor to set different iomasks. */ -void silc_schedule_set_listen_fd(SilcSchedule schedule, - SilcUInt32 fd, SilcTaskEvent iomask) +void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd, + SilcTaskEvent mask, bool send_events) { int i; bool found = FALSE; @@ -896,10 +902,14 @@ void silc_schedule_set_listen_fd(SilcSchedule schedule, for (i = 0; i < schedule->max_fd; i++) if (schedule->fd_list[i].fd == fd) { schedule->fd_list[i].fd = fd; - schedule->fd_list[i].events = iomask; + schedule->fd_list[i].events = mask; if (i > schedule->last_fd) schedule->last_fd = i; found = TRUE; + if (send_events) { + schedule->fd_list[i].revents = mask; + silc_schedule_dispatch_nontimeout(schedule); + } break; } @@ -907,9 +917,13 @@ void silc_schedule_set_listen_fd(SilcSchedule schedule, for (i = 0; i < schedule->max_fd; i++) if (schedule->fd_list[i].events == 0) { schedule->fd_list[i].fd = fd; - schedule->fd_list[i].events = iomask; + schedule->fd_list[i].events = mask; if (i > schedule->last_fd) schedule->last_fd = i; + if (send_events) { + schedule->fd_list[i].revents = mask; + silc_schedule_dispatch_nontimeout(schedule); + } break; } @@ -1078,7 +1092,7 @@ static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first) if (first == prev) break; - if (silc_schedule_task_timeout_compare(&prev->timeout, &task->timeout)) + if (silc_compare_timeval(&prev->timeout, &task->timeout)) task = prev; prev = prev->prev; @@ -1111,13 +1125,11 @@ static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask, /* If we have longer timeout than with the task head of us we have found our spot. */ - if (silc_schedule_task_timeout_compare(&prev->timeout, - &newtask->timeout)) + if (silc_compare_timeval(&prev->timeout, &newtask->timeout)) break; /* If we are equal size of timeout we will be after it. */ - if (!silc_schedule_task_timeout_compare(&newtask->timeout, - &prev->timeout)) + if (!silc_compare_timeval(&newtask->timeout, &prev->timeout)) break; /* We have shorter timeout, compare to next one. */ @@ -1132,11 +1144,9 @@ static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask, if (prev == task) { /* Check if we are going to be the first task in the queue */ - if (silc_schedule_task_timeout_compare(&prev->timeout, - &newtask->timeout)) + if (silc_compare_timeval(&prev->timeout, &newtask->timeout)) break; - if (!silc_schedule_task_timeout_compare(&newtask->timeout, - &prev->timeout)) + if (!silc_compare_timeval(&newtask->timeout, &prev->timeout)) break; /* We are now the first task in queue */ @@ -1150,13 +1160,11 @@ static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask, /* If we have longer timeout than with the task head of us we have found our spot. */ - if (silc_schedule_task_timeout_compare(&prev->timeout, - &newtask->timeout)) + if (silc_compare_timeval(&prev->timeout, &newtask->timeout)) break; /* If we are equal size of timeout, priority kicks in place. */ - if (!silc_schedule_task_timeout_compare(&newtask->timeout, - &prev->timeout)) + if (!silc_compare_timeval(&newtask->timeout, &prev->timeout)) if (prev->priority >= SILC_TASK_PRI_NORMAL) break; @@ -1172,11 +1180,9 @@ static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask, if (prev == task) { /* Check if we are going to be the first task in the queue */ - if (silc_schedule_task_timeout_compare(&prev->timeout, - &newtask->timeout)) + if (silc_compare_timeval(&prev->timeout, &newtask->timeout)) break; - if (!silc_schedule_task_timeout_compare(&newtask->timeout, - &prev->timeout)) + if (!silc_compare_timeval(&newtask->timeout, &prev->timeout)) if (prev->priority >= SILC_TASK_PRI_NORMAL) break; @@ -1226,7 +1232,7 @@ static int silc_schedule_task_remove(SilcTaskQueue queue, SilcTask task) return TRUE; } - SILC_LOG_DEBUG(("Removing task")); + SILC_LOG_DEBUG(("Removing task %p", task)); /* Unregister the task */ old = first; @@ -1255,20 +1261,6 @@ static int silc_schedule_task_remove(SilcTaskQueue queue, SilcTask task) } } -/* Compare two time values. If the first argument is smaller than the - second this function returns TRUE. */ - -static int silc_schedule_task_timeout_compare(struct timeval *smaller, - struct timeval *bigger) -{ - if ((smaller->tv_sec < bigger->tv_sec) || - ((smaller->tv_sec == bigger->tv_sec) && - (smaller->tv_usec < bigger->tv_usec))) - return TRUE; - - return FALSE; -} - static void silc_task_del_by_fd(SilcTaskQueue queue, SilcUInt32 fd) { SilcTask next;