]> git.ipfire.org Git - thirdparty/mtr.git/commit
Rework Cygwin mtr-packet to respond to signals (such as SIGTERM) 292/head
authorMatt Kimball <matt.kimball@gmail.com>
Sun, 3 Mar 2019 16:00:55 +0000 (08:00 -0800)
committerMatt Kimball <matt.kimball@gmail.com>
Sun, 3 Mar 2019 16:00:55 +0000 (08:00 -0800)
commit059e23c5a005929d6aba2bf133806d7f1a65b006
treed2785aa9b47cd1fc133bc6ce0d4e43f5def88f1d
parent30c60d1535801dc7c0f3cb37913b2824f3650aa6
Rework Cygwin mtr-packet to respond to signals (such as SIGTERM)

The prior implementation of mtr-packet on Cygwin would
not respond to Unix-style signals sent from other processes.
It was unkillable from the Cygwin shell, even with SIGKILL,
and exiting mtr would sometimes stall for several seconds because
it would ignore the SIGTERM sent from the main mtr process.
It would then wait for all outstanding probes to timeout before
exiting.

Signals were ignored because they are implemented by the Cygwin
library at the user level, (i.e. not provided by the OS kernel),
and mtr-packet often bypassed Cygwin's I/O functions by calling
Win32 APIs directly.

With this rework, the Cygwin implementation uses an ICMP service
thread to call the Win32 ICMP functions, but the main thread
uses a POSIX-style select() loop, similar to the Unix version mtr.

I would have liked to avoid multithreading entirely, but here are
the constraints:

    a)  mtr was originally a Unix program which used "raw sockets"
    b)  In order to port mtr to Windows, Cygwin is used to get a
        Unix-like environment
    c)  You can't use a raw socket to receive an ICMP reply on Windows.
        However, Windows provides a separate API in the form of
        ICMP.DLL for sending and receiving ICMP messages.
    d)  The ICMP API works asynchronously, and requires completion
        through an asynchronous procedure call ("APC")
    e)  APCs are only delivered during blocking Win32 operations
        which are flagged as "alertable."  This prevents apps from
        having APCs execute unexpectedly during an I/O operation.
    f)  Cygwin's implementation of POSIX functions does all I/O
        through non-alertable I/O operations.  This is reasonable
        because APCs don't exist in the POSIX API.
    g)  Cygwin implements Unix-style signals at the application level,
        since the Windows kernel doesn't have them.  We want our
        program to respond to SIGTERM and SIGKILL, at least.
    h)  Cygwin's signal implementation will deliver signals during
        blocking I/O functions in the Cygwin library, but won't
        respond to signals if the signal is sent while the application
        is in a blocking Windows API call which Cygwin is not aware of.
    i)  Since we want to both send/receive ICMP probes and also respond
        to Unix-style signals, we require two threads:  one which
        uses Cygwin's POSIX style blocking I/O and can respond to
        signals, and one which uses alertable waits using Win32
        blocking APIs.

The solution is to have the main thread using select() as the
blocking operation in its loop, and also to have an ICMP service
thread using WaitForSingleObjectEx() as its blocking operation.
The main thread will respond to signals.  The ICMP service thread
will run the APCs completing ICMP.DLL requests.

This change doesn't affect non-Windows versions of mtr, other than
moving the code from command_unix.c back into command.c,
since it can now be shared between Unix-like systems and Windows.
Makefile.am
packet/command.c
packet/command.h
packet/command_cygwin.c [deleted file]
packet/command_cygwin.h [deleted file]
packet/command_unix.c [deleted file]
packet/command_unix.h [deleted file]
packet/probe_cygwin.c
packet/probe_cygwin.h
packet/wait_cygwin.c