summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md3
-rw-r--r--lib/pure/asyncdispatch.nim4
-rw-r--r--lib/pure/ioselects/ioselectors_epoll.nim4
-rw-r--r--lib/pure/ioselects/ioselectors_kqueue.nim2
-rw-r--r--lib/pure/ioselects/ioselectors_select.nim4
-rw-r--r--tests/async/testmanyasyncevents.nim23
6 files changed, 33 insertions, 7 deletions
diff --git a/changelog.md b/changelog.md
index 657354fe6..8b1aaeadc 100644
--- a/changelog.md
+++ b/changelog.md
@@ -23,6 +23,8 @@
 
 ## Library changes
 
+- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` and only returns once all pending async operations are guaranteed to have completed.
+- `asyncdispatch.drain` now consistently uses the passed timeout value for all iterations of the event loop, and not just the first iteration. This is more consistent with the other asyncdispatch apis, and allows `asyncdispatch.drain` to be more efficient.
 - `base64.encode` and `base64.decode` was made faster by about 50%.
 - `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support (ISO 40314).
 
@@ -46,3 +48,4 @@
 
 ## Bugfixes
 
+- The `FD` variant of `selector.unregister` for `ioselector_epoll` and `ioselector_select` now properly handle the `Event.User` select event type.
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index f540c5207..38946e82f 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1559,8 +1559,8 @@ proc drain*(timeout = 500) =
   ## Waits for completion events and processes them. Raises ``ValueError``
   ## if there are no pending operations. In contrast to ``poll`` this
   ## processes as many events as are available.
-  if runOnce(timeout):
-    while hasPendingOperations() and runOnce(0): discard
+  if runOnce(timeout) or hasPendingOperations():
+    while hasPendingOperations() and runOnce(timeout): discard
 
 proc poll*(timeout = 500) =
   ## Waits for completion events and processes them. Raises ``ValueError``
diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim
index 7c6f15164..bf13cc83e 100644
--- a/lib/pure/ioselects/ioselectors_epoll.nim
+++ b/lib/pure/ioselects/ioselectors_epoll.nim
@@ -197,7 +197,7 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
            "Descriptor $# is not registered in the selector!" % $fdi)
   if pkey.events != {}:
     when not defined(android):
-      if pkey.events * {Event.Read, Event.Write} != {}:
+      if Event.Read in pkey.events or Event.Write in pkey.events or Event.User in pkey.events:
         var epv = EpollEvent()
         # TODO: Refactor all these EPOLL_CTL_DEL + dec(s.count) into a proc.
         if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
@@ -237,7 +237,7 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
         if posix.close(cint(fdi)) != 0:
           raiseIOSelectorsError(osLastError())
     else:
-      if pkey.events * {Event.Read, Event.Write} != {}:
+      if Event.Read in pkey.events or Event.Write in pkey.events or Event.User in pkey.events:
         var epv = EpollEvent()
         if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
           raiseIOSelectorsError(osLastError())
diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim
index 0c51e67f4..65dc0c496 100644
--- a/lib/pure/ioselects/ioselectors_kqueue.nim
+++ b/lib/pure/ioselects/ioselectors_kqueue.nim
@@ -632,4 +632,4 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
 
 
 proc getFd*[T](s: Selector[T]): int =
-  return s.kqFD.int
\ No newline at end of file
+  return s.kqFD.int
diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim
index 1f608e43e..b90a01c06 100644
--- a/lib/pure/ioselects/ioselectors_select.nim
+++ b/lib/pure/ioselects/ioselectors_select.nim
@@ -286,7 +286,7 @@ proc unregister*[T](s: Selector[T], fd: SocketHandle|int) =
   s.withSelectLock():
     let fd = fd.SocketHandle
     var pkey = s.getKey(fd)
-    if Event.Read in pkey.events:
+    if Event.Read in pkey.events or Event.User in pkey.events:
       IOFD_CLR(fd, addr s.rSet)
       dec(s.count)
     if Event.Write in pkey.events:
@@ -462,4 +462,4 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value,
 
 
 proc getFd*[T](s: Selector[T]): int =
-  return -1
\ No newline at end of file
+  return -1
diff --git a/tests/async/testmanyasyncevents.nim b/tests/async/testmanyasyncevents.nim
new file mode 100644
index 000000000..5a103736f
--- /dev/null
+++ b/tests/async/testmanyasyncevents.nim
@@ -0,0 +1,23 @@
+discard """
+output: '''
+hasPendingOperations: false
+triggerCount: 100 
+'''
+"""
+
+import asyncDispatch
+
+var triggerCount = 0
+var evs = newSeq[AsyncEvent]()
+
+for i in 0 ..< 100: # has to be lower than the typical physical fd limit
+  var ev = newAsyncEvent()
+  evs.add(ev)
+  addEvent(ev, proc(fd: AsyncFD): bool {.gcsafe,closure.} = triggerCount += 1; true)
+
+for ev in evs:
+  ev.trigger()
+
+drain()
+echo "hasPendingOperations: ", hasPendingOperations()
+echo "triggerCount: ", triggerCount