From: Martin Mares Date: Sat, 26 Feb 2011 11:11:16 +0000 (+0100) Subject: Main: Added main_teardown() and main_destroy() X-Git-Tag: v5.0~129^2~10 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=6abfdbaa3b7ca7f418c459fd7613e4a95d78800e;p=libucw.git Main: Added main_teardown() and main_destroy() There are now two possibilities how to get rid of a main loop context. Either you call main_delete(), which is gentle and fails whenever there are any active files/hooks/etc. Or you call main_destroy(), which forcibly removes all such objects; it also closes all files. main_teardown() just calls main_destroy() on the current context, just as main_cleanup() calls main_delete(). Also, file_close_all() is no longer available -- the only known use cases are after fork(), but closing files is no longer sufficient there. All calls to file_close_all() should be therefore replaced by main_teardown(). --- diff --git a/ucw/main-test.c b/ucw/main-test.c index 41b6b5c6..2cf10f63 100644 --- a/ucw/main-test.c +++ b/ucw/main-test.c @@ -68,6 +68,7 @@ static void dtimer(struct main_timer *tm) static void dentry(void) { log_fork(); + main_teardown(); msg(L_INFO, "*** SUBPROCESS START ***"); sleep(2); msg(L_INFO, "*** SUBPROCESS FINISH ***"); @@ -124,6 +125,7 @@ main(void) block_io_del(&fout); hook_del(&hook); signal_del(&sg); + timer_del(&tm); main_cleanup(); return 0; } diff --git a/ucw/mainloop.c b/ucw/mainloop.c index f0c94d56..de40fc5c 100644 --- a/ucw/mainloop.c +++ b/ucw/mainloop.c @@ -75,6 +75,15 @@ main_is_current(struct main_context *m) return (m == main_current_nocheck()); } +static inline uns +count_timers(struct main_context *m) +{ + if (m->timer_table) + return GARY_SIZE(m->timer_table) - 1; + else + return 0; +} + struct main_context * main_new(void) { @@ -103,8 +112,8 @@ main_new(void) return m; } -void -main_delete(struct main_context *m) +static void +main_prepare_delete(struct main_context *m) { /* * If the context is current, deactivate it first. But beware, @@ -113,6 +122,17 @@ main_delete(struct main_context *m) if (main_is_current(m)) main_switch_context(NULL); + // 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; +#else + GARY_FREE(m->poll_table); + GARY_FREE(m->poll_file_table); +#endif + if (m->sigchld_handler) { signal_del_ctx(m, m->sigchld_handler); @@ -128,22 +148,49 @@ main_delete(struct main_context *m) close(m->sig_pipe_recv); close(m->sig_pipe_send); } +} + +static void +main_do_delete(struct main_context *m) +{ + GARY_FREE(m->timer_table); + xfree(m); +} + +void +main_delete(struct main_context *m) +{ + if (!m) + return; + + main_prepare_delete(m); ASSERT(clist_empty(&m->file_list)); ASSERT(clist_empty(&m->file_active_list)); ASSERT(clist_empty(&m->hook_list)); ASSERT(clist_empty(&m->hook_done_list)); ASSERT(clist_empty(&m->process_list)); ASSERT(clist_empty(&m->signal_list)); - GARY_FREE(m->timer_table); + ASSERT(!count_timers(m)); + main_do_delete(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); + + // Close all files + clist_insert_list_after(&m->file_active_list, m->file_list.head.prev); #ifdef CONFIG_UCW_EPOLL - ASSERT(clist_empty(&m->file_recalc_list)); - xfree(m->epoll_events); - close(m->epoll_fd); -#else - GARY_FREE(m->poll_table); - GARY_FREE(m->poll_file_table); + clist_insert_list_after(&m->file_recalc_list, m->file_list.head.prev); #endif - xfree(m); + CLIST_FOR_EACH(struct main_file *, f, m->file_list) + close(f->fd); + + main_do_delete(m); } struct main_context * @@ -176,22 +223,19 @@ main_init(void) void main_cleanup(void) { - main_delete(main_current()); + main_delete(main_current_nocheck()); } void -main_get_time(void) +main_teardown(void) { - main_get_time_ctx(main_current()); + main_destroy(main_current_nocheck()); } -static inline uns -count_timers(struct main_context *m) +void +main_get_time(void) { - if (m->timer_table) - return GARY_SIZE(m->timer_table) - 1; - else - return 0; + main_get_time_ctx(main_current()); } void @@ -314,7 +358,7 @@ file_del_ctx(struct main_context *m, struct main_file *fi) clist_unlink(&fi->n); m->file_cnt--; #ifdef CONFIG_UCW_EPOLL - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, fi->fd, NULL) < 0) + if (m->epoll_fd >= 0 && epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, fi->fd, NULL) < 0) die("epoll_ctl() failed: %m"); #else m->poll_table_obsolete = 1; @@ -327,15 +371,6 @@ file_del(struct main_file *fi) file_del_ctx(main_current(), fi); } -void -file_close_all(void) -{ - struct main_context *m = main_current(); - - CLIST_FOR_EACH(struct main_file *, f, m->file_list) - close(f->fd); -} - void hook_add(struct main_hook *ho) { diff --git a/ucw/mainloop.h b/ucw/mainloop.h index f74057da..bf20de8b 100644 --- a/ucw/mainloop.h +++ b/ucw/mainloop.h @@ -58,11 +58,13 @@ struct main_context { struct main_context *main_new(void); void main_delete(struct main_context *m); +void main_destroy(struct main_context *m); struct main_context *main_switch_context(struct main_context *m); struct main_context *main_current(void); void main_init(void); void main_cleanup(void); +void main_teardown(void); /** * Start the mainloop. @@ -224,11 +226,6 @@ void file_chg(struct main_file *fi); * Can be called from a handler. **/ void file_del(struct main_file *fi); -/** - * Closes all file descriptors known to mainloop. Often used between fork() - * and exec(). - **/ -void file_close_all(void); struct main_block_io { struct main_file file;