Epoll now works.
This commit is contained in:
parent
526f9da463
commit
471c0aa634
2 changed files with 54 additions and 32 deletions
|
|
@ -31,13 +31,14 @@ const
|
||||||
EPOLL_CTL_MOD* = 3 # Change file descriptor epoll_event structure.
|
EPOLL_CTL_MOD* = 3 # Change file descriptor epoll_event structure.
|
||||||
|
|
||||||
type
|
type
|
||||||
epoll_data* {.pure, final.} = object
|
epoll_data* {.importc: "union epoll_data",
|
||||||
thePtr*: pointer
|
header: "<sys/epoll.h>", pure, final.} = object # TODO: This is actually a union.
|
||||||
fd*: cint
|
thePtr* {.importc: "ptr".}: pointer # \
|
||||||
u32*: uint32
|
#fd*: cint
|
||||||
u64*: uint64
|
#u32*: uint32
|
||||||
|
#u64*: uint64
|
||||||
|
|
||||||
epoll_event* {.pure, final.} = object
|
epoll_event* {.importc: "struct epoll_event", header: "<sys/epoll.h>", pure, final.} = object
|
||||||
events*: uint32 # Epoll events
|
events*: uint32 # Epoll events
|
||||||
data*: epoll_data # User data variable
|
data*: epoll_data # User data variable
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ type
|
||||||
PSelector* = ref object of PObject ## Selector interface.
|
PSelector* = ref object of PObject ## Selector interface.
|
||||||
fds*: TTable[cint, TSelectorKey]
|
fds*: TTable[cint, TSelectorKey]
|
||||||
registerImpl*: proc (s: PSelector, fd: cint, events: set[TEvent],
|
registerImpl*: proc (s: PSelector, fd: cint, events: set[TEvent],
|
||||||
data: var PObject): TSelectorKey {.nimcall, tags: [FWriteIO].}
|
data: PObject): TSelectorKey {.nimcall, tags: [FWriteIO].}
|
||||||
unregisterImpl*: proc (s: PSelector, fd: cint): TSelectorKey {.nimcall, tags: [FWriteIO].}
|
unregisterImpl*: proc (s: PSelector, fd: cint): TSelectorKey {.nimcall, tags: [FWriteIO].}
|
||||||
selectImpl*: proc (s: PSelector, timeout: int): seq[TReadyInfo] {.nimcall, tags: [FReadIO].}
|
selectImpl*: proc (s: PSelector, timeout: int): seq[TReadyInfo] {.nimcall, tags: [FReadIO].}
|
||||||
closeImpl*: proc (s: PSelector) {.nimcall.}
|
closeImpl*: proc (s: PSelector) {.nimcall.}
|
||||||
|
|
@ -38,7 +38,7 @@ template initSelector(r: expr) =
|
||||||
new r
|
new r
|
||||||
r.fds = initTable[cint, TSelectorKey]()
|
r.fds = initTable[cint, TSelectorKey]()
|
||||||
|
|
||||||
proc register*(s: PSelector, fd: cint, events: set[TEvent], data: var PObject):
|
proc register*(s: PSelector, fd: cint, events: set[TEvent], data: PObject):
|
||||||
TSelectorKey =
|
TSelectorKey =
|
||||||
if not s.registerImpl.isNil: result = s.registerImpl(s, fd, events, data)
|
if not s.registerImpl.isNil: result = s.registerImpl(s, fd, events, data)
|
||||||
|
|
||||||
|
|
@ -51,10 +51,10 @@ proc unregister*(s: PSelector, fd: cint): TSelectorKey =
|
||||||
|
|
||||||
proc select*(s: PSelector, timeout = 500): seq[TReadyInfo] =
|
proc select*(s: PSelector, timeout = 500): seq[TReadyInfo] =
|
||||||
##
|
##
|
||||||
## **Note:** For the ``epoll`` implementation the resulting
|
## The ``events`` field of the returned ``key`` contains the original events
|
||||||
## ``TSelectorKey.events`` will not contain the original events.
|
## for which the ``fd`` was bound. This is contrary to the ``events`` field
|
||||||
## TODO: This breaks what TSelectorKey means... it's not a key anymore.
|
## of the ``TReadyInfo`` tuple which determines which events are ready
|
||||||
## Rename to TSelectorInfo?
|
## on the ``fd``.
|
||||||
|
|
||||||
if not s.selectImpl.isNil: result = s.selectImpl(s, timeout)
|
if not s.selectImpl.isNil: result = s.selectImpl(s, timeout)
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ type
|
||||||
PSelectSelector* = ref object of PSelector ## Implementation of select()
|
PSelectSelector* = ref object of PSelector ## Implementation of select()
|
||||||
|
|
||||||
proc ssRegister(s: PSelector, fd: cint, events: set[TEvent],
|
proc ssRegister(s: PSelector, fd: cint, events: set[TEvent],
|
||||||
data: var PObject): TSelectorKey =
|
data: PObject): TSelectorKey =
|
||||||
if s.fds.hasKey(fd):
|
if s.fds.hasKey(fd):
|
||||||
raise newException(EInvalidValue, "FD already exists in selector.")
|
raise newException(EInvalidValue, "FD already exists in selector.")
|
||||||
var sk = TSelectorKey(fd: fd, events: events, data: data)
|
var sk = TSelectorKey(fd: fd, events: events, data: data)
|
||||||
|
|
@ -144,19 +144,29 @@ proc newSelectSelector*(): PSelectSelector =
|
||||||
when defined(linux):
|
when defined(linux):
|
||||||
import epoll
|
import epoll
|
||||||
type
|
type
|
||||||
PEpollSelector = ref object of PSelector
|
PEpollSelector* = ref object of PSelector
|
||||||
epollFD: cint
|
epollFD: cint
|
||||||
|
events: array[64, ptr epoll_event]
|
||||||
|
|
||||||
|
TDataWrapper = object
|
||||||
|
fd: cint
|
||||||
|
boundEvents: set[TEvent] ## The events which ``fd`` listens for.
|
||||||
|
data: PObject ## User object.
|
||||||
|
|
||||||
proc esRegister(s: PSelector, fd: cint, events: set[TEvent],
|
proc esRegister(s: PSelector, fd: cint, events: set[TEvent],
|
||||||
data: var PObject): TSelectorKey =
|
data: PObject): TSelectorKey =
|
||||||
var es = PEpollSelector(s)
|
var es = PEpollSelector(s)
|
||||||
var event: epoll_event
|
var event: epoll_event
|
||||||
if EvRead in events:
|
if EvRead in events:
|
||||||
event.events = EPOLLIN
|
event.events = EPOLLIN
|
||||||
if EvWrite in events:
|
if EvWrite in events:
|
||||||
event.events = event.events or EPOLLOUT
|
event.events = event.events or EPOLLOUT
|
||||||
event.data.fd = fd
|
|
||||||
event.data.thePtr = addr(data)
|
var dw = cast[ptr TDataWrapper](alloc0(sizeof(TDataWrapper))) # TODO: This needs to be dealloc'd
|
||||||
|
dw.fd = fd
|
||||||
|
dw.boundEvents = events
|
||||||
|
dw.data = data
|
||||||
|
event.data.thePtr = dw
|
||||||
|
|
||||||
if epoll_ctl(es.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
|
if epoll_ctl(es.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
|
||||||
OSError(OSLastError())
|
OSError(OSLastError())
|
||||||
|
|
@ -176,27 +186,35 @@ when defined(linux):
|
||||||
proc esClose(s: PSelector) =
|
proc esClose(s: PSelector) =
|
||||||
var es = PEpollSelector(s)
|
var es = PEpollSelector(s)
|
||||||
if es.epollFD.close() != 0: OSError(OSLastError())
|
if es.epollFD.close() != 0: OSError(OSLastError())
|
||||||
|
dealloc(addr es.events) # TODO: Test this
|
||||||
|
|
||||||
proc esSelect(s: PSelector, timeout: int): seq[TReadyInfo] =
|
proc esSelect(s: PSelector, timeout: int): seq[TReadyInfo] =
|
||||||
result = @[]
|
result = @[]
|
||||||
var es = PEpollSelector(s)
|
var es = PEpollSelector(s)
|
||||||
|
|
||||||
var events: array[64, epoll_event]
|
let evNum = epoll_wait(es.epollFD, es.events[0], 64.cint, timeout.cint)
|
||||||
let evNum = epoll_wait(es.epollFD, addr events[0], 64.cint, timeout.cint)
|
|
||||||
if evNum < 0: OSError(OSLastError())
|
if evNum < 0: OSError(OSLastError())
|
||||||
for i in 0 .. 63:
|
if evNum == 0: return @[]
|
||||||
|
for i in 0 .. <evNum:
|
||||||
var evSet: set[TEvent] = {}
|
var evSet: set[TEvent] = {}
|
||||||
if (events[i].events and EPOLLIN) == 1: evSet = evSet + {EvRead}
|
if (es.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
|
||||||
if (events[i].events and EPOLLOUT) == 1: evSet = evSet + {EvWrite}
|
if (es.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
|
||||||
let selectorKey = TSelectorKey(fd: events[i].data.fd, events: evSet,
|
let dw = cast[ptr TDataWrapper](es.events[i].data.thePtr)
|
||||||
data: cast[PObject](events[i].data.thePtr))
|
|
||||||
|
let selectorKey = TSelectorKey(fd: dw.fd, events: dw.boundEvents,
|
||||||
|
data: dw.data)
|
||||||
result.add((selectorKey, evSet))
|
result.add((selectorKey, evSet))
|
||||||
|
|
||||||
proc newEpollSelector*(): PEpollSelector =
|
proc newEpollSelector*(): PEpollSelector =
|
||||||
new result
|
new result
|
||||||
result.epollFD = epoll_create(64)
|
result.epollFD = epoll_create(64)
|
||||||
|
result.events = cast[array[64, ptr epoll_event]](alloc0(sizeof(epoll_event)*64))
|
||||||
if result.epollFD < 0:
|
if result.epollFD < 0:
|
||||||
OSError(OSLastError())
|
OSError(OSLastError())
|
||||||
|
result.registerImpl = esRegister
|
||||||
|
result.unregisterImpl = esUnregister
|
||||||
|
result.closeImpl = esClose
|
||||||
|
result.selectImpl = esSelect
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
# Select()
|
# Select()
|
||||||
|
|
@ -205,18 +223,21 @@ when isMainModule:
|
||||||
PSockWrapper = ref object of PObject
|
PSockWrapper = ref object of PObject
|
||||||
sock: TSocket
|
sock: TSocket
|
||||||
|
|
||||||
|
|
||||||
var sock = socket()
|
var sock = socket()
|
||||||
sock.connect("irc.freenode.net", TPort(6667))
|
sock.connect("irc.freenode.net", TPort(6667))
|
||||||
|
|
||||||
var selector = newSelectSelector()
|
var selector = newEpollSelector()
|
||||||
var data = PSockWrapper(sock: sock)
|
var data = PSockWrapper(sock: sock)
|
||||||
let key = selector.register(sock.getFD.cint, {EvRead, EvWrite}, data)
|
let key = selector.register(sock.getFD.cint, {EvRead}, data)
|
||||||
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
let ready = selector.select()
|
let ready = selector.select(1000)
|
||||||
echo ready.len
|
echo ready.len
|
||||||
if ready.len > 0: echo ready[0].repr
|
if ready.len > 0: echo ready[0].events
|
||||||
|
i.inc
|
||||||
|
if i == 6:
|
||||||
|
selector.close()
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue