diff --git a/chronos/asyncloop.nim b/chronos/asyncloop.nim index 43b2c43..4ef41a0 100644 --- a/chronos/asyncloop.nim +++ b/chronos/asyncloop.nim @@ -174,7 +174,13 @@ when defined(windows): elif unixPlatform: import ./selectors2 from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, - MSG_NOSIGNAL, SIGPIPE + MSG_NOSIGNAL + from posix import SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, + SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, + SIGPIPE, SIGALRM, SIGTERM, SIGPIPE + export SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, + SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, + SIGPIPE, SIGALRM, SIGTERM, SIGPIPE type CallbackFunc* = proc (arg: pointer) {.gcsafe, raises: [Defect].} @@ -851,6 +857,50 @@ proc callIdle*(cbproc: CallbackFunc) {.gcsafe, raises: [Defect].} = include asyncfutures2 +when not(defined(windows)): + when ioselSupportedPlatform: + proc waitSignal*(signal: int): Future[void] {. + raises: [Defect].} = + var retFuture = newFuture[void]("chronos.waitSignal()") + var sigfd: int = -1 + + template getSignalException(e: untyped): untyped = + newException(AsyncError, "Could not manipulate signal handler, " & + "reason [" & $e.name & "]: " & $e.msg) + + proc continuation(udata: pointer) {.gcsafe.} = + if not(retFuture.finished()): + if sigfd != -1: + try: + removeSignal(sigfd) + retFuture.complete() + except IOSelectorsException as exc: + retFuture.fail(getSignalException(exc)) + + proc cancellation(udata: pointer) {.gcsafe.} = + if not(retFuture.finished()): + if sigfd != -1: + try: + removeSignal(sigfd) + except IOSelectorsException as exc: + retFuture.fail(getSignalException(exc)) + + sigfd = + try: + addSignal(signal, continuation) + except IOSelectorsException as exc: + retFuture.fail(getSignalException(exc)) + return retFuture + except ValueError as exc: + retFuture.fail(getSignalException(exc)) + return retFuture + except OSError as exc: + retFuture.fail(getSignalException(exc)) + return retFuture + + retFuture.cancelCallback = cancellation + retFuture + proc sleepAsync*(duration: Duration): Future[void] = ## Suspends the execution of the current async procedure for the next ## ``duration`` time. diff --git a/tests/testsignal.nim b/tests/testsignal.nim index 0d5377c..1163a8c 100644 --- a/tests/testsignal.nim +++ b/tests/testsignal.nim @@ -38,13 +38,33 @@ suite "Signal handling test suite": discard posix.kill(posix.getpid(), cint(signal)) waitFor(fut) signalCounter == value - else: - const - SIGINT = 0 - SIGTERM = 0 - proc test(signal, value: int): bool = true + + proc testWait(signal: int): bool = + var fut = waitSignal(signal) + discard posix.kill(posix.getpid(), cint(signal)) + waitFor(fut) + true test "SIGINT test": - check test(SIGINT, 31337) == true + when not defined(windows): + check test(SIGINT, 31337) == true + else: + skip() + test "SIGTERM test": - check test(SIGTERM, 65537) == true + when defined(windows): + skip() + else: + check test(SIGTERM, 65537) == true + + test "waitSignal(SIGINT) test": + when defined(windows): + skip() + else: + check testWait(SIGINT) == true + + test "waitSignal(SIGTERM) test": + when defined(windows): + skip() + else: + check testWait(SIGTERM) == true