aboutsummaryrefslogtreecommitdiff
path: root/src/fluxbox.cc
diff options
context:
space:
mode:
authorMathias Gumz <akira at fluxbox dot org>2014-02-18 18:34:35 (GMT)
committerMathias Gumz <akira at fluxbox dot org>2014-02-18 18:34:35 (GMT)
commit43bdf499d56c09a520dc3bc03438dee4092d3d58 (patch)
treefc08fe113eb7c577eb402bf9ffebd8038d4f90da /src/fluxbox.cc
parent3696562aa87c7e68cb8b00b85f0e8d5cf2d199bf (diff)
downloadfluxbox-43bdf499d56c09a520dc3bc03438dee4092d3d58.zip
fluxbox-43bdf499d56c09a520dc3bc03438dee4092d3d58.tar.bz2
Fix race condition on shutdown
This commit fixes primarily a race condition that occurs when xinit(1) shuts down: by not acting properly fluxbox gets caught in an infinite loop. It caused bug #1100. xinit(1) sends a SIGHUP signal to all processes. fluxbox tries to shutdown itself properly by shutting down workspaces and screens. While doing that, the Xserver might be gone already. Additionally, fluxbox used to restart() itself on SIGHUP, which is clearly not the right thing to do when xinit(1) is about to end the session. So, fluxbox does this: * handling SIGHUP now shuts down fluxbox without clearing workspaces and screens. * A 2 second alarm() is triggered in Fluxbox::shutdown() as a last resort * XSetIOErrorHandler() is used to recognize the disconnect from the xserver. * SIGUSR1 is for restarting fluxbox, SIGUSR2 for reloading the config * FbTk/SignalHandler.cc/hh is gone; this unused abstraction served currently no real purpose. Signal handling is now done in main.cc * Unrelated to the issue itself src/main.cc was trimmed down quite a bit and the code (responsible for handling the command line interface) was moved to src/cli*
Diffstat (limited to 'src/fluxbox.cc')
-rw-r--r--src/fluxbox.cc97
1 files changed, 24 insertions, 73 deletions
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index 8305b8a..07419ba 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -177,11 +177,15 @@ int handleXErrors(Display *d, XErrorEvent *e) {
177// kill(0, 2); 177// kill(0, 2);
178 } 178 }
179#endif // !DEBUG 179#endif // !DEBUG
180
181 return False; 180 return False;
182} 181}
183 182
184 183
184int handleXIOErrors(Display* d) {
185 cerr << "Fluxbox: XIOError: lost connection to display.\n";
186 exit(1);
187}
188
185 189
186/* functor to call a memberfunction with by a reference argument 190/* functor to call a memberfunction with by a reference argument
187 other places needs this helper as well it should be moved 191 other places needs this helper as well it should be moved
@@ -290,21 +294,8 @@ Fluxbox::Fluxbox(int argc, char **argv,
290 s_kwm2_dockwindow = XInternAtom(disp, 294 s_kwm2_dockwindow = XInternAtom(disp,
291 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False); 295 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
292 // setup X error handler 296 // setup X error handler
293 XSetErrorHandler((XErrorHandler) handleXErrors); 297 XSetErrorHandler(handleXErrors);
294 298 XSetIOErrorHandler(handleXIOErrors);
295 //catch system signals
296 SignalHandler &sigh = SignalHandler::instance();
297 sigh.registerHandler(SIGSEGV, this);
298 sigh.registerHandler(SIGFPE, this);
299 sigh.registerHandler(SIGTERM, this);
300 sigh.registerHandler(SIGINT, this);
301#ifndef _WIN32
302 sigh.registerHandler(SIGPIPE, this); // e.g. output sent to grep
303 sigh.registerHandler(SIGCHLD, this);
304 sigh.registerHandler(SIGHUP, this);
305 sigh.registerHandler(SIGUSR1, this);
306 sigh.registerHandler(SIGUSR2, this);
307#endif
308 299
309 // 300 //
310 // setup timer 301 // setup timer
@@ -896,58 +887,6 @@ void Fluxbox::handleClientMessage(XClientMessageEvent &ce) {
896 } 887 }
897} 888}
898 889
899/// handle system signals
900void Fluxbox::handleSignal(int signum) {
901 _FB_USES_NLS;
902
903 static int re_enter = 0;
904
905 switch (signum) {
906#ifndef _WIN32
907 case SIGCHLD: // we don't want the child process to kill us
908 // more than one process may have terminated
909 while (waitpid(-1, 0, WNOHANG | WUNTRACED) > 0);
910 break;
911 case SIGHUP:
912 restart();
913 break;
914 case SIGUSR1:
915 load_rc();
916 break;
917 case SIGUSR2:
918 reconfigure();
919 break;
920#endif
921 case SIGSEGV:
922 abort();
923 break;
924 case SIGFPE:
925 case SIGINT:
926#ifndef _WIN32
927 case SIGPIPE:
928#endif
929 case SIGTERM:
930 shutdown();
931 break;
932 default:
933 fprintf(stderr,
934 _FB_CONSOLETEXT(BaseDisplay, SignalCaught, "%s: signal %d caught\n", "signal catch debug message. Include %s for Command<void> and %d for signal number").c_str(),
935 m_argv[0], signum);
936
937 if (! m_starting && ! re_enter) {
938 re_enter = 1;
939 cerr<<_FB_CONSOLETEXT(BaseDisplay, ShuttingDown, "Shutting Down\n", "Quitting because of signal, end with newline");
940 shutdown();
941 }
942
943
944 cerr<<_FB_CONSOLETEXT(BaseDisplay, Aborting, "Aborting... dumping core\n", "Aboring and dumping core, end with newline");
945 abort();
946 break;
947 }
948}
949
950
951void Fluxbox::windowDied(Focusable &focusable) { 890void Fluxbox::windowDied(Focusable &focusable) {
952 FluxboxWindow *fbwin = focusable.fbwindow(); 891 FluxboxWindow *fbwin = focusable.fbwindow();
953 892
@@ -1122,18 +1061,30 @@ void Fluxbox::restart(const char *prog) {
1122 } 1061 }
1123} 1062}
1124 1063
1125/// prepares fluxbox for a shutdown 1064// prepares fluxbox for a shutdown. when x_wants_down is != 0 we assume that
1126void Fluxbox::shutdown() { 1065// the xserver is about to shutdown or is in the midst of shutting down
1066// already. trying to cleanup over a shaky xserver connection is pointless and
1067// might lead to hangups.
1068void Fluxbox::shutdown(int x_wants_down) {
1127 if (m_shutdown) 1069 if (m_shutdown)
1128 return; 1070 return;
1129 1071
1072 Display *dpy = FbTk::App::instance()->display();
1130 m_shutdown = true; 1073 m_shutdown = true;
1131 1074
1132 XSetInputFocus(FbTk::App::instance()->display(), PointerRoot, None, CurrentTime); 1075#ifdef HAVE_ALARM
1076 // give ourself 2 seconds (randomly picked randon number) to shutdown
1077 // and then try to reenter signal handling. a bad race condition might
1078 // lead to an inifite loop and this is some kind of last resort
1079 alarm(2);
1080#endif
1133 1081
1134 STLUtil::forAll(m_screen_list, mem_fun(&BScreen::shutdown)); 1082 XSetInputFocus(dpy, PointerRoot, None, CurrentTime);
1135 1083
1136 sync(false); 1084 if (x_wants_down == 0) {
1085 STLUtil::forAll(m_screen_list, mem_fun(&BScreen::shutdown));
1086 sync(false);
1087 }
1137} 1088}
1138 1089
1139/// saves resources 1090/// saves resources