Restart on crash

This commit is contained in:
o9000 2016-01-03 18:03:36 +01:00
parent 69f6f65db6
commit cd863c2819
6 changed files with 194 additions and 11 deletions

View file

@ -28,6 +28,7 @@
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
#include <unistd.h>
#include "systraybar.h"
#include "server.h"

View file

@ -34,6 +34,8 @@
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <time.h>
#include <sys/time.h>
#ifdef HAVE_SN
#include <libsn/sn.h>
@ -75,6 +77,7 @@ XSettingsClient *xsettings_client = NULL;
timeout *detect_compositor_timer = NULL;
int detect_compositor_timer_counter = 0;
double start_time = 0;
void detect_compositor(void *arg)
{
@ -185,14 +188,9 @@ const char *get_home_dir()
return pw->pw_dir;
}
void crash_handler(int sig)
void dump_backtrace(int log_fd)
{
char path[4096];
sprintf(path, "%s/.tint2-crash.log", get_home_dir());
int log_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0600);
log_string(log_fd, "Crashing with signal ");
log_string(log_fd, signal_name(sig));
log_string(log_fd, "\nBacktrace:\n");
log_string(log_fd, YELLOW "\nBacktrace:\n");
#ifdef ENABLE_LIBUNWIND
unw_cursor_t cursor;
@ -225,7 +223,61 @@ void crash_handler(int sig)
log_string(log_fd, "Backtrace not supported on this system. Install libunwind or libexecinfo.\n");
#endif
#endif
_exit(sig);
log_string(log_fd, RESET);
}
// sleep() returns early when signals arrive. This function does not.
void safe_sleep(int seconds)
{
double t0 = get_time();
while (1) {
double t = get_time();
if (t > t0 + seconds)
return;
sleep(1);
}
}
void reexecute_tint2()
{
write_string(2, GREEN "Attempting to restart tint2...\n" RESET);
// If tint2 cannot stay stable for 30 seconds, don't restart
if (get_time() - start_time < 30) {
write_string(2, GREEN "Not restarting tint2 since the uptime is too small.\n" RESET);
exit(-1);
}
safe_sleep(1);
close_all_fds();
char *path = get_own_path();
execlp(path, path, "-c", config_path, NULL);
exit(-1);
}
void crash_handler(int sig)
{
// We are going to crash, so restart the panel
char path[4096];
sprintf(path, "%s/.tint2-crash.log", get_home_dir());
int log_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0600);
log_string(log_fd, RED "tint2 crashed with signal " RESET);
log_string(log_fd, signal_name(sig));
dump_backtrace(log_fd);
log_string(log_fd, RED "Please create a bug report with this log output.\n" RESET);
close(log_fd);
reexecute_tint2();
}
void x11_io_error(Display *display)
{
// We are going to crash, so restart the panel
char path[4096];
sprintf(path, "%s/.tint2-crash.log", get_home_dir());
int log_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0600);
log_string(log_fd, RED "tint2 crashed due to an X11 I/O error" RESET);
dump_backtrace(log_fd);
log_string(log_fd, RED "Please create a bug report with this log output.\n" RESET);
close(log_fd);
reexecute_tint2();
}
void init(int argc, char *argv[])
@ -373,6 +425,7 @@ void init_X11_pre_config()
exit(1);
}
XSetErrorHandler((XErrorHandler)server_catch_error);
XSetIOErrorHandler((XIOErrorHandler)x11_io_error);
server_init_atoms();
server.screen = DefaultScreen(server.display);
server.root_win = RootWindow(server.display, server.screen);
@ -1387,6 +1440,8 @@ void dnd_drop(XClientMessageEvent *e)
int main(int argc, char *argv[])
{
start:
start_time = get_time();
init(argc, argv);
init_X11_pre_config();

View file

@ -32,6 +32,13 @@
#include "common.h"
#include "../server.h"
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include <sys/sysctl.h>
#ifdef HAVE_RSVG
#include <librsvg/rsvg.h>
@ -620,3 +627,112 @@ GList *g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data)
return list;
}
#endif
// Based loosely on close_allv from
// https://git.gnome.org/browse/glib/tree/gio/libasyncns/asyncns.c?h=2.21.0#n205
// license: LGPL version 2.1
// but with all the junk removed
// and
// https://opensource.apple.com/source/sudo/sudo-46/src/closefrom.c
// license: BSD
void close_all_fds()
{
const int from_fd = 3;
#ifdef __linux__
DIR *d = opendir("/proc/self/fd");
if (d) {
for (struct dirent *de = readdir(d); de; de = readdir(d)) {
if (de->d_name[0] == '.')
continue;
int fd = atoi(de->d_name);
if (fd < from_fd)
continue;
if (fd == dirfd(d))
continue;
close(fd);
}
closedir(d);
return;
}
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
closefrom(from_fd);
return;
#endif
#if defined(__NetBSD__)
fcntl(from_fd, F_CLOSEM, 0);
#endif
// Worst case scenario: iterate over all possible fds
int max_fd = sysconf(_SC_OPEN_MAX);
for (int fd = from_fd; fd < max_fd; fd++) {
close(fd);
}
return;
}
char* get_own_path()
{
const int buf_size = 4096;
char *buf = calloc(buf_size, 1);
#ifdef __linux__
if (readlink("/proc/self/exe", buf, buf_size) > 0)
return buf;
#endif
#if defined(__FreeBSD__)
int mib[4] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PATHNAME,
getpid()
};
size_t max_len = buf_size;
if (sysctl(mib, 4, buf, &max_len, NULL, 0) == 0)
return buf;
#endif
#if defined(__DragonFly__)
if (readlink("/proc/curproc/file", buf, buf_size) > 0)
return buf;
#endif
#if defined(__NetBSD__)
if (readlink("/proc/curproc/exe", buf, buf_size) > 0)
return buf;
#endif
#if defined(__OpenBSD__)
int mib[4] = {
CTL_KERN,
KERN_PROC_ARGS,
getpid(),
KERN_PROC_ARGV
};
char *path = NULL;
size_t len;
if (sysctl(mib, 4, NULL, &len, NULL, 0) == 0 && len > 0) {
char **argv = malloc(len);
if (argv) {
if (sysctl(mib, 4, argv, &len, NULL, 0) == 0) {
path = realpath(argv[0], NULL);
}
}
free(argv);
}
if (path) {
free(buf);
return path;
}
#endif
sprintf(buf, "tint2");
return buf;
}

View file

@ -14,7 +14,7 @@
#define GREEN "\033[1;32m"
#define YELLOW "\033[1;33m"
#define RED "\033[31m"
#define RED "\033[1;31m"
#define BLUE "\033[1;34m"
#define RESET "\033[0m"
@ -108,4 +108,8 @@ GList *g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data);
#define g_assert_null(expr) g_assert((expr) == NULL)
#endif
void close_all_fds();
char* get_own_path();
#endif

View file

@ -435,11 +435,16 @@ void stop_multi_timeout(timeout *t)
double profiling_get_time_old_time = 0;
double profiling_get_time()
double get_time()
{
struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time);
double t = cur_time.tv_sec + cur_time.tv_nsec * 1.0e-9;
return cur_time.tv_sec + cur_time.tv_nsec * 1.0e-9;
}
double profiling_get_time()
{
double t = get_time();
if (profiling_get_time_old_time == 0)
profiling_get_time_old_time = t;
double delta = t - profiling_get_time_old_time;

View file

@ -69,4 +69,6 @@ struct timespec add_msec_to_timespec(struct timespec ts, int msec);
// At the first call returns zero.
double profiling_get_time();
double get_time();
#endif // TIMER_H