[PATCH 2 of 2] chg: send SIGPIPE to server immediately when pager exits (issue5278)

Jun Wu quark at fb.com
Fri Jun 24 13:39:34 EDT 2016


This works for hg commends like:

    @command('wait', [], 'wait', norepo=True)
    def _crash(ui, *args):
        for i in xrange(4000):
            ui.write('%s\n' % i)
        time.sleep(30)

But does not work with shell aliases (in which case SIGCHLD handler is not
triggered). I will investigate later.

Excerpts from Jun Wu's message of 2016-06-24 17:10:18 +0100:
> # HG changeset patch
> # User Jun Wu <quark at fb.com>
> # Date 1466778070 -3600
> #      Fri Jun 24 15:21:10 2016 +0100
> # Node ID 701ec0855d2c4b9a40aeb3c8d317aa6b54a3e308
> # Parent  f1195d649b4237400de44ac741f701aded61eb95
> # Available At https://bitbucket.org/quark-zju/hg-draft 
> #              hg pull https://bitbucket.org/quark-zju/hg-draft  -r 701ec0855d2c
> chg: send SIGPIPE to server immediately when pager exits (issue5278)
> 
> If the user press 'q' to leave the 'less' pager, it is expected to end the
> hg process immediately. We currently rely on SIGPIPE for this behavior. But
> SIGPIPE won't arrive if we don't write anything (like doing heavy
> computation, reading from network etc). If that happens, the user will feel
> that the hg process just hangs.
> 
> The patch address the issue by adding a SIGCHLD signal handler and sends
> SIGPIPE to the server as soon as the pager exits.
> 
> This is also an issue with hg's pager implementation.
> 
> diff --git a/contrib/chg/chg.c b/contrib/chg/chg.c
> --- a/contrib/chg/chg.c
> +++ b/contrib/chg/chg.c
> @@ -338,6 +338,7 @@ static void killcmdserver(const struct c
>      }
>  }
>  
> +static pid_t pagerpid = 0;
>  static pid_t peerpid = 0;
>  
>  static void forwardsignal(int sig)
> @@ -380,6 +381,17 @@ error:
>      abortmsgerrno("failed to handle stop signal");
>  }
>  
> +static void handlechildsignal(int sig)
> +{

Missed "(void)sig" to avoid unused variable warning.

> +    if (peerpid == 0 || pagerpid == 0)
> +        return;
> +    /* if pager exits, notify the server with SIGPIPE immediately.
> +     * otherwise the server won't get SIGPIPE if it does not write
> +     * anything. (issue5278) */
> +    if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid)
> +        kill(peerpid, SIGPIPE);
> +}
> +
>  static void setupsignalhandler(pid_t pid)
>  {
>      if (pid <= 0)
> @@ -416,6 +428,11 @@ static void setupsignalhandler(pid_t pid
>      sa.sa_flags = SA_RESTART;
>      if (sigaction(SIGTSTP, &sa, NULL) < 0)
>          goto error;
> +    /* get notified when pager exits */
> +    sa.sa_handler = handlechildsignal;
> +    sa.sa_flags = SA_RESTART;
> +    if (sigaction(SIGCHLD, &sa, NULL) < 0)
> +        goto error;
>  
>      return;
>  
> @@ -638,7 +655,7 @@ int main(int argc, const char *argv[], c
>      }
>  
>      setupsignalhandler(hgc_peerpid(hgc));
> -    pid_t pagerpid = setuppager(hgc, argv + 1, argc - 1);
> +    pagerpid = setuppager(hgc, argv + 1, argc - 1);
>      int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
>      restoresignalhandler();
>      hgc_close(hgc);


More information about the Mercurial-devel mailing list