Async upcoming (#6585)
* Merge upcoming async with current. * Various improvements to selectors (mostly docs). Two changes to highlight: * Renamed ``setEvent`` to ``trigger`` * Reused setBlocking from nativesockets. * Various changes/fixes to asyncdispatch after upcoming merge. * Make some attempts to be compatible with older selectors. * Reuse epoll module in ioselectors_epoll.
This commit is contained in:
parent
2c584cdb3d
commit
d3394be555
10 changed files with 766 additions and 925 deletions
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
# This module implements Linux epoll().
|
||||
|
||||
import posix, times
|
||||
import posix, times, epoll
|
||||
|
||||
# Maximum number of events that can be returned
|
||||
const MAX_EPOLL_EVENTS = 64
|
||||
|
|
@ -36,35 +36,6 @@ when not defined(android):
|
|||
ssi_addr*: uint64
|
||||
pad* {.importc: "__pad".}: array[0..47, uint8]
|
||||
|
||||
type
|
||||
eventFdData {.importc: "eventfd_t",
|
||||
header: "<sys/eventfd.h>", pure, final.} = uint64
|
||||
epoll_data {.importc: "union epoll_data", header: "<sys/epoll.h>",
|
||||
pure, final.} = object
|
||||
u64 {.importc: "u64".}: uint64
|
||||
epoll_event {.importc: "struct epoll_event",
|
||||
header: "<sys/epoll.h>", pure, final.} = object
|
||||
events: uint32 # Epoll events
|
||||
data: epoll_data # User data variable
|
||||
|
||||
const
|
||||
EPOLL_CTL_ADD = 1 # Add a file descriptor to the interface.
|
||||
EPOLL_CTL_DEL = 2 # Remove a file descriptor from the interface.
|
||||
EPOLL_CTL_MOD = 3 # Change file descriptor epoll_event structure.
|
||||
EPOLLIN = 0x00000001
|
||||
EPOLLOUT = 0x00000004
|
||||
EPOLLERR = 0x00000008
|
||||
EPOLLHUP = 0x00000010
|
||||
EPOLLRDHUP = 0x00002000
|
||||
EPOLLONESHOT = 1 shl 30
|
||||
|
||||
proc epoll_create(size: cint): cint
|
||||
{.importc: "epoll_create", header: "<sys/epoll.h>".}
|
||||
proc epoll_ctl(epfd: cint; op: cint; fd: cint; event: ptr epoll_event): cint
|
||||
{.importc: "epoll_ctl", header: "<sys/epoll.h>".}
|
||||
proc epoll_wait(epfd: cint; events: ptr epoll_event; maxevents: cint;
|
||||
timeout: cint): cint
|
||||
{.importc: "epoll_wait", header: "<sys/epoll.h>".}
|
||||
proc timerfd_create(clock_id: ClockId, flags: cint): cint
|
||||
{.cdecl, importc: "timerfd_create", header: "<sys/timerfd.h>".}
|
||||
proc timerfd_settime(ufd: cint, flags: cint,
|
||||
|
|
@ -80,26 +51,26 @@ when not defined(android):
|
|||
var RLIMIT_NOFILE {.importc: "RLIMIT_NOFILE",
|
||||
header: "<sys/resource.h>".}: cint
|
||||
type
|
||||
rlimit {.importc: "struct rlimit",
|
||||
RLimit {.importc: "struct rlimit",
|
||||
header: "<sys/resource.h>", pure, final.} = object
|
||||
rlim_cur: int
|
||||
rlim_max: int
|
||||
proc getrlimit(resource: cint, rlp: var rlimit): cint
|
||||
proc getrlimit(resource: cint, rlp: var RLimit): cint
|
||||
{.importc: "getrlimit",header: "<sys/resource.h>".}
|
||||
|
||||
when hasThreadSupport:
|
||||
type
|
||||
SelectorImpl[T] = object
|
||||
epollFD : cint
|
||||
maxFD : int
|
||||
epollFD: cint
|
||||
maxFD: int
|
||||
fds: ptr SharedArray[SelectorKey[T]]
|
||||
count: int
|
||||
Selector*[T] = ptr SelectorImpl[T]
|
||||
else:
|
||||
type
|
||||
SelectorImpl[T] = object
|
||||
epollFD : cint
|
||||
maxFD : int
|
||||
epollFD: cint
|
||||
maxFD: int
|
||||
fds: seq[SelectorKey[T]]
|
||||
count: int
|
||||
Selector*[T] = ref SelectorImpl[T]
|
||||
|
|
@ -109,7 +80,8 @@ type
|
|||
SelectEvent* = ptr SelectEventImpl
|
||||
|
||||
proc newSelector*[T](): Selector[T] =
|
||||
var a = rlimit()
|
||||
# Retrieve the maximum fd count (for current OS) via getrlimit()
|
||||
var a = RLimit()
|
||||
if getrlimit(RLIMIT_NOFILE, a) != 0:
|
||||
raiseOsError(osLastError())
|
||||
var maxFD = int(a.rlim_max)
|
||||
|
|
@ -152,8 +124,8 @@ proc newSelectEvent*(): SelectEvent =
|
|||
result = cast[SelectEvent](allocShared0(sizeof(SelectEventImpl)))
|
||||
result.efd = fdci
|
||||
|
||||
proc setEvent*(ev: SelectEvent) =
|
||||
var data : uint64 = 1
|
||||
proc trigger*(ev: SelectEvent) =
|
||||
var data: uint64 = 1
|
||||
if posix.write(ev.efd, addr data, sizeof(uint64)) == -1:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
|
||||
|
|
@ -164,6 +136,8 @@ proc close*(ev: SelectEvent) =
|
|||
raiseIOSelectorsError(osLastError())
|
||||
|
||||
template checkFd(s, f) =
|
||||
# TODO: I don't see how this can ever happen. You won't be able to create an
|
||||
# FD if there is too many. -- DP
|
||||
if f >= s.maxFD:
|
||||
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
||||
|
||||
|
|
@ -171,10 +145,10 @@ proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
|||
events: set[Event], data: T) =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == 0, "Descriptor $# already registered" % $fdi)
|
||||
s.setKey(fdi, events, 0, data)
|
||||
if events != {}:
|
||||
var epv = epoll_event(events: EPOLLRDHUP)
|
||||
var epv = EpollEvent(events: EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
if Event.Read in events: epv.events = epv.events or EPOLLIN
|
||||
if Event.Write in events: epv.events = epv.events or EPOLLOUT
|
||||
|
|
@ -189,10 +163,10 @@ proc updateHandle*[T](s: Selector[T], fd: SocketHandle, events: set[Event]) =
|
|||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||
"Descriptor $# is not registered in the selector!" % $fdi)
|
||||
doAssert(pkey.events * maskEvents == {})
|
||||
if pkey.events != events:
|
||||
var epv = epoll_event(events: EPOLLRDHUP)
|
||||
var epv = EpollEvent(events: EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
|
||||
if Event.Read in events: epv.events = epv.events or EPOLLIN
|
||||
|
|
@ -217,24 +191,25 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
|||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||
"Descriptor $# is not registered in the selector!" % $fdi)
|
||||
if pkey.events != {}:
|
||||
when not defined(android):
|
||||
if pkey.events * {Event.Read, Event.Write} != {}:
|
||||
var epv = epoll_event()
|
||||
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:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
dec(s.count)
|
||||
elif Event.Timer in pkey.events:
|
||||
if Event.Finished notin pkey.events:
|
||||
var epv = epoll_event()
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
dec(s.count)
|
||||
if posix.close(cint(fdi)) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
elif Event.Signal in pkey.events:
|
||||
var epv = epoll_event()
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
var nmask, omask: Sigset
|
||||
|
|
@ -247,7 +222,7 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
|||
raiseIOSelectorsError(osLastError())
|
||||
elif Event.Process in pkey.events:
|
||||
if Event.Finished notin pkey.events:
|
||||
var epv = epoll_event()
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
var nmask, omask: Sigset
|
||||
|
|
@ -260,13 +235,13 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
|||
raiseIOSelectorsError(osLastError())
|
||||
else:
|
||||
if pkey.events * {Event.Read, Event.Write} != {}:
|
||||
var epv = epoll_event()
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
dec(s.count)
|
||||
elif Event.Timer in pkey.events:
|
||||
if Event.Finished notin pkey.events:
|
||||
var epv = epoll_event()
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
dec(s.count)
|
||||
|
|
@ -280,7 +255,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
|||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0, "Event is not registered in the queue!")
|
||||
doAssert(Event.User in pkey.events)
|
||||
var epv = epoll_event()
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
dec(s.count)
|
||||
|
|
@ -300,7 +275,7 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool,
|
|||
doAssert(s.fds[fdi].ident == 0)
|
||||
|
||||
var events = {Event.Timer}
|
||||
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
if oneshot:
|
||||
new_ts.it_interval.tv_sec = 0.Time
|
||||
|
|
@ -343,7 +318,7 @@ when not defined(android):
|
|||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
|
||||
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
|
|
@ -370,7 +345,7 @@ when not defined(android):
|
|||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
|
||||
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
epv.events = EPOLLIN or EPOLLRDHUP
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) != 0:
|
||||
|
|
@ -383,7 +358,7 @@ proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
|||
let fdi = int(ev.efd)
|
||||
doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!")
|
||||
s.setKey(fdi, {Event.User}, 0, data)
|
||||
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = ev.efd.uint
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, ev.efd, addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
|
|
@ -392,7 +367,7 @@ proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
|||
proc selectInto*[T](s: Selector[T], timeout: int,
|
||||
results: var openarray[ReadyKey]): int =
|
||||
var
|
||||
resTable: array[MAX_EPOLL_EVENTS, epoll_event]
|
||||
resTable: array[MAX_EPOLL_EVENTS, EpollEvent]
|
||||
maxres = MAX_EPOLL_EVENTS
|
||||
i, k: int
|
||||
|
||||
|
|
@ -482,7 +457,7 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
|||
rkey.events.incl(Event.User)
|
||||
|
||||
if Event.Oneshot in pkey.events:
|
||||
var epv = epoll_event()
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, cint(fdi), addr epv) != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
# we will not clear key until it will be unregistered, so
|
||||
|
|
@ -505,16 +480,19 @@ proc select*[T](s: Selector[T], timeout: int): seq[ReadyKey] =
|
|||
template isEmpty*[T](s: Selector[T]): bool =
|
||||
(s.count == 0)
|
||||
|
||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): T =
|
||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||
return s.fds[fd].ident != 0
|
||||
|
||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
if s.fds[fdi].ident != 0:
|
||||
if fdi in s:
|
||||
result = s.fds[fdi].data
|
||||
|
||||
proc setData*[T](s: Selector[T], fd: SocketHandle|int, data: T): bool =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
if s.fds[fdi].ident != 0:
|
||||
if fdi in s:
|
||||
s.fds[fdi].data = data
|
||||
result = true
|
||||
|
||||
|
|
@ -523,8 +501,8 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value,
|
|||
mixin checkFd
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
if s.fds[fdi].ident != 0:
|
||||
var value = addr(s.fds[fdi].data)
|
||||
if fdi in s:
|
||||
var value = addr(s.getData(fdi))
|
||||
body
|
||||
|
||||
template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
|
||||
|
|
@ -532,8 +510,8 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1,
|
|||
mixin checkFd
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
if s.fds[fdi].ident != 0:
|
||||
var value = addr(s.fds[fdi].data)
|
||||
if fdi in s:
|
||||
var value = addr(s.getData(fdi))
|
||||
body1
|
||||
else:
|
||||
body2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue