X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=ucw%2Fmainloop.c;h=b2b07c5082476bedbdc023e094f49f6feb02a28b;hb=6efdc514c193f18c9ef840096750c37e78a01bf6;hp=de40fc5cabd72b38718f8fe748169c7bb41bbb4d;hpb=6abfdbaa3b7ca7f418c459fd7613e4a95d78800e;p=libucw.git diff --git a/ucw/mainloop.c b/ucw/mainloop.c index de40fc5c..b2b07c50 100644 --- a/ucw/mainloop.c +++ b/ucw/mainloop.c @@ -1,7 +1,7 @@ /* * UCW Library -- Main Loop * - * (c) 2004--2011 Martin Mares + * (c) 2004--2012 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -9,11 +9,13 @@ #undef LOCAL_DEBUG -#include "ucw/lib.h" -#include "ucw/heap.h" -#include "ucw/mainloop.h" -#include "ucw/threads.h" -#include "ucw/gary.h" +#include +#include +#include +#include +#include +#include +#include #include #include @@ -49,10 +51,7 @@ static void signal_del_ctx(struct main_context *m, struct main_signal *ms); static void main_get_time_ctx(struct main_context *m) { - struct timeval tv; - gettimeofday(&tv, NULL); - m->now_seconds = tv.tv_sec; - m->now = (timestamp_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; + m->now = get_timestamp(); } static struct main_context * @@ -100,7 +99,7 @@ main_new(void) m->epoll_fd = epoll_create(64); if (m->epoll_fd < 0) die("epoll_create() failed: %m"); - m->epoll_events = xmalloc(EPOLL_BUF_SIZE * sizeof(struct epoll_event *)); + m->epoll_events = xmalloc(EPOLL_BUF_SIZE * sizeof(struct epoll_event)); clist_init(&m->file_recalc_list); #else m->poll_table_obsolete = 1; @@ -124,7 +123,6 @@ main_prepare_delete(struct main_context *m) // Close epoll descriptor early enough, it might be shared after fork! #ifdef CONFIG_UCW_EPOLL - ASSERT(clist_empty(&m->file_recalc_list)); xfree(m->epoll_events); close(m->epoll_fd); m->epoll_fd = -1; @@ -166,6 +164,9 @@ main_delete(struct main_context *m) main_prepare_delete(m); ASSERT(clist_empty(&m->file_list)); ASSERT(clist_empty(&m->file_active_list)); +#ifdef CONFIG_UCW_EPOLL + ASSERT(clist_empty(&m->file_recalc_list)); +#endif ASSERT(clist_empty(&m->hook_list)); ASSERT(clist_empty(&m->hook_done_list)); ASSERT(clist_empty(&m->process_list)); @@ -177,7 +178,6 @@ main_delete(struct main_context *m) void main_destroy(struct main_context *m) { - // FIXME: Add a doc note on calling from a running mainloop if (!m) return; main_prepare_delete(m); @@ -305,9 +305,9 @@ file_want_events(struct main_file *fi) { uns events = 0; if (fi->read_handler) - events |= POLLIN | POLLHUP | POLLERR; + events |= POLLIN; if (fi->write_handler) - events |= POLLOUT | POLLERR; + events |= POLLOUT; return events; } @@ -317,7 +317,7 @@ file_add(struct main_file *fi) struct main_context *m = main_current(); DBG("MAIN: Adding file %p (fd=%d)", fi, fi->fd); - ASSERT(!clist_is_linked(&fi->n)); + ASSERT(!file_is_active(fi)); clist_add_tail(&m->file_list, &fi->n); m->file_cnt++; #ifdef CONFIG_UCW_EPOLL @@ -354,7 +354,8 @@ file_del_ctx(struct main_context *m, struct main_file *fi) // XXX: Can be called on a non-current context DBG("MAIN: Deleting file %p (fd=%d)", fi, fi->fd); - ASSERT(clist_is_linked(&fi->n)); + if (!file_is_active(fi)) + return; clist_unlink(&fi->n); m->file_cnt--; #ifdef CONFIG_UCW_EPOLL @@ -377,7 +378,8 @@ hook_add(struct main_hook *ho) struct main_context *m = main_current(); DBG("MAIN: Adding hook %p", ho); - ASSERT(!clist_is_linked(&ho->n)); + if (hook_is_active(ho)) + clist_unlink(&ho->n); clist_add_tail(&m->hook_list, &ho->n); } @@ -385,8 +387,8 @@ void hook_del(struct main_hook *ho) { DBG("MAIN: Deleting hook %p", ho); - ASSERT(clist_is_linked(&ho->n)); - clist_unlink(&ho->n); + if (hook_is_active(ho)) + clist_unlink(&ho->n); } static void @@ -418,7 +420,7 @@ process_add(struct main_process *mp) struct main_context *m = main_current(); DBG("MAIN: Adding process %p (pid=%d)", mp, mp->pid); - ASSERT(!clist_is_linked(&mp->n)); + ASSERT(!process_is_active(mp)); ASSERT(mp->handler); clist_add_tail(&m->process_list, &mp->n); if (!m->sigchld_handler) @@ -435,8 +437,8 @@ void process_del(struct main_process *mp) { DBG("MAIN: Deleting process %p (pid=%d)", mp, mp->pid); - ASSERT(clist_is_linked(&mp->n)); - clist_unlink(&mp->n); + if (process_is_active(mp)) + clist_unlink(&mp->n); } int @@ -542,7 +544,7 @@ signal_add(struct main_signal *ms) DBG("MAIN: Adding signal %p (sig=%d)", ms, ms->signum); - ASSERT(!clist_is_linked(&ms->n)); + ASSERT(!signal_is_active(ms)); // Adding at the head of the list is better if we are in the middle of walking the list. clist_add_head(&m->signal_list, &ms->n); if (m->sig_pipe_recv < 0) @@ -567,7 +569,8 @@ signal_del_ctx(struct main_context *m, struct main_signal *ms) // XXX: Can be called on a non-current context DBG("MAIN: Deleting signal %p (sig=%d)", ms, ms->signum); - ASSERT(clist_is_linked(&ms->n)); + if (!signal_is_active(ms)) + return; clist_unlink(&ms->n); int another = 0; @@ -593,48 +596,90 @@ signal_del(struct main_signal *ms) signal_del_ctx(main_current(), ms); } +#ifdef CONFIG_UCW_DEBUG + +void +file_debug(struct main_file *fi) +{ + msg(L_DEBUG, "\t\t%p (fd %d, rh %p, wh %p, data %p)", + fi, fi->fd, fi->read_handler, fi->write_handler, fi->data); +} + +void +hook_debug(struct main_hook *ho) +{ + msg(L_DEBUG, "\t\t%p (func %p, data %p)", ho, ho->handler, ho->data); +} + +void +signal_debug(struct main_signal *sg) +{ + if (sg->signum < 0) + msg(L_DEBUG, "\t\t(placeholder)"); + else + msg(L_DEBUG, "\t\t%p (sig %d, func %p, data %p)", sg, sg->signum, sg->handler, sg->data); +} + +static void +timer_debug_ctx(struct main_context *m, struct main_timer *tm) +{ + msg(L_DEBUG, "\t\t%p (expires %lld, data %p)", tm, (long long)(tm->expires - m->now), tm->data); +} + +void +timer_debug(struct main_timer *tm) +{ + timer_debug_ctx(main_current(), tm); +} + +void +process_debug(struct main_process *pr) +{ + msg(L_DEBUG, "\t\t%p (pid %d, func %p, data %p)", pr, pr->pid, pr->handler, pr->data); +} + void main_debug_context(struct main_context *m UNUSED) { -#ifdef CONFIG_DEBUG msg(L_DEBUG, "### Main loop status on %lld", (long long) m->now); msg(L_DEBUG, "\tActive timers:"); uns num_timers = count_timers(m); for (uns i = 1; i <= num_timers; i++) - { - struct main_timer *tm = m->timer_table[i]; - msg(L_DEBUG, "\t\t%p (expires %lld, data %p)", tm, (long long)(tm->expires ? tm->expires - m->now : 999999), tm->data); - } + timer_debug(m->timer_table[i]); msg(L_DEBUG, "\tActive files:"); CLIST_FOR_EACH(struct main_file *, fi, m->file_list) - msg(L_DEBUG, "\t\t%p (fd %d, rh %p, wh %p, data %p)", - fi, fi->fd, fi->read_handler, fi->write_handler, fi->data); + file_debug(fi); CLIST_FOR_EACH(struct main_file *, fi, m->file_active_list) - msg(L_DEBUG, "\t\t%p (fd %d, rh %p, wh %p, data %p) [pending events: %x]", - fi, fi->fd, fi->read_handler, fi->write_handler, fi->data, fi->events); - // FIXME: Can we display status of block_io requests somehow? + file_debug(fi); #ifdef CONFIG_UCW_EPOLL CLIST_FOR_EACH(struct main_file *, fi, m->file_recalc_list) - msg(L_DEBUG, "\t\t%p (fd %d, rh %p, wh %p, data %p) [pending recalculation]", - fi, fi->fd, fi->read_handler, fi->write_handler, fi->data); + file_debug(fi); #endif msg(L_DEBUG, "\tActive hooks:"); CLIST_FOR_EACH(struct main_hook *, ho, m->hook_done_list) - msg(L_DEBUG, "\t\t%p (func %p, data %p)", ho, ho->handler, ho->data); + hook_debug(ho); CLIST_FOR_EACH(struct main_hook *, ho, m->hook_list) - msg(L_DEBUG, "\t\t%p (func %p, data %p)", ho, ho->handler, ho->data); + hook_debug(ho); msg(L_DEBUG, "\tActive processes:"); CLIST_FOR_EACH(struct main_process *, pr, m->process_list) - msg(L_DEBUG, "\t\t%p (pid %d, func %p, data %p)", pr, pr->pid, pr->handler, pr->data); + process_debug(pr); msg(L_DEBUG, "\tActive signal catchers:"); CLIST_FOR_EACH(struct main_signal *, sg, m->signal_list) - if (sg->signum < 0) - msg(L_DEBUG, "\t\t(placeholder)"); - else - msg(L_DEBUG, "\t\t%p (sig %d, func %p, data %p)", sg, sg->signum, sg->handler, sg->data); -#endif + signal_debug(sg); } +#else + +// Stubs +void file_debug(struct main_file *fi UNUSED) { } +void hook_debug(struct main_hook *ho UNUSED) { } +void signal_debug(struct main_signal *sg UNUSED) { } +void timer_debug(struct main_timer *tm UNUSED) { } +void process_debug(struct main_process *pr UNUSED) { } +void main_debug_context(struct main_context *m UNUSED) { } + +#endif + static void process_timers(struct main_context *m) { @@ -666,7 +711,7 @@ process_hooks(struct main_context *m) hook_min == HOOK_DONE && hook_max == HOOK_DONE || m->shutdown) { - DBG("MAIN: Shut down by %s", m->shutdown ? "main_shutdown" : "a hook"); + DBG("MAIN: Shut down by %s", m->shutdown ? "main_shut_down" : "a hook"); return HOOK_SHUTDOWN; } if (hook_max == HOOK_RETRY) @@ -729,6 +774,8 @@ main_loop(void) struct main_context *m = main_current(); main_get_time_ctx(m); + m->shutdown = 0; + for (;;) { timestamp_t wake = m->now + 1000000000; @@ -742,10 +789,15 @@ main_loop(void) break; default: ; } - if (count_timers(m)) - wake = MIN(wake, m->timer_table[1]->expires); - main_get_time_ctx(m); - int timeout = ((wake > m->now) ? wake - m->now : 0); + + int timeout = 0; + if (!m->single_step) + { + if (count_timers(m)) + wake = MIN(wake, m->timer_table[1]->expires); + main_get_time_ctx(m); + timeout = ((wake > m->now) ? wake - m->now : 0); + } #ifdef CONFIG_UCW_EPOLL recalc_files(m); @@ -766,7 +818,12 @@ main_loop(void) m->idle_time += m->now - old_now; if (n <= 0) - continue; + { + if (m->single_step) + return; + else + continue; + } // Relink all files with a pending event to file_active_list #ifdef CONFIG_UCW_EPOLL @@ -801,17 +858,17 @@ main_loop(void) struct main_file *fi; while (fi = clist_head(&m->file_active_list)) { - if (fi->events & (POLLIN | POLLHUP | POLLERR)) + if (fi->read_handler && (fi->events & (POLLIN | POLLHUP))) { - fi->events &= ~(POLLIN | POLLHUP | POLLERR); + fi->events &= ~(POLLIN | POLLHUP); do DBG("MAIN: Read event on fd %d", fi->fd); while (fi->read_handler && fi->read_handler(fi)); continue; } - if (fi->events & (POLLOUT | POLLERR)) + if (fi->write_handler && (fi->events & (POLLOUT | POLLHUP | POLLERR))) { - fi->events &= ~(POLLOUT | POLLERR); + fi->events &= ~(POLLOUT | POLLHUP | POLLERR); do DBG("MAIN: Write event on fd %d", fi->fd); while (fi->write_handler && fi->write_handler(fi)); @@ -822,3 +879,12 @@ main_loop(void) } } } + +void +main_step(void) +{ + struct main_context *m = main_current(); + m->single_step = 1; + main_loop(); + m->single_step = 0; +}