+ m->now_seconds = tv.tv_sec;
+ m->now = (timestamp_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+static struct main_context *
+main_current_nocheck(void)
+{
+ return ucwlib_thread_context()->main_context;
+}
+
+struct main_context *
+main_current(void)
+{
+ struct main_context *m = main_current_nocheck();
+ ASSERT(m);
+ return m;
+}
+
+static int
+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)
+{
+ struct main_context *m = xmalloc_zero(sizeof(*m));
+
+ DBG("MAIN: New context");
+ clist_init(&m->file_list);
+ clist_init(&m->file_active_list);
+ clist_init(&m->hook_list);
+ clist_init(&m->hook_done_list);
+ clist_init(&m->process_list);
+ clist_init(&m->signal_list);
+#ifdef CONFIG_UCW_EPOLL
+ 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 *));
+ clist_init(&m->file_recalc_list);
+#else
+ m->poll_table_obsolete = 1;
+#endif
+ main_get_time_ctx(m);
+ sigemptyset(&m->want_signals);
+ m->sig_pipe_recv = m->sig_pipe_send = -1;
+
+ return m;
+}
+
+static void
+main_prepare_delete(struct main_context *m)
+{
+ /*
+ * If the context is current, deactivate it first. But beware,
+ * we must not call functions that depend on the current context.
+ */
+ if (main_is_current(m))
+ main_switch_context(NULL);
+
+ // Close epoll descriptor early enough, it might be shared after fork!
+#ifdef CONFIG_UCW_EPOLL
+ 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);
+ xfree(m->sigchld_handler);
+ }
+ if (m->sig_pipe_file)
+ {
+ file_del_ctx(m, m->sig_pipe_file);
+ xfree(m->sig_pipe_file);
+ }
+ if (m->sig_pipe_recv >= 0)
+ {
+ 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));
+#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));
+ ASSERT(clist_empty(&m->signal_list));
+ ASSERT(!count_timers(m));
+ main_do_delete(m);
+}
+
+void
+main_destroy(struct main_context *m)
+{
+ 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
+ clist_insert_list_after(&m->file_recalc_list, m->file_list.head.prev);
+#endif
+ CLIST_FOR_EACH(struct main_file *, f, m->file_list)
+ close(f->fd);
+
+ main_do_delete(m);
+}
+
+struct main_context *
+main_switch_context(struct main_context *m)
+{
+ struct ucwlib_context *c = ucwlib_thread_context();
+ struct main_context *m0 = c->main_context;
+
+ /*
+ * Not only we need to switch the signal sets of the two contexts,
+ * but it is also necessary to avoid invoking a signal handler
+ * in the middle of changing c->main_context.
+ */
+ if (m0 && !clist_empty(&m0->signal_list))
+ THREAD_SIGMASK(SIG_BLOCK, &m0->want_signals, NULL);
+ c->main_context = m;
+ if (m && !clist_empty(&m->signal_list))
+ THREAD_SIGMASK(SIG_UNBLOCK, &m->want_signals, NULL);
+
+ return m0;