Restart on crash
This commit is contained in:
parent
69f6f65db6
commit
cd863c2819
6 changed files with 194 additions and 11 deletions
|
@ -28,6 +28,7 @@
|
||||||
#include <X11/extensions/Xdamage.h>
|
#include <X11/extensions/Xdamage.h>
|
||||||
#include <X11/extensions/Xcomposite.h>
|
#include <X11/extensions/Xcomposite.h>
|
||||||
#include <X11/extensions/Xrender.h>
|
#include <X11/extensions/Xrender.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "systraybar.h"
|
#include "systraybar.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
71
src/tint.c
71
src/tint.c
|
@ -34,6 +34,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#ifdef HAVE_SN
|
#ifdef HAVE_SN
|
||||||
#include <libsn/sn.h>
|
#include <libsn/sn.h>
|
||||||
|
@ -75,6 +77,7 @@ XSettingsClient *xsettings_client = NULL;
|
||||||
|
|
||||||
timeout *detect_compositor_timer = NULL;
|
timeout *detect_compositor_timer = NULL;
|
||||||
int detect_compositor_timer_counter = 0;
|
int detect_compositor_timer_counter = 0;
|
||||||
|
double start_time = 0;
|
||||||
|
|
||||||
void detect_compositor(void *arg)
|
void detect_compositor(void *arg)
|
||||||
{
|
{
|
||||||
|
@ -185,14 +188,9 @@ const char *get_home_dir()
|
||||||
return pw->pw_dir;
|
return pw->pw_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
void crash_handler(int sig)
|
void dump_backtrace(int log_fd)
|
||||||
{
|
{
|
||||||
char path[4096];
|
log_string(log_fd, YELLOW "\nBacktrace:\n");
|
||||||
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");
|
|
||||||
|
|
||||||
#ifdef ENABLE_LIBUNWIND
|
#ifdef ENABLE_LIBUNWIND
|
||||||
unw_cursor_t cursor;
|
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");
|
log_string(log_fd, "Backtrace not supported on this system. Install libunwind or libexecinfo.\n");
|
||||||
#endif
|
#endif
|
||||||
#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[])
|
void init(int argc, char *argv[])
|
||||||
|
@ -373,6 +425,7 @@ void init_X11_pre_config()
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
XSetErrorHandler((XErrorHandler)server_catch_error);
|
XSetErrorHandler((XErrorHandler)server_catch_error);
|
||||||
|
XSetIOErrorHandler((XIOErrorHandler)x11_io_error);
|
||||||
server_init_atoms();
|
server_init_atoms();
|
||||||
server.screen = DefaultScreen(server.display);
|
server.screen = DefaultScreen(server.display);
|
||||||
server.root_win = RootWindow(server.display, server.screen);
|
server.root_win = RootWindow(server.display, server.screen);
|
||||||
|
@ -1387,6 +1440,8 @@ void dnd_drop(XClientMessageEvent *e)
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
start:
|
start:
|
||||||
|
start_time = get_time();
|
||||||
|
|
||||||
init(argc, argv);
|
init(argc, argv);
|
||||||
|
|
||||||
init_X11_pre_config();
|
init_X11_pre_config();
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "../server.h"
|
#include "../server.h"
|
||||||
#include <sys/wait.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
|
#ifdef HAVE_RSVG
|
||||||
#include <librsvg/rsvg.h>
|
#include <librsvg/rsvg.h>
|
||||||
|
@ -620,3 +627,112 @@ GList *g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#define GREEN "\033[1;32m"
|
#define GREEN "\033[1;32m"
|
||||||
#define YELLOW "\033[1;33m"
|
#define YELLOW "\033[1;33m"
|
||||||
#define RED "\033[31m"
|
#define RED "\033[1;31m"
|
||||||
#define BLUE "\033[1;34m"
|
#define BLUE "\033[1;34m"
|
||||||
#define RESET "\033[0m"
|
#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)
|
#define g_assert_null(expr) g_assert((expr) == NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void close_all_fds();
|
||||||
|
|
||||||
|
char* get_own_path();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -435,11 +435,16 @@ void stop_multi_timeout(timeout *t)
|
||||||
|
|
||||||
double profiling_get_time_old_time = 0;
|
double profiling_get_time_old_time = 0;
|
||||||
|
|
||||||
double profiling_get_time()
|
double get_time()
|
||||||
{
|
{
|
||||||
struct timespec cur_time;
|
struct timespec cur_time;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &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)
|
if (profiling_get_time_old_time == 0)
|
||||||
profiling_get_time_old_time = t;
|
profiling_get_time_old_time = t;
|
||||||
double delta = t - profiling_get_time_old_time;
|
double delta = t - profiling_get_time_old_time;
|
||||||
|
|
|
@ -69,4 +69,6 @@ struct timespec add_msec_to_timespec(struct timespec ts, int msec);
|
||||||
// At the first call returns zero.
|
// At the first call returns zero.
|
||||||
double profiling_get_time();
|
double profiling_get_time();
|
||||||
|
|
||||||
|
double get_time();
|
||||||
|
|
||||||
#endif // TIMER_H
|
#endif // TIMER_H
|
||||||
|
|
Loading…
Reference in a new issue