]> mj.ucw.cz Git - libucw.git/commitdiff
Main: Added main_teardown() and main_destroy()
authorMartin Mares <mj@ucw.cz>
Sat, 26 Feb 2011 11:11:16 +0000 (12:11 +0100)
committerMartin Mares <mj@ucw.cz>
Sat, 26 Feb 2011 11:11:16 +0000 (12:11 +0100)
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().

ucw/main-test.c
ucw/mainloop.c
ucw/mainloop.h

index 41b6b5c6f3d36ed63f974a9f32d3259b537594de..2cf10f6373c276bbbe12071fccd68f32620026d7 100644 (file)
@@ -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;
 }
index f0c94d56c453192da2c4ad3c315acaa0e1d400cd..de40fc5cabd72b38718f8fe748169c7bb41bbb4d 100644 (file)
@@ -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)
 {
index f74057da29debf52d8666ce6937d1ad608538f98..bf20de8b0e55513d6728b27bd112dbb33ee2113c 100644 (file)
@@ -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;