Skip to content

Commit

Permalink
Merge pull request #12371 from rayman22201/IOSelector_unregister_fix
Browse files Browse the repository at this point in the history
Test + fix for epoll and kqueue selector modules to properly unregister event handles that have the key type "User"
  • Loading branch information
dom96 committed Oct 22, 2019
2 parents 0490324 + 92fa7e0 commit 6bfa4eb
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 7 deletions.
3 changes: 3 additions & 0 deletions changelog.md
Expand Up @@ -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).

Expand All @@ -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.
4 changes: 2 additions & 2 deletions lib/pure/asyncdispatch.nim
Expand Up @@ -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``
Expand Down
4 changes: 2 additions & 2 deletions lib/pure/ioselects/ioselectors_epoll.nim
Expand Up @@ -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:
Expand Down Expand Up @@ -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())
Expand Down
2 changes: 1 addition & 1 deletion lib/pure/ioselects/ioselectors_kqueue.nim
Expand Up @@ -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
return s.kqFD.int
4 changes: 2 additions & 2 deletions lib/pure/ioselects/ioselectors_select.nim
Expand Up @@ -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:
Expand Down Expand Up @@ -462,4 +462,4 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value,


proc getFd*[T](s: Selector[T]): int =
return -1
return -1
23 changes: 23 additions & 0 deletions 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

0 comments on commit 6bfa4eb

Please sign in to comment.