X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=inline;f=lib%2Fmainloop.c;h=affc4aec8efa0845ca67b20b01816464a2125cec;hb=a71db29f49ca53affdec9bb557d386fbd2c04328;hp=c83c9262f0149951a70f46750b2c80ee18c8cb56;hpb=623ac4972bd717007ef7d672dbe9fb265e3f8a3a;p=libucw.git diff --git a/lib/mainloop.c b/lib/mainloop.c index c83c9262..affc4aec 100644 --- a/lib/mainloop.c +++ b/lib/mainloop.c @@ -1,7 +1,7 @@ /* - * Sherlock Library -- Main Loop + * UCW Library -- Main Loop * - * (c) 2004 Martin Mares + * (c) 2004--2006 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -22,8 +21,10 @@ #include #include #include +#include -sh_time_t now; +timestamp_t main_now; +sh_time_t main_now_seconds; uns main_shutdown; clist main_timer_list, main_file_list, main_hook_list, main_process_list; @@ -32,6 +33,16 @@ static uns main_poll_table_obsolete, main_poll_table_size; static struct pollfd *main_poll_table; static uns main_sigchld_set_up; +void +main_get_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + main_now_seconds = tv.tv_sec; + main_now = (timestamp_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; + // DBG("It's %Ld o'clock", (long long) main_now); +} + void main_init(void) { @@ -40,12 +51,18 @@ main_init(void) clist_init(&main_file_list); clist_init(&main_hook_list); clist_init(&main_process_list); - now = time(NULL); + main_file_cnt = 0; + main_poll_table_obsolete = 1; + main_get_time(); } void -timer_add(struct main_timer *tm, sh_time_t expires) +timer_add(struct main_timer *tm, timestamp_t expires) { + if (expires) + DBG("MAIN: Setting timer %p (expire at now+%Ld)", tm, (long long)(expires-main_now)); + else + DBG("MAIN: Clearing timer %p", tm); if (tm->expires) clist_remove(&tm->n); tm->expires = expires; @@ -76,6 +93,7 @@ file_timer_expired(struct main_timer *tm) void file_add(struct main_file *fi) { + DBG("MAIN: Adding file %p (fd=%d)", fi, fi->fd); ASSERT(!fi->n.next); clist_add_tail(&main_file_list, &fi->n); fi->timer.handler = file_timer_expired; @@ -103,6 +121,7 @@ file_chg(struct main_file *fi) void file_del(struct main_file *fi) { + DBG("MAIN: Deleting file %p (fd=%d)", fi, fi->fd); ASSERT(fi->n.next); timer_del(&fi->timer); clist_remove(&fi->n); @@ -198,15 +217,23 @@ file_write(struct main_file *fi, void *buf, uns len) } void -file_set_timeout(struct main_file *fi, sh_time_t expires) +file_set_timeout(struct main_file *fi, timestamp_t expires) { ASSERT(fi->n.next); timer_add(&fi->timer, expires); } +void +file_close_all(void) +{ + CLIST_FOR_EACH(struct main_file *, f, main_file_list) + close(f->fd); +} + void hook_add(struct main_hook *ho) { + DBG("MAIN: Adding hook %p", ho); ASSERT(!ho->n.next); clist_add_tail(&main_hook_list, &ho->n); } @@ -214,6 +241,7 @@ hook_add(struct main_hook *ho) void hook_del(struct main_hook *ho) { + DBG("MAIN: Deleting hook %p", ho); ASSERT(ho->n.next); clist_remove(&ho->n); ho->n.next = ho->n.prev = NULL; @@ -228,6 +256,7 @@ main_sigchld_handler(int x UNUSED) void process_add(struct main_process *mp) { + DBG("MAIN: Adding process %p (pid=%d)", mp, mp->pid); ASSERT(!mp->n.next); ASSERT(mp->handler); clist_add_tail(&main_process_list, &mp->n); @@ -245,16 +274,15 @@ process_add(struct main_process *mp) void process_del(struct main_process *mp) { + DBG("MAIN: Deleting process %p (pid=%d)", mp, mp->pid); ASSERT(mp->n.next); clist_remove(&mp->n); - mp->pid = 0; mp->n.next = NULL; } int process_fork(struct main_process *mp) { - ASSERT(!mp->pid); pid_t pid = fork(); if (pid < 0) { @@ -278,17 +306,18 @@ process_fork(struct main_process *mp) void main_debug(void) { -#ifdef DEBUG - log(L_DEBUG, "### Main loop status on %d", (int)now); +#ifdef CONFIG_DEBUG + log(L_DEBUG, "### Main loop status on %Ld", (long long)main_now); log(L_DEBUG, "\tActive timers:"); struct main_timer *tm; CLIST_WALK(tm, main_timer_list) - log(L_DEBUG, "\t\t%p (expires %d, data %p)", tm, (int)tm->expires, tm->data); + log(L_DEBUG, "\t\t%p (expires %Ld, data %p)", tm, (long long)(tm->expires ? tm->expires-main_now : 999999), tm->data); struct main_file *fi; log(L_DEBUG, "\tActive files:"); CLIST_WALK(fi, main_file_list) - log(L_DEBUG, "\t\t%p (fd %d, rh %p, wh %p, eh %p, expires %d, data %p)", - fi, fi->fd, fi->read_handler, fi->write_handler, fi->error_handler, fi->timer.expires, fi->data); + log(L_DEBUG, "\t\t%p (fd %d, rh %p, wh %p, eh %p, expires %Ld, data %p)", + fi, fi->fd, fi->read_handler, fi->write_handler, fi->error_handler, + (long long)(fi->timer.expires ? fi->timer.expires-main_now : 999999), fi->data); log(L_DEBUG, "\tActive hooks:"); struct main_hook *ho; CLIST_WALK(ho, main_hook_list) @@ -315,7 +344,7 @@ main_rebuild_poll_table(void) main_poll_table = xmalloc(sizeof(struct pollfd) * main_poll_table_size); } struct pollfd *p = main_poll_table; - DBG("MAIN: Rebuliding poll table: %d of %d entries set", main_file_cnt, main_poll_table_size); + DBG("MAIN: Rebuilding poll table: %d of %d entries set", main_file_cnt, main_poll_table_size); CLIST_WALK(fi, main_file_list) { p->fd = fi->fd; @@ -337,27 +366,40 @@ main_loop(void) struct main_process *pr; cnode *tmp; - while (!main_shutdown) + for (;;) { - now = time(NULL); - sh_time_t wake = now + 60; - while ((tm = clist_head(&main_timer_list)) && tm->expires <= now) + main_get_time(); + timestamp_t wake = main_now + 1000000000; + while ((tm = clist_head(&main_timer_list)) && tm->expires <= main_now) { - DBG("MAIN: Timer %p expired", tm); + DBG("MAIN: Timer %p expired at now-%Ld", tm, (long long)(main_now - tm->expires)); tm->handler(tm); } + int hook_min = HOOK_RETRY; + int hook_max = HOOK_SHUTDOWN; CLIST_WALK_DELSAFE(ho, main_hook_list, tmp) { DBG("MAIN: Hook %p", ho); - if (ho->handler(ho)) - wake = 0; + int ret = ho->handler(ho); + hook_min = MIN(hook_min, ret); + hook_max = MAX(hook_max, ret); + } + if (hook_min == HOOK_SHUTDOWN || + hook_min == HOOK_DONE && hook_max == HOOK_DONE || + main_shutdown) + { + DBG("MAIN: Shut down by %s", main_shutdown ? "main_shutdown" : "a hook"); + return; } + if (hook_max == HOOK_RETRY) + wake = 0; if (main_poll_table_obsolete) main_rebuild_poll_table(); if (!clist_empty(&main_process_list)) { int stat; pid_t pid; + wake = MIN(wake, main_now + 10000); while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { DBG("MAIN: Child %d exited with status %x", pid, stat); @@ -377,12 +419,12 @@ main_loop(void) /* FIXME: Here is a small race window where SIGCHLD can come unnoticed. */ if ((tm = clist_head(&main_timer_list)) && tm->expires < wake) wake = tm->expires; - int timeout = (wake ? (wake - now) * 1000 : 0); + int timeout = (wake ? wake - main_now : 0); DBG("MAIN: Poll for %d fds and timeout %d ms", main_file_cnt, timeout); if (poll(main_poll_table, main_file_cnt, timeout)) { struct pollfd *p = main_poll_table; - now = time(NULL); + main_get_time(); CLIST_WALK(fi, main_file_list) { if (p->revents & (POLLIN | POLLHUP | POLLERR)) @@ -450,14 +492,15 @@ static int dhook(struct main_hook *ho UNUSED) static void dtimer(struct main_timer *tm) { log(L_INFO, "Timer tick"); - timer_add(tm, now + 10); + timer_add(tm, main_now + 10000); } -static void dentry(struct main_process *pr UNUSED) +static void dentry(void) { log(L_INFO, "*** SUBPROCESS START ***"); sleep(2); log(L_INFO, "*** SUBPROCESS FINISH ***"); + exit(0); } static void dexit(struct main_process *pr) @@ -487,7 +530,7 @@ main(void) hook_add(&hook); tm.handler = dtimer; - timer_add(&tm, now + 1); + timer_add(&tm, main_now + 1000); mp.handler = dexit; if (!process_fork(&mp))