screen: Implement dead/zombie window polling Currently if zombie keys are defined, one needs to explicitly hit a key to tell screen to try to reconnect a window. This is rather unfortunte if you for example have dozens of screens connected to foreign machines through network connections. Once the network connection is cut for a while, all windows will enter the dead/zombie state and one has to go through all windows manually and hit the zombie resurrect key, once the network got set up again. This patch implements auto-reconnecting via zombie_timeout (in seconds) variable. By default it is set to 0 which complies to current behavior (no polling is done). Signed-off-by: Thomas Renninger --- comm.c | 3 ++- comm.h.dist | 3 ++- doc/screen.1 | 9 +++++++++ doc/screen.texinfo | 9 +++++++++ process.c | 12 ++++++++++++ screen.c | 7 +++++++ window.c | 29 ++++++++++++++++++++++++++++- window.h | 3 +++ 8 files changed, 72 insertions(+), 3 deletions(-) Index: screen-4.0.4/comm.c =================================================================== --- screen-4.0.4.orig/comm.c +++ screen-4.0.4/comm.c @@ -339,5 +339,6 @@ struct comm comms[RC_LAST + 1] = #ifdef ZMODEM { "zmodem", ARGS_012 }, #endif - { "zombie", ARGS_012 } + { "zombie", ARGS_012 }, + { "zombie_timeout", ARGS_1 } }; Index: screen-4.0.4/doc/screen.1 =================================================================== --- screen-4.0.4.orig/doc/screen.1 +++ screen-4.0.4/doc/screen.1 @@ -3545,6 +3545,15 @@ Optionally you can put the word \*Qonerr to monitor exit status of the process running in the window. If it exits normally ('0'), the window disappears. Any other exit value causes the window to become a zombie. +.BR "zombie_timeout" [\fIseconds\fP] +.PP +Per default +.I screen +windows are removed from the window list as soon as +the windows process (e.g. shell) exits. If \fBzombie\fP keys are defined +(compare with above \fBzombie\fP command), it is possible to also set a +timeout when screen tries to automatically reconnect a dead screen window. + .SH "THE MESSAGE LINE" .I Screen displays informational messages and other diagnostics in a \fImessage line\fP. Index: screen-4.0.4/doc/screen.texinfo =================================================================== --- screen-4.0.4.orig/doc/screen.texinfo +++ screen-4.0.4/doc/screen.texinfo @@ -1238,6 +1238,8 @@ Send an XON character. @xref{XON/XOFF}. Define how screen treats zmodem requests. @xref{Zmodem}. @item zombie address@hidden [onerror] ] Keep dead windows. @xref{Zombie}. address@hidden zombie_timeout address@hidden +Try to reconnect dead windows after timeout. @xref{Zombie}. @end table @node New Window, Selecting, Commands, Top @@ -5222,6 +5224,8 @@ Display the version and modification dat @section Zombie @deffn Command zombie address@hidden [onerror] ] @deffnx Command defzombie address@hidden address@hidden Command zombie_timeout address@hidden address@hidden deffn (none)@* Per default windows are removed from the window list as soon as the windows process (e.g. shell) exits. When a string of two keys is @@ -5241,6 +5245,11 @@ Optionally you can put the word @code{on cause screen to monitor exit status of the process running in the window. If it exits normally ('0'), the window disappears. Any other exit value causes the window to become a zombie. + +Additionally the @code{zombie_timeout} command exists. +If a window is declared ``dead'', screen will automatically try to +resurrect the window after the timeout. +It only works if zombie keys are defined via @code{zombie} command. @end deffn @node Printcmd, Rendition, Zombie, Miscellaneous Index: screen-4.0.4/process.c =================================================================== --- screen-4.0.4.orig/process.c +++ screen-4.0.4/process.c @@ -3067,6 +3067,18 @@ int key; } WindowChanged((struct win *)0, 0); break; + case RC_ZOMBIE_TIMEOUT: + if (argc != 1) + { + Msg(0, "Setting zombie polling needs a timeout arg\n"); + break; + } + nwin_default.poll_zombie_timeout = atoi(args[0]); + if (fore) + fore->w_poll_zombie_timeout = nwin_default.poll_zombie_timeout; + + debug1("Setting zombie polling to %d\n", nwin_default.poll_zombie_timeout); + break; case RC_SILENCE: n = fore->w_silence != 0; i = fore->w_silencewait; Index: screen-4.0.4/screen.c =================================================================== --- screen-4.0.4.orig/screen.c +++ screen-4.0.4/screen.c @@ -1557,6 +1557,13 @@ int wstat_valid; p->w_y = MFindUsedLine(p, p->w_bot, 1); sprintf(buf, "\n\r=== Command %s (%s) ===", reason, s ? s : "?"); WriteString(p, buf, strlen(buf)); + if (p->w_poll_zombie_timeout) + { + debug2("Set zombie poll timeout for window %s to %d\n", p->w_title, + p->w_poll_zombie_timeout); + SetTimeout(&p->w_zombieev, p->w_poll_zombie_timeout * 1000); + evenq(&p->w_zombieev); + } WindowChanged(p, 'f'); } else Index: screen-4.0.4/window.c =================================================================== --- screen-4.0.4.orig/window.c +++ screen-4.0.4/window.c @@ -87,6 +87,7 @@ static int DoAutolf __P((char *, int *, static void ZombieProcess __P((char **, int *)); static void win_readev_fn __P((struct event *, char *)); static void win_writeev_fn __P((struct event *, char *)); +static void win_resurrect_zombie_fn __P((struct event *, char *)); static int muchpending __P((struct win *, struct event *)); #ifdef COPY_PASTE static void paste_slowev_fn __P((struct event *, char *)); @@ -164,7 +165,8 @@ struct NewWindow nwin_default = 0, /* bce */ 0, /* encoding */ (char *)0, /* hstatus */ - (char *)0 /* charset */ + (char *)0, /* charset */ + 0 /* poll_zombie_timeout */ }; struct NewWindow nwin_options; @@ -198,6 +200,7 @@ struct NewWindow *def, *new, *res; COMPOSE(encoding); COMPOSE(hstatus); COMPOSE(charset); + COMPOSE(poll_zombie_timeout); #undef COMPOSE } @@ -838,6 +841,14 @@ struct NewWindow *newwin; DoStartLog(p, buf, sizeof(buf)); } + /* Is this all where I have to init window poll timeout? */ + if (nwin.poll_zombie_timeout) + p->w_poll_zombie_timeout = nwin.poll_zombie_timeout; + + p->w_zombieev.type = EV_TIMEOUT; + p->w_zombieev.data = (char *)p; + p->w_zombieev.handler = win_resurrect_zombie_fn; + p->w_readev.fd = p->w_writeev.fd = p->w_ptyfd; p->w_readev.type = EV_READ; p->w_writeev.type = EV_WRITE; @@ -1060,6 +1071,7 @@ struct win *wp; evdeq(&wp->w_readev); /* just in case */ evdeq(&wp->w_writeev); /* just in case */ evdeq(&wp->w_silenceev); + evdeq(&wp->w_zombieev); evdeq(&wp->w_destroyev); #ifdef COPY_PASTE FreePaster(&wp->w_paster); @@ -1941,6 +1953,21 @@ char *data; return; } +static void +win_resurrect_zombie_fn(ev, data) +struct event *ev; +char *data; +{ + struct win *p = (struct win *)data; + debug2("Try to resurrecting Zombie event: %d [%s]\n", + p->w_number, p->w_title); + /* Already reconnected? */ + if (p->w_deadpid != p->w_pid) + return; + debug1("Resurrecting Zombie: %d\n", p->w_number); + WriteString(p, "\r\n", 2); + RemakeWindow(p); +} static void win_writeev_fn(ev, data) Index: screen-4.0.4/window.h =================================================================== --- screen-4.0.4.orig/window.h +++ screen-4.0.4/window.h @@ -57,6 +57,7 @@ struct NewWindow int encoding; char *hstatus; char *charset; + int poll_zombie_timeout; }; #ifdef PSEUDOS @@ -150,6 +151,8 @@ struct win struct event w_readev; struct event w_writeev; struct event w_silenceev; /* silence event */ + struct event w_zombieev; /* event to try to resurrect window */ + int w_poll_zombie_timeout; int w_ptyfd; /* fd of the master pty */ char w_inbuf[IOSIZE]; int w_inlen; Index: screen-4.0.4/comm.h.dist =================================================================== --- screen-4.0.4.orig/comm.h.dist +++ screen-4.0.4/comm.h.dist @@ -236,5 +236,6 @@ struct action #define RC_XON 179 #define RC_ZMODEM 180 #define RC_ZOMBIE 181 +#define RC_ZOMBIE_TIMEOUT 182 -#define RC_LAST 181 +#define RC_LAST 182