void WaitForChild(void) { int pid; struct display *d; waitType status; sigset_t mask, omask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGHUP); sigprocmask(SIG_BLOCK, &mask, &omask); WDMDebug("signals blocked\n"); if (!ChildReady && !Rescan) sigsuspend(&omask); ChildReady = 0; sigprocmask(SIG_SETMASK, &omask, (sigset_t *) NULL); while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { WDMDebug("Manager wait returns pid: %d sig %d core %d code %d\n", pid, waitSig(status), waitCore(status), waitCode(status)); if (autoRescan.i) RescanIfMod(); /* SUPPRESS 560 */ if ((d = FindDisplayByPid(pid))) { d->pid = -1; switch (waitVal(status)) { case UNMANAGE_DISPLAY: WDMDebug("Display exited with UNMANAGE_DISPLAY\n"); StopDisplay(d); break; case OBEYSESS_DISPLAY: d->startTries = 0; WDMDebug("Display exited with OBEYSESS_DISPLAY\n"); if (d->displayType.lifetime != Permanent || d->status == zombie) StopDisplay(d); else RestartDisplay(d, FALSE); break; default: WDMDebug("Display exited with unknown status %d\n", waitVal(status)); WDMError("Unknown session exit code %d from process %d\n", waitVal(status), pid); StopDisplay(d); break; case OPENFAILED_DISPLAY: WDMDebug("Display exited with OPENFAILED_DISPLAY, try %d of %d\n", d->startTries, d->startAttempts); WDMError("Display %s cannot be opened\n", d->name); /* * no display connection was ever made, tell the * terminal that the open attempt failed */ #ifdef XDMCP if (d->displayType.origin == FromXDMCP) SendFailed(d, "Cannot open display"); #endif if (d->displayType.origin == FromXDMCP || d->status == zombie || ++d->startTries >= d->startAttempts) { WDMError("Display %s is being disabled\n", d->name); StopDisplay(d); } else { RestartDisplay(d, TRUE); } break; case RESERVER_DISPLAY: d->startTries = 0; WDMDebug("Display exited with RESERVER_DISPLAY\n"); if (d->displayType.origin == FromXDMCP || d->status == zombie) StopDisplay(d); else RestartDisplay(d, TRUE); { Time_t Time; time(&Time); WDMDebug("time %i %i\n", (int)Time, (int)d->lastCrash); if (d->lastCrash && ((Time - d->lastCrash) < XDM_BROKEN_INTERVAL)) { WDMDebug("Server crash frequency too high:" " removing display %s\n", d->name); WDMError("Server crash rate too high:" " removing display %s\n", d->name); RemoveDisplay(d); } else d->lastCrash = Time; } break; case waitCompose(SIGTERM, 0, 0): WDMDebug("Display exited on SIGTERM, try %d of %d\n", d->startTries, d->startAttempts); if (d->displayType.origin == FromXDMCP || d->status == zombie || ++d->startTries >= d->startAttempts) { WDMError("Display %s is being disabled\n", d->name); StopDisplay(d); } else RestartDisplay(d, TRUE); break; case REMANAGE_DISPLAY: d->startTries = 0; WDMDebug("Display exited with REMANAGE_DISPLAY\n"); /* * XDMCP will restart the session if the display * requests it */ if (d->displayType.origin == FromXDMCP || d->status == zombie) StopDisplay(d); else RestartDisplay(d, FALSE); break; } } /* SUPPRESS 560 */ else if ((d = FindDisplayByServerPid(pid))) { d->serverPid = -1; switch (d->status) { case zombie: WDMDebug("Zombie server reaped, removing display %s\n", d->name); RemoveDisplay(d); break; case phoenix: WDMDebug("Phoenix server arises, restarting display %s\n", d->name); d->status = notRunning; break; case running: WDMDebug("Server for display %s terminated unexpectedly, status %d %d\n", d->name, waitVal(status), status); WDMError("Server for display %s terminated unexpectedly: %d\n", d->name, waitVal(status)); d->status = notRunning; if (d->pid != -1) { WDMDebug("Terminating session pid %d\n", d->pid); TerminateProcess(d->pid, SIGTERM); } break; case notRunning: WDMDebug("Server exited for notRunning session on display %s\n", d->name); break; } } else { WDMDebug("Unknown child termination, status %d\n", waitVal(status)); } } StartDisplays(); }
void WaitForChild (void) { pid_t pid; struct display *d; waitType status; sigset_t mask, omask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGHUP); sigprocmask(SIG_BLOCK, &mask, &omask); Debug ("signals blocked\n"); if (!ChildReady && !Rescan) sigsuspend(&omask); ChildReady = 0; sigprocmask(SIG_SETMASK, &omask, (sigset_t *)NULL); while ((pid = waitpid (-1, &status, WNOHANG)) > 0) { Debug ("Manager wait returns pid: %d sig %d core %d code %d\n", pid, waitSig(status), waitCore(status), waitCode(status)); if (autoRescan) RescanIfMod (); /* SUPPRESS 560 */ if ((d = FindDisplayByPid (pid))) { d->pid = -1; switch (waitVal (status)) { case UNMANAGE_DISPLAY: Debug ("Display exited with UNMANAGE_DISPLAY\n"); StopDisplay (d); break; case OBEYSESS_DISPLAY: d->startTries = 0; d->reservTries = 0; Debug ("Display exited with OBEYSESS_DISPLAY\n"); if (d->status == zombie) StopDisplay (d); else RestartDisplay (d, FALSE); break; case OPENFAILED_DISPLAY: Debug ("Display exited with OPENFAILED_DISPLAY, try %d of %d\n", d->startTries, d->startAttempts); LogError ("Display %s cannot be opened\n", d->name); /* * no display connection was ever made, tell the * terminal that the open attempt failed */ if (d->status == zombie || ++d->startTries >= d->startAttempts) { LogError ("Display %s is being disabled\n", d->name); StopDisplay (d); } else { RestartDisplay (d, TRUE); } break; case RESERVER_DISPLAY: d->startTries = 0; Debug ("Display exited with RESERVER_DISPLAY\n"); if (d->status == zombie) StopDisplay(d); else { Time_t now; int crash; time(&now); crash = d->lastReserv && ((now - d->lastReserv) < XDM_BROKEN_INTERVAL); Debug("time %lli %lli try %i of %i%s\n", (long long)now, (long long)d->lastReserv, d->reservTries, d->reservAttempts, crash ? " crash" : ""); if (!crash) d->reservTries = 0; if (crash && ++d->reservTries >= d->reservAttempts) { const char *msg = "Server crash frequency too high: stopping display"; Debug("%s %s\n", msg, d->name); LogError("%s %s\n", msg, d->name); /* For a local X server either: * 1. The server exit was returned by waitpid(). So * serverPid==-1 => StopDisplay() calls RemoveDisplay() * * 2. The server is in zombie state or still running. So * serverPid>1 => StopDisplay() * a. sets status=zombie, * b. kills the server. * The next waitpid() returns this zombie server pid * and the 'case zombie:' below then calls * RemoveDisplay(). */ StopDisplay(d); } else { RestartDisplay(d, TRUE); } d->lastReserv = now; } break; case waitCompose (SIGTERM,0,0): Debug ("Display exited on SIGTERM, try %d of %d\n", d->startTries, d->startAttempts); if (d->status == zombie || ++d->startTries >= d->startAttempts) { /* * During normal xdm shutdown, killed local X servers * can be zombies; this is not an error. */ if (d->status == zombie && (d->startTries < d->startAttempts)) LogInfo ("display %s is being disabled\n", d->name); else LogError ("display %s is being disabled\n", d->name); StopDisplay(d); } else RestartDisplay (d, TRUE); break; case REMANAGE_DISPLAY: d->startTries = 0; Debug ("Display exited with REMANAGE_DISPLAY\n"); /* * XDMCP will restart the session if the display * requests it */ if (d->status == zombie) StopDisplay(d); else RestartDisplay (d, FALSE); break; default: Debug ("Display exited with unknown status %d\n", waitVal(status)); LogError ("Unknown session exit code %d from process %d\n", waitVal (status), pid); StopDisplay (d); break; } } /* SUPPRESS 560 */ else if ((d = FindDisplayByServerPid (pid))) { d->serverPid = -1; switch (d->status) { case zombie: Debug ("Zombie server reaped, removing display %s\n", d->name); RemoveDisplay (d); break; case phoenix: Debug ("Phoenix server arises, restarting display %s\n", d->name); d->status = notRunning; break; case running: Debug ("Server for display %s terminated unexpectedly, status %d %d\n", d->name, waitVal (status), status); LogError ("Server for display %s terminated unexpectedly: %d\n", d->name, waitVal (status)); if (d->pid != -1) { Debug ("Terminating session pid %d\n", d->pid); kill (d->pid, SIGTERM); } break; case notRunning: Debug ("Server exited for notRunning session on display %s\n", d->name); break; } } else { Debug ("Unknown child termination, status %d\n", waitVal (status)); } } StartDisplays (); }