summary refs log tree commit diff stats
path: root/lib/pure/selectors.nim
diff options
context:
space:
mode:
authorAdam Strzelecki <ono@java.pl>2015-09-29 19:27:41 +0200
committerAdam Strzelecki <ono@java.pl>2015-09-29 19:27:41 +0200
commit248f52fea7f22beac1ac75022b6b4d49964f6071 (patch)
tree13d6e573a49b040ca2cd4c1c066158985751fccb /lib/pure/selectors.nim
parent900ea8103014dcd8e7f72c774689743df2d3075c (diff)
downloadNim-248f52fea7f22beac1ac75022b6b4d49964f6071.tar.gz
Selectors using OS X & Free/Open/NetBSD kqueue API
Diffstat (limited to 'lib/pure/selectors.nim')
-rw-r--r--lib/pure/selectors.nim82
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index bfc393a96..2ee8f1180 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -13,6 +13,8 @@ import os, unsigned, hashes
 
 when defined(linux):
   import posix, epoll
+elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  import posix, kqueue, times
 elif defined(windows):
   import winlean
 else:
@@ -204,6 +206,86 @@ elif defined(linux):
     ## Retrieves the selector key for ``fd``.
     return s.fds[fd]
 
+elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  type
+    Selector* = object
+      kqFD: cint
+      events: array[64, KEvent]
+      when MultiThreaded:
+        fds: SharedTable[SocketHandle, SelectorKey]
+      else:
+        fds: Table[SocketHandle, SelectorKey]
+
+  template modifyKQueue(kqFD: cint, fd: SocketHandle, event: Event,
+                        op: cushort) =
+    var kev = KEvent(ident:  fd.cuint,
+                     filter: if event == EvRead: EVFILT_READ else: EVFILT_WRITE,
+                     flags:  op)
+    if kevent(kqFD, addr kev, 1, nil, 0, nil) == -1:
+      raiseOSError(osLastError())
+
+  proc register*(s: var Selector, fd: SocketHandle, events: set[Event],
+                 data: SelectorData) =
+    for event in events:
+      modifyKQueue(s.kqFD, fd, event, EV_ADD)
+    s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
+
+  proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
+    let previousEvents = s.fds[fd].events
+    if previousEvents != events:
+      for event in events-previousEvents:
+        modifyKQueue(s.kqFD, fd, event, EV_ADD)
+      for event in previousEvents-events:
+        modifyKQueue(s.kqFD, fd, event, EV_DELETE)
+      s.fds.mget(fd).events = events
+
+  proc unregister*(s: var Selector, fd: SocketHandle) =
+    for event in s.fds[fd].events:
+      modifyKQueue(s.kqFD, fd, event, EV_DELETE)
+    s.fds.del(fd)
+
+  proc close*(s: var Selector) =
+    when MultiThreaded: deinitSharedTable(s.fds)
+    if s.kqFD.close() != 0: raiseOSError(osLastError())
+
+  proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
+    result = @[]
+    var tv = Timespec(tv_sec: timeout.Time, tv_nsec: 0)
+    let evNum = kevent(s.kqFD, nil, 0, addr s.events[0], 64.cint, addr tv)
+    if evNum < 0:
+      let err = osLastError()
+      if err.cint == EINTR:
+        return @[]
+      raiseOSError(err)
+    if evNum == 0: return @[]
+    for i in 0 .. <evNum:
+      let fd = s.events[i].ident.SocketHandle
+
+      var evSet: set[Event] = {}
+      if  (s.events[i].flags and EV_EOF) != 0: evSet = evSet + {EvError}
+      if   s.events[i].filter == EVFILT_READ:  evSet = evSet + {EvRead}
+      elif s.events[i].filter == EVFILT_WRITE: evSet = evSet + {EvWrite}
+      let selectorKey = s.fds[fd]
+      assert selectorKey.fd != 0.SocketHandle
+      result.add((selectorKey, evSet))
+
+  proc newSelector*(): Selector =
+    result.kqFD = kqueue()
+    if result.kqFD < 0:
+      raiseOSError(osLastError())
+    when MultiThreaded:
+      result.fds = initSharedTable[SocketHandle, SelectorKey]()
+    else:
+      result.fds = initTable[SocketHandle, SelectorKey]()
+
+  proc contains*(s: Selector, fd: SocketHandle): bool =
+    ## Determines whether selector contains a file descriptor.
+    s.fds.hasKey(fd) # and s.fds[fd].events != {}
+
+  proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
+    ## Retrieves the selector key for ``fd``.
+    return s.fds[fd]
+
 elif not defined(nimdoc):
   # TODO: kqueue for bsd/mac os x.
   type