void DispatcherPrivate::run_steps() { int now = _wall.read_us(); TRACE(("run_steps(): starting, now=%i.\r\n", now)); clear_signals(); clear_normal_step(); run_tasks(StateCommited); #ifdef DISPATCH_DEBUG int tick_before = get_tick(); #endif // no commited nodes left, see if we have enough time for a normal loop for(;;) { int tdiff = wall_diff(now); if(tdiff >= _clock_multiplier) break; run_tasks(StateNormal | StateUrgent); DelayedThread::signal_wait(SIGNAL_CHANGED, (_clock_multiplier - tdiff) / 1000); } run_tasks(StateUrgent); TRACE(("Dispatcher wait end (diff=%i, tdiff=%i).\r\n", wall_diff(now), get_tick() - tick_before)); }
struct tmuxproc * proc_start(const char *name, struct event_base *base, int forkflag, void (*signalcb)(int)) { struct tmuxproc *tp; struct utsname u; #ifdef TMATE_SLAVE if (forkflag) fatal("can't fork"); #else if (forkflag) { switch (fork()) { case -1: fatal("fork failed"); case 0: break; default: return (NULL); } if (daemon(1, 0) != 0) fatal("daemon failed"); clear_signals(0); if (event_reinit(base) != 0) fatalx("event_reinit failed"); } log_open(name); #endif #ifdef HAVE_SETPROCTITLE setproctitle("%s (%s)", name, socket_path); #endif if (uname(&u) < 0) memset(&u, 0, sizeof u); log_debug("%s started (%ld): socket %s, protocol %d", name, (long)getpid(), socket_path, PROTOCOL_VERSION); log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release, u.version, event_get_version(), event_get_method()); tp = xcalloc(1, sizeof *tp); tp->name = xstrdup(name); #ifndef TMATE_SLAVE tp->signalcb = signalcb; set_signals(proc_signal_cb, tp); #endif return (tp); }
bool unix_post_minidump_callback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded) { // Copy minidump file path into fixed buffer in the app instance to avoid // heap allocations in a crash handler. // path format: <dump_dir>/<minidump_id>.dmp int dirPathLength = strlen(dump_dir); int idLength = strlen(minidump_id); // The path must not be truncated. llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); char * path = LLApp::instance()->getMiniDumpFilename(); S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; strncpy(path, dump_dir, remaining); remaining -= dirPathLength; path += dirPathLength; if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') { *path++ = '/'; --remaining; } if (remaining > 0) { strncpy(path, minidump_id, remaining); remaining -= idLength; path += idLength; strncpy(path, ".dmp", remaining); } llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; LLApp::runErrorHandler(); #ifndef LL_RELEASE_FOR_DOWNLOAD clear_signals(); return false; #else return true; #endif }
struct tmuxproc * proc_start(const char *name, struct event_base *base, int forkflag, void (*signalcb)(int)) { struct tmuxproc *tp; if (forkflag) { switch (fork()) { case -1: fatal("fork failed"); case 0: break; default: return (NULL); } if (daemon(1, 0) != 0) fatal("daemon failed"); clear_signals(0); if (event_reinit(base) != 0) fatalx("event_reinit failed"); } logfile(name); #ifdef HAVE_SETPROCTITLE setproctitle("%s (%s)", name, socket_path); #endif log_debug("%s started (%ld): socket %s, protocol %d", name, (long)getpid(), socket_path, PROTOCOL_VERSION); tp = xcalloc(1, sizeof *tp); tp->name = xstrdup(name); tp->signalcb = signalcb; set_signals(proc_signal_cb, tp); return (tp); }
enum cmd_retval cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c = cmdq->state.c; struct window_pane *wp = cmdq->state.tflag.wp; struct session *s = cmdq->state.tflag.s; struct winlink *wl = cmdq->state.tflag.wl; char *cmd; int old_fd, pipe_fd[2], null_fd; struct format_tree *ft; /* Destroy the old pipe. */ old_fd = wp->pipe_fd; if (wp->pipe_fd != -1) { bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; } /* If no pipe command, that is enough. */ if (args->argc == 0 || *args->argv[0] == '\0') return (CMD_RETURN_NORMAL); /* * With -o, only open the new pipe if there was no previous one. This * allows a pipe to be toggled with a single key, for example: * * bind ^p pipep -o 'cat >>~/output' */ if (args_has(self->args, 'o') && old_fd != -1) return (CMD_RETURN_NORMAL); /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { cmdq_error(cmdq, "socketpair error: %s", strerror(errno)); return (CMD_RETURN_ERROR); } /* Expand the command. */ ft = format_create(cmdq, 0); format_defaults(ft, c, s, wl, wp); cmd = format_expand_time(ft, args->argv[0], time(NULL)); format_free(ft); /* Fork the child. */ switch (fork()) { case -1: cmdq_error(cmdq, "fork error: %s", strerror(errno)); free(cmd); return (CMD_RETURN_ERROR); case 0: /* Child process. */ close(pipe_fd[0]); clear_signals(1); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); if (pipe_fd[1] != STDIN_FILENO) close(pipe_fd[1]); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); if (dup2(null_fd, STDOUT_FILENO) == -1) _exit(1); if (dup2(null_fd, STDERR_FILENO) == -1) _exit(1); if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) close(null_fd); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); _exit(1); default: /* Parent process. */ close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL, NULL, cmd_pipe_pane_error_callback, wp); bufferevent_enable(wp->pipe_event, EV_WRITE); setblocking(wp->pipe_fd, 0); free(cmd); return (CMD_RETURN_NORMAL); } }
void default_unix_signal_handler(int signum, siginfo_t *info, void *) { // Unix implementation of synchronous signal handler // This runs in the thread that threw the signal. // We do the somewhat sketchy operation of blocking in here until the error handler // has gracefully stopped the app. if (LLApp::sLogInSignal) { llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl; } switch (signum) { case SIGCHLD: if (LLApp::sLogInSignal) { llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl; } // Check result code for all child procs for which we've // registered callbacks THIS WILL NOT WORK IF SIGCHLD IS SENT // w/o killing the child (Go, launcher!) // TODO: Now that we're using SIGACTION, we can actually // implement the launcher behavior to determine who sent the // SIGCHLD even if it doesn't result in child termination if (LLApp::sChildMap.count(info->si_pid)) { LLApp::sChildMap[info->si_pid].mGotSigChild = TRUE; } LLApp::incSigChildCount(); return; case SIGABRT: // Abort just results in termination of the app, no funky error handling. if (LLApp::sLogInSignal) { llwarns << "Signal handler - Got SIGABRT, terminating" << llendl; } clear_signals(); raise(signum); return; case SIGINT: case SIGHUP: case SIGTERM: if (LLApp::sLogInSignal) { llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl; } // Graceful exit // Just set our state to quitting, not error if (LLApp::isQuitting() || LLApp::isError()) { // We're already trying to die, just ignore this signal if (LLApp::sLogInSignal) { llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; } return; } LLApp::setQuitting(); return; case SIGALRM: case SIGPIPE: case SIGUSR2: default: if (signum == LL_SMACKDOWN_SIGNAL || signum == SIGBUS || signum == SIGILL || signum == SIGFPE || signum == SIGSEGV || signum == SIGQUIT) { if (signum == LL_SMACKDOWN_SIGNAL) { // Smackdown treated just like any other app termination, for now if (LLApp::sLogInSignal) { llwarns << "Signal handler - Handling smackdown signal!" << llendl; } else { // Don't log anything, even errors - this is because this signal could happen anywhere. LLError::setDefaultLevel(LLError::LEVEL_NONE); } // Change the signal that we reraise to SIGABRT, so we generate a core dump. signum = SIGABRT; } if (LLApp::sLogInSignal) { llwarns << "Signal handler - Handling fatal signal!" << llendl; } if (LLApp::isError()) { // Received second fatal signal while handling first, just die right now // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app. clear_signals(); if (LLApp::sLogInSignal) { llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl; } raise(signum); return; } if (LLApp::sLogInSignal) { llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl; } if(LLApp::sDisableCrashlogger) //Don't gracefully handle any signals crash and core for a gdb post mortum { clear_signals(); llwarns << "Fatal signal received, not handling the crash here, passing back to operating system" << llendl; raise(signum); return; } // Flag status to ERROR, so thread_error does its work. LLApp::setError(); // Block in the signal handler until somebody says that we're done. while (LLApp::sErrorThreadRunning && !LLApp::isStopped()) { ms_sleep(10); } if (LLApp::sLogInSignal) { llwarns << "Signal handler - App is stopped, reraising signal" << llendl; } clear_signals(); raise(signum); return; } else { if (LLApp::sLogInSignal) { llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl; } } } }
/* Start a job running, if it isn't already. */ struct job * job_run(const char *cmd, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; struct environ env; pid_t pid; int nullfd, out[2]; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) return (NULL); environ_init(&env); environ_copy(&global_environ, &env); server_fill_environ(NULL, &env); switch (pid = fork()) { case -1: environ_free(&env); return (NULL); case 0: /* child */ clear_signals(1); environ_push(&env); environ_free(&env); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); if (out[1] != STDOUT_FILENO) close(out[1]); close(out[0]); nullfd = open(_PATH_DEVNULL, O_RDWR, 0); if (nullfd < 0) fatal("open failed"); if (dup2(nullfd, STDIN_FILENO) == -1) fatal("dup2 failed"); if (dup2(nullfd, STDERR_FILENO) == -1) fatal("dup2 failed"); if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) close(nullfd); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); fatal("execl failed"); } /* parent */ environ_free(&env); close(out[1]); job = xmalloc(sizeof *job); job->cmd = xstrdup(cmd); job->pid = pid; job->status = 0; LIST_INSERT_HEAD(&all_jobs, job, lentry); job->callbackfn = callbackfn; job->freefn = freefn; job->data = data; job->fd = out[0]; setblocking(job->fd, 0); job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job); bufferevent_enable(job->event, EV_READ); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); return (job); }
/*! * \brief Obtain a backtrace and print it to stdout. * * If GDB can be used to get a backtrace then we use it, otherwise and only * if TA3D_BUILTIN_BACKTRACE_SUPPORT is defined, a backtrace is obtained * then writen into a log file. It will be displayed in stdout when gdb is missing. * After this call, the program will exit with a exit status code equals * to `-1`. * * \param signum Which signal was received */ void backtrace_handler (int signum) { // Some functions called at exit may crash, so we must disable signals in order // to prevent overwriting a useful log clear_signals(); // Get TA3D's PID pid_t mypid = getpid(); // Try to get a stack trace from GDB String::Vector threads; TA3D::System::run_command(String("gdb --pid=") << mypid << " -ex \"info threads\" --batch").split(threads, "\n"); if (!threads.empty()) { String cmd; cmd << "gdb --pid=" << mypid << " -ex \"info threads\""; for(size_t i = 0 ; i < threads.size() ; ++i) { String &line = threads[i]; if (line.startsWith('[') || line.startsWith("0x") || line.startsWith('#')) continue; if (line.startsWith('*')) { line[0] = ' '; line.trimLeft(' '); } const int id = line.to<int>(); if (id <= 0) continue; cmd << " -ex \"thread " << id << "\" -ex bt"; } cmd << " --batch"; const String trace = TA3D::System::run_command(cmd); if (!trace.empty()) { bug_reporter(trace); exit(-1); } } // If GDB is not available or returned an error we must find another way ... this is now platform dependent # ifdef TA3D_BUILTIN_BACKTRACE_SUPPORT // Retrieving a backtrace void *array[400]; int size = backtrace (array, 400); char** strings = backtrace_symbols(array, size); // Try to log it Yuni::Core::IO::File::Stream m_File(String(TA3D::Paths::Logs) << "backtrace.txt", Yuni::Core::IO::OpenMode::write); if(m_File.opened()) { m_File << "received signal " << strsignal( signum ) << "\n"; m_File << "Obtained " << size << " stack frames.\n"; for (int i = 0; i < size; ++i) m_File << strings[i] << "\n"; m_File.flush(); m_File.close(); printf("received signal %s\n", strsignal( signum )); printf ("Obtained %d stack frames.\n", static_cast<int>(size)); for (int i = 0; i < size; ++i) printf ("%s\n", strings[i]); String szErrReport; szErrReport << "An error has occured.\nDebugging information have been logged to:\n" << TA3D::Paths::Logs << "backtrace.txt\nPlease report to our forums (http://www.ta3d.org/)\nand keep this file, it'll help us debugging.\n"; criticalMessage(szErrReport); } else { // The file is not opened // The backtrace will be directly to stdout instead. printf("received signal %s\n", strsignal(signum)); printf("couldn't open file for writing!!\n"); printf ("Obtained %d stack frames.\n", static_cast<int>(size)); for (int i = 0; i < size; ++i) printf ("%s\n", strings[i]); } free(strings); # else // ifdef TA3D_BUILTIN_BACKTRACE_SUPPORT // The backtrace support is disabled: warns the user String szErrReport = "An error has occured.\nDebugging information could not be logged.\nPlease report to our forums (http://www.ta3d.org/) so we can fix it."; criticalMessage(szErrReport); # endif // ifdef TA3D_BUILTIN_BACKTRACE_SUPPORT exit(-1); }
void init_signals_helper() { clear_signals(); signal(SIGINT, neci_sigint); }
int cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; struct window_pane *wp; char *command; int old_fd, pipe_fd[2], null_fd; if ((c = cmd_find_client(ctx, NULL)) == NULL) return (-1); if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); /* Destroy the old pipe. */ old_fd = wp->pipe_fd; if (wp->pipe_fd != -1) { bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; } /* If no pipe command, that is enough. */ if (args->argc == 0 || *args->argv[0] == '\0') return (0); /* * With -o, only open the new pipe if there was no previous one. This * allows a pipe to be toggled with a single key, for example: * * bind ^p pipep -o 'cat >>~/output' */ if (args_has(self->args, 'o') && old_fd != -1) return (0); /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { ctx->error(ctx, "socketpair error: %s", strerror(errno)); return (-1); } /* Fork the child. */ switch (fork()) { case -1: ctx->error(ctx, "fork error: %s", strerror(errno)); return (-1); case 0: /* Child process. */ close(pipe_fd[0]); clear_signals(1); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); if (pipe_fd[1] != STDIN_FILENO) close(pipe_fd[1]); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); if (dup2(null_fd, STDOUT_FILENO) == -1) _exit(1); if (dup2(null_fd, STDERR_FILENO) == -1) _exit(1); if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) close(null_fd); closefrom(STDERR_FILENO + 1); command = status_replace( c, NULL, NULL, NULL, args->argv[0], time(NULL), 0); execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); _exit(1); default: /* Parent process. */ close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL, NULL, cmd_pipe_pane_error_callback, wp); bufferevent_enable(wp->pipe_event, EV_WRITE); setblocking(wp->pipe_fd, 0); return (0); } }
/* Start a job running, if it isn't already. */ struct job * job_run(const char *cmd, struct session *s, const char *cwd, job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb, void *data) { struct job *job; struct environ *env; pid_t pid; int nullfd, out[2]; const char *home; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) return (NULL); /* * Do not set TERM during .tmux.conf, it is nice to be able to use * if-shell to decide on default-terminal based on outside TERM. */ env = environ_for_session(s, !cfg_finished); switch (pid = fork()) { case -1: environ_free(env); close(out[0]); close(out[1]); return (NULL); case 0: /* child */ clear_signals(1); if (cwd == NULL || chdir(cwd) != 0) { if ((home = find_home()) == NULL || chdir(home) != 0) chdir("/"); } environ_push(env); environ_free(env); if (dup2(out[1], STDIN_FILENO) == -1) fatal("dup2 failed"); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO) close(out[1]); close(out[0]); nullfd = open(_PATH_DEVNULL, O_RDWR, 0); if (nullfd < 0) fatal("open failed"); if (dup2(nullfd, STDERR_FILENO) == -1) fatal("dup2 failed"); if (nullfd != STDERR_FILENO) close(nullfd); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); fatal("execl failed"); } /* parent */ environ_free(env); close(out[1]); job = xmalloc(sizeof *job); job->state = JOB_RUNNING; job->cmd = xstrdup(cmd); job->pid = pid; job->status = 0; LIST_INSERT_HEAD(&all_jobs, job, entry); job->updatecb = updatecb; job->completecb = completecb; job->freecb = freecb; job->data = data; job->fd = out[0]; setblocking(job->fd, 0); job->event = bufferevent_new(job->fd, job_read_callback, job_write_callback, job_error_callback, job); bufferevent_enable(job->event, EV_READ|EV_WRITE); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); return (job); }