From a4528ab7057029132d812af02ee9f33eed5c5b11 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 25 May 2018 04:05:13 +0300 Subject: [PATCH] Add asynchronous posix signal handling. Add signal tests. --- asyncdispatch2.nimble | 4 ++++ asyncdispatch2/asyncloop.nim | 34 ++++++++++++++++++++-------- tests/testsignal.nim | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 tests/testsignal.nim diff --git a/asyncdispatch2.nimble b/asyncdispatch2.nimble index f6566be..cc5dcf3 100644 --- a/asyncdispatch2.nimble +++ b/asyncdispatch2.nimble @@ -26,6 +26,10 @@ task test, "Run all tests": exec "nim c -r tests/testfut" exec "nim c -r -d:release tests/testfut" + exec "nim c -r -d:useSysAssert -d:useGcAssert tests/testsignal" + exec "nim c -r tests/testsignal" + exec "nim c -r -d:release tests/testsignal" + exec "nim c -r -d:useSysAssert -d:useGcAssert tests/testdatagram" exec "nim c -r tests/testdatagram" exec "nim c -r -d:release tests/testdatagram" diff --git a/asyncdispatch2/asyncloop.nim b/asyncdispatch2/asyncloop.nim index 4d43e3d..35c950e 100644 --- a/asyncdispatch2/asyncloop.nim +++ b/asyncdispatch2/asyncloop.nim @@ -185,6 +185,7 @@ proc initCallSoonProc() = when defined(windows) or defined(nimdoc): import winlean, sets, hashes + type WSAPROC_TRANSMITFILE = proc(hSocket: SocketHandle, hFile: Handle, nNumberOfBytesToWrite: DWORD, @@ -203,6 +204,9 @@ when defined(windows) or defined(nimdoc): bytesCount*: int32 udata*: pointer + CustomOverlapped* = object of OVERLAPPED + data*: CompletionData + PDispatcher* = ref object of PDispatcherBase ioPort: Handle handles: HashSet[AsyncFD] @@ -211,9 +215,6 @@ when defined(windows) or defined(nimdoc): getAcceptExSockAddrs*: WSAPROC_GETACCEPTEXSOCKADDRS transmitFile*: WSAPROC_TRANSMITFILE - CustomOverlapped* = object of OVERLAPPED - data*: CompletionData - PtrCustomOverlapped* = ptr CustomOverlapped RefCustomOverlapped* = ref CustomOverlapped @@ -324,12 +325,6 @@ when defined(windows) or defined(nimdoc): var callable = loop.callbacks.popFirst() callable.function(callable.udata) - template getUdata*(u: untyped) = - if isNil(u): - nil - else: - cast[ptr CustomOverlapped](u).data.udata - proc getFunc(s: SocketHandle, fun: var pointer, guid: var GUID): bool = var bytesRet: Dword fun = nil @@ -497,6 +492,27 @@ else: raise newException(ValueError, "File descriptor not registered.") p.selector.updateHandle(int(fd), newEvents) + when ioselSupportedPlatform: + proc addSignal*(signal: int, cb: CallbackFunc, + udata: pointer = nil): int = + ## Start watching signal ``signal``, and when signal appears, call the + ## callback ``cb``. Returns signal identifier code, which can be used + ## to remove signal callback via ``removeSignal``. + let p = getGlobalDispatcher() + var data: SelectorData + result = p.selector.registerSignal(signal, data) + withData(p.selector, result, adata) do: + adata.reader = AsyncCallback(function: cb, udata: addr adata.rdata) + adata.rdata.fd = AsyncFD(result) + adata.rdata.udata = udata + do: + raise newException(ValueError, "File descriptor not registered.") + + proc removeSignal*(sigfd: int) = + ## Remove watching signal ``signal``. + let p = getGlobalDispatcher() + p.selector.unregister(sigfd) + proc poll*() = let loop = getGlobalDispatcher() var curTime = fastEpochTime() diff --git a/tests/testsignal.nim b/tests/testsignal.nim new file mode 100644 index 0000000..196223d --- /dev/null +++ b/tests/testsignal.nim @@ -0,0 +1,43 @@ +# Asyncdispatch2 Test Suite +# (c) Copyright 2018 +# Status Research & Development GmbH +# +# Licensed under either of +# Apache License, version 2.0, (LICENSE-APACHEv2) +# MIT license (LICENSE-MIT) + +import unittest, strutils +import ../asyncdispatch2 + +when not defined(windows): + import posix + + var signalCounter = 0 + + proc signalProc(udata: pointer) = + var cdata = cast[ptr CompletionData](udata) + signalCounter = cast[int](cdata.udata) + removeSignal(int(cdata.fd)) + + proc asyncProc() {.async.} = + await sleepAsync(500) + + proc test(signal, value: int): bool = + discard addSignal(signal, signalProc, cast[pointer](value)) + var fut = asyncProc() + discard posix.kill(posix.getpid(), cint(signal)) + waitFor(fut) + signalCounter == value + +else: + const + SIGINT = 0 + SIGTERM = 0 + proc test(signal, value: int): bool = true + +when isMainModule: + suite "Signal handling test suite": + test "SIGINT test": + check test(SIGINT, 31337) == true + test "SIGTERM test": + check test(SIGTERM, 65537) == true