static void keep_alive_finalize(JSFreeOp *fop, JSObject *obj) { KeepAlive *priv; void *key; void *value; priv = (KeepAlive *) JS_GetPrivate(obj); gjs_debug_lifecycle(GJS_DEBUG_KEEP_ALIVE, "keep_alive finalizing, obj %p priv %p", obj, priv); if (priv == NULL) return; /* we are the prototype, not a real instance */ priv->inside_finalize = true; while (gjs_g_hash_table_steal_one(priv->children, &key, &value)) { Child *child = (Child *) value; if (child->notify) (* child->notify) (child->child, child->data); child_free(child); } g_hash_table_destroy(priv->children); g_slice_free(KeepAlive, priv); }
static void keep_alive_finalize(JSContext *context, JSObject *obj) { KeepAlive *priv; void *key; void *value; priv = priv_from_js(context, obj); gjs_debug_lifecycle(GJS_DEBUG_KEEP_ALIVE, "keep_alive finalizing, obj %p priv %p", obj, priv); if (priv == NULL) return; /* we are the prototype, not a real instance, so constructor never called */ priv->inside_finalize = TRUE; while (gjs_g_hash_table_steal_one(priv->children, &key, &value)) { Child *child = value; if (child->notify) (* child->notify) (child->child, child->data); child_free(child); } g_hash_table_destroy(priv->children); g_slice_free(KeepAlive, priv); }
gboolean mainloop_child_kill(pid_t pid) { GListPtr iter; mainloop_child_t *child = NULL; for (iter = child_list; iter != NULL; iter = iter->next) { child = iter->data; if (pid == child->pid) { break; } } if (child == NULL) { return FALSE; } if (child_kill_helper(child) != 0) { /* failed to terminate child process */ return FALSE; } /* It is impossible to block SIGKILL, this allows us to * call waitpid without WNOHANG here */ if (child_waitpid(child, 0) == FALSE) { /* not much we can do if this occurs */ return FALSE; } child_list = g_list_remove(child_list, child); child_free(child); return TRUE; }
static void mta_shutdown(void) { #ifdef VALGRIND child_free(); free_peers(); clean_setproctitle(); event_base_free(NULL); #endif log_info("mail transfer agent exiting"); _exit(0); }
int mainloop_child_kill(pid_t pid) { GListPtr iter; mainloop_child_t *child = NULL; mainloop_child_t *match = NULL; /* It is impossible to block SIGKILL, this allows us to * call waitpid without WNOHANG flag.*/ int waitflags = 0, rc = 0; for (iter = child_list; iter != NULL && match == NULL; iter = iter->next) { child = iter->data; if (pid == child->pid) { match = child; } } if (match == NULL) { return FALSE; } rc = child_kill_helper(match); if(rc == -ESRCH) { /* Its gone, but hasn't shown up in waitpid() yet * * Wait until we get SIGCHLD and let child_death_dispatch() * clean it up as normal (so we get the correct return * code/status) * * The blocking alternative would be to call: * child_waitpid(match, 0); */ crm_trace("Waiting for child %d to be reaped by child_death_dispatch()", match->pid); return TRUE; } else if(rc != 0) { /* If KILL for some other reason set the WNOHANG flag since we * can't be certain what happened. */ waitflags = WNOHANG; } if (child_waitpid(match, waitflags) == FALSE) { /* not much we can do if this occurs */ return FALSE; } child_list = g_list_remove(child_list, match); child_free(match); return TRUE; }
static void control_shutdown(void) { #ifdef VALGRIND child_free(); free_peers(); clean_setproctitle(); event_base_free(NULL); #endif log_info("control process exiting"); unlink(SMTPD_SOCKET); _exit(0); }
static void child_death_dispatch(int signal) { GListPtr iter = child_list; gboolean exited; while(iter) { GListPtr saved = NULL; mainloop_child_t *child = iter->data; exited = child_waitpid(child, WNOHANG); saved = iter; iter = iter->next; if (exited == FALSE) { continue; } crm_trace("Removing process entry %p for %d", child, child->pid); child_list = g_list_remove_link(child_list, saved); g_list_free(saved); child_free(child); } }
int main(int argc, char *argv[]) { int backlog = 10; muxer_t *muxers[2] = {NULL, NULL}; status_writer_t *sw = NULL; child_t *child = NULL; int child_status = -1; int ring_buffer_size = 65535; int fds[3] = {-1, -1, -1}; int ii = 0, exit_status = 0, nwritten = 0; pthread_t sw_thread, muxer_threads[2]; char socket_paths[3][PATH_MAX + 1]; char *socket_names[3] = { "stdout.sock", "stderr.sock", "status.sock" }; barrier_t *barrier = NULL; if (argc < 3) { fprintf(stderr, "Usage: %s <socket directory> <cmd>\n", argv[0]); exit(EXIT_FAILURE); } /* Setup listeners on domain sockets */ for (ii = 0; ii < 3; ++ii) { memset(socket_paths[ii], 0, sizeof(socket_paths[ii])); nwritten = snprintf(socket_paths[ii], sizeof(socket_paths[ii]), "%s/%s", argv[1], socket_names[ii]); if (nwritten >= sizeof(socket_paths[ii])) { fprintf(stderr, "Socket path too long\n"); exit_status = 1; goto cleanup; } fds[ii] = create_unix_domain_listener(socket_paths[ii], backlog); DLOG("created listener, path=%s fd=%d", socket_paths[ii], fds[ii]); if (-1 == fds[ii]) { perrorf("Failed creating socket at %s:", socket_paths[ii]); exit_status = 1; goto cleanup; } set_cloexec(fds[ii]); } child = child_create(argv + 2, argc - 2); printf("child_pid=%d\n", child->pid); fflush(stdout); /* Muxers for stdout/stderr */ muxers[0] = muxer_alloc(fds[0], child->stdout[0], ring_buffer_size); muxers[1] = muxer_alloc(fds[1], child->stderr[0], ring_buffer_size); for (ii = 0; ii < 2; ++ii) { if (pthread_create(&muxer_threads[ii], NULL, run_muxer, muxers[ii])) { perrorf("Failed creating muxer thread:"); exit_status = 1; goto cleanup; } DLOG("created muxer thread for socket=%s", socket_paths[ii]); } /* Status writer */ barrier = barrier_alloc(); sw = status_writer_alloc(fds[2], barrier); if (pthread_create(&sw_thread, NULL, run_status_writer, sw)) { perrorf("Failed creating muxer thread:"); exit_status = 1; goto cleanup; } /* Wait for clients on stdout, stderr, and status */ for (ii = 0; ii < 2; ++ii) { muxer_wait_for_client(muxers[ii]); } barrier_wait(barrier); child_continue(child); printf("child active\n"); fflush(stdout); if (-1 == waitpid(child->pid, &child_status, 0)) { perrorf("Waitpid for child failed: "); exit_status = 1; goto cleanup; } DLOG("child exited, status = %d", WEXITSTATUS(child_status)); /* Wait for status writer */ status_writer_finish(sw, child_status); pthread_join(sw_thread, NULL); /* Wait for muxers */ for (ii = 0; ii < 2; ++ii) { muxer_stop(muxers[ii]); pthread_join(muxer_threads[ii], NULL); } DLOG("all done, cleaning up and exiting"); cleanup: if (NULL != child) { child_free(child); } if (NULL != barrier) { barrier_free(barrier); } if (NULL != sw) { status_writer_free(sw); } for (ii = 0; ii < 2; ++ii) { if (NULL != muxers[ii]) { muxer_free(muxers[ii]); } } /* Close accept sockets and clean up paths */ for (ii = 0; ii < 3; ++ii) { if (-1 != fds[ii]) { close(fds[ii]); unlink(socket_paths[ii]); } } return exit_status; }