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));
	}
Exemple #2
0
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);
}
Exemple #3
0
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
}
Exemple #4
0
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);
}
Exemple #5
0
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);
	}
}
Exemple #6
0
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;
			}
		}
	}
}
Exemple #7
0
/* 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);
}
Exemple #8
0
/*!
 * \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);
}
Exemple #9
0
void init_signals_helper() {
	clear_signals();
	signal(SIGINT, neci_sigint);
}
Exemple #10
0
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);
	}
}
Exemple #11
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);
}