summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2016-12-17 23:04:34 +0100
committerAraq <rumpf_a@web.de>2016-12-17 23:04:34 +0100
commit24239c23619e9d64562699b5d890fa2575e9c9cb (patch)
tree7b68d65e1bc5c12a465dd29814e6328cb25e30b4 /lib
parent3a4ec7f101f539fb536086b59c84e1b2c095ef82 (diff)
parentd4c33df91996e30ded5f7f2014e7cd49176b5b05 (diff)
downloadNim-24239c23619e9d64562699b5d890fa2575e9c9cb.tar.gz
Merge branch 'devel' into sighashes
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/ioselectors.nim14
-rw-r--r--lib/pure/ioselects/ioselectors_epoll.nim320
-rw-r--r--lib/upcoming/asyncdispatch.nim20
3 files changed, 206 insertions, 148 deletions
diff --git a/lib/pure/ioselectors.nim b/lib/pure/ioselectors.nim
index 744bdbaa1..5745d0b72 100644
--- a/lib/pure/ioselectors.nim
+++ b/lib/pure/ioselectors.nim
@@ -18,10 +18,12 @@
 ## Supported features: files, sockets, pipes, timers, processes, signals
 ## and user events.
 ##
-## Fully supported OS: MacOSX, FreeBSD, OpenBSD, NetBSD, Linux.
+## Fully supported OS: MacOSX, FreeBSD, OpenBSD, NetBSD, Linux (except
+## for Android).
 ##
 ## Partially supported OS: Windows (only sockets and user events),
 ## Solaris (files, sockets, handles and user events).
+## Android (files, sockets, handles and user events).
 ##
 ## TODO: ``/dev/poll``, ``event ports`` and filesystem events.
 
@@ -29,9 +31,11 @@ import os
 
 const hasThreadSupport = compileOption("threads") and defined(threadsafe)
 
-const supportedPlatform = defined(macosx) or defined(freebsd) or
-                          defined(netbsd) or defined(openbsd) or
-                          defined(linux)
+const ioselSupportedPlatform* = defined(macosx) or defined(freebsd) or
+                                defined(netbsd) or defined(openbsd) or
+                                (defined(linux) and not defined(android))
+  ## This constant is used to determine whether the destination platform is
+  ## fully supported by ``ioselectors`` module.
 
 const bsdPlatform = defined(macosx) or defined(freebsd) or
                     defined(netbsd) or defined(openbsd)
@@ -244,7 +248,7 @@ else:
       skey.key.fd = pkeyfd
       skey.key.data = pdata
 
-  when supportedPlatform:
+  when ioselSupportedPlatform:
     template blockSignals(newmask: var Sigset, oldmask: var Sigset) =
       when hasThreadSupport:
         if posix.pthread_sigmask(SIG_BLOCK, newmask, oldmask) == -1:
diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim
index 4bc6e9d51..ceba670fb 100644
--- a/lib/pure/ioselects/ioselectors_epoll.nim
+++ b/lib/pure/ioselects/ioselectors_epoll.nim
@@ -14,27 +14,29 @@ import posix, times
 # Maximum number of events that can be returned
 const MAX_EPOLL_RESULT_EVENTS = 64
 
-type
-  SignalFdInfo* {.importc: "struct signalfd_siginfo",
-                  header: "<sys/signalfd.h>", pure, final.} = object
-    ssi_signo*: uint32
-    ssi_errno*: int32
-    ssi_code*: int32
-    ssi_pid*: uint32
-    ssi_uid*: uint32
-    ssi_fd*: int32
-    ssi_tid*: uint32
-    ssi_band*: uint32
-    ssi_overrun*: uint32
-    ssi_trapno*: uint32
-    ssi_status*: int32
-    ssi_int*: int32
-    ssi_ptr*: uint64
-    ssi_utime*: uint64
-    ssi_stime*: uint64
-    ssi_addr*: uint64
-    pad* {.importc: "__pad".}: array[0..47, uint8]
+when not defined(android):
+  type
+    SignalFdInfo* {.importc: "struct signalfd_siginfo",
+                    header: "<sys/signalfd.h>", pure, final.} = object
+      ssi_signo*: uint32
+      ssi_errno*: int32
+      ssi_code*: int32
+      ssi_pid*: uint32
+      ssi_uid*: uint32
+      ssi_fd*: int32
+      ssi_tid*: uint32
+      ssi_band*: uint32
+      ssi_overrun*: uint32
+      ssi_trapno*: uint32
+      ssi_status*: int32
+      ssi_int*: int32
+      ssi_ptr*: uint64
+      ssi_utime*: uint64
+      ssi_stime*: uint64
+      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>",
@@ -68,12 +70,22 @@ proc timerfd_create(clock_id: ClockId, flags: cint): cint
 proc timerfd_settime(ufd: cint, flags: cint,
                       utmr: var Itimerspec, otmr: var Itimerspec): cint
      {.cdecl, importc: "timerfd_settime", header: "<sys/timerfd.h>".}
-proc signalfd(fd: cint, mask: var Sigset, flags: cint): cint
-     {.cdecl, importc: "signalfd", header: "<sys/signalfd.h>".}
 proc eventfd(count: cuint, flags: cint): cint
      {.cdecl, importc: "eventfd", header: "<sys/eventfd.h>".}
-proc ulimit(cmd: cint): clong
-     {.importc: "ulimit", header: "<ulimit.h>", varargs.}
+
+when not defined(android):
+  proc signalfd(fd: cint, mask: var Sigset, flags: cint): cint
+       {.cdecl, importc: "signalfd", header: "<sys/signalfd.h>".}
+
+var RLIMIT_NOFILE {.importc: "RLIMIT_NOFILE",
+                    header: "<sys/resource.h>".}: cint
+type
+  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
+     {.importc: "getrlimit",header: "<sys/resource.h>".}
 
 when hasThreadSupport:
   type
@@ -97,7 +109,10 @@ type
   SelectEvent* = ptr SelectEventImpl
 
 proc newSelector*[T](): Selector[T] =
-  var maxFD = int(ulimit(4, 0))
+  var a = rlimit()
+  if getrlimit(RLIMIT_NOFILE, a) != 0:
+    raiseOsError(osLastError())
+  var maxFD = int(a.rlim_max)
   doAssert(maxFD > 0)
 
   var epollFD = epoll_create(MAX_EPOLL_RESULT_EVENTS)
@@ -194,39 +209,53 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
   doAssert(pkey.ident != 0)
 
   if pkey.events != {}:
-    if pkey.events * {Event.Read, Event.Write} != {}:
-      var epv = epoll_event()
-      if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
-        raiseOSError(osLastError())
-      dec(s.count)
-    elif Event.Timer in pkey.events:
-      var epv = epoll_event()
-      if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
-        raiseOSError(osLastError())
-      discard posix.close(fdi.cint)
-      dec(s.count)
-    elif Event.Signal in pkey.events:
-      var epv = epoll_event()
-      if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
-        raiseOSError(osLastError())
-      var nmask, omask: Sigset
-      discard sigemptyset(nmask)
-      discard sigemptyset(omask)
-      discard sigaddset(nmask, cint(s.fds[fdi].param))
-      unblockSignals(nmask, omask)
-      discard posix.close(fdi.cint)
-      dec(s.count)
-    elif Event.Process in pkey.events:
-      var epv = epoll_event()
-      if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
-        raiseOSError(osLastError())
-      var nmask, omask: Sigset
-      discard sigemptyset(nmask)
-      discard sigemptyset(omask)
-      discard sigaddset(nmask, SIGCHLD)
-      unblockSignals(nmask, omask)
-      discard posix.close(fdi.cint)
-      dec(s.count)
+    when not defined(android):
+      if pkey.events * {Event.Read, Event.Write} != {}:
+        var epv = epoll_event()
+        if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
+          raiseOSError(osLastError())
+        dec(s.count)
+      elif Event.Timer in pkey.events:
+        var epv = epoll_event()
+        if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
+          raiseOSError(osLastError())
+        discard posix.close(fdi.cint)
+        dec(s.count)
+      elif Event.Signal in pkey.events:
+        var epv = epoll_event()
+        if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
+          raiseOSError(osLastError())
+        var nmask, omask: Sigset
+        discard sigemptyset(nmask)
+        discard sigemptyset(omask)
+        discard sigaddset(nmask, cint(s.fds[fdi].param))
+        unblockSignals(nmask, omask)
+        discard posix.close(fdi.cint)
+        dec(s.count)
+      elif Event.Process in pkey.events:
+        var epv = epoll_event()
+        if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
+          raiseOSError(osLastError())
+        var nmask, omask: Sigset
+        discard sigemptyset(nmask)
+        discard sigemptyset(omask)
+        discard sigaddset(nmask, SIGCHLD)
+        unblockSignals(nmask, omask)
+        discard posix.close(fdi.cint)
+        dec(s.count)
+    else:
+      if pkey.events * {Event.Read, Event.Write} != {}:
+        var epv = epoll_event()
+        if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
+          raiseOSError(osLastError())
+        dec(s.count)
+      elif Event.Timer in pkey.events:
+        var epv = epoll_event()
+        if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
+          raiseOSError(osLastError())
+        discard posix.close(fdi.cint)
+        dec(s.count)
+
   pkey.ident = 0
   pkey.events = {}
 
@@ -280,60 +309,61 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool,
   inc(s.count)
   result = fdi
 
-proc registerSignal*[T](s: Selector[T], signal: int,
-                        data: T): int {.discardable.} =
-  var
-    nmask: Sigset
-    omask: Sigset
+when not defined(android):
+  proc registerSignal*[T](s: Selector[T], signal: int,
+                          data: T): int {.discardable.} =
+    var
+      nmask: Sigset
+      omask: Sigset
 
-  discard sigemptyset(nmask)
-  discard sigemptyset(omask)
-  discard sigaddset(nmask, cint(signal))
-  blockSignals(nmask, omask)
+    discard sigemptyset(nmask)
+    discard sigemptyset(omask)
+    discard sigaddset(nmask, cint(signal))
+    blockSignals(nmask, omask)
 
-  let fdi = signalfd(-1, nmask, 0).int
-  if fdi == -1:
-    raiseOSError(osLastError())
-  setNonBlocking(fdi.cint)
+    let fdi = signalfd(-1, nmask, 0).int
+    if fdi == -1:
+      raiseOSError(osLastError())
+    setNonBlocking(fdi.cint)
 
-  s.checkFd(fdi)
-  doAssert(s.fds[fdi].ident == 0)
+    s.checkFd(fdi)
+    doAssert(s.fds[fdi].ident == 0)
 
-  var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
-  epv.data.u64 = fdi.uint
-  if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) == -1:
-    raiseOSError(osLastError())
-  s.setKey(fdi, signal, {Event.Signal}, signal, data)
-  inc(s.count)
-  result = fdi
+    var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
+    epv.data.u64 = fdi.uint
+    if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) == -1:
+      raiseOSError(osLastError())
+    s.setKey(fdi, signal, {Event.Signal}, signal, data)
+    inc(s.count)
+    result = fdi
 
-proc registerProcess*[T](s: Selector, pid: int,
-                         data: T): int {.discardable.} =
-  var
-    nmask: Sigset
-    omask: Sigset
+  proc registerProcess*[T](s: Selector, pid: int,
+                           data: T): int {.discardable.} =
+    var
+      nmask: Sigset
+      omask: Sigset
 
-  discard sigemptyset(nmask)
-  discard sigemptyset(omask)
-  discard sigaddset(nmask, posix.SIGCHLD)
-  blockSignals(nmask, omask)
+    discard sigemptyset(nmask)
+    discard sigemptyset(omask)
+    discard sigaddset(nmask, posix.SIGCHLD)
+    blockSignals(nmask, omask)
 
-  let fdi = signalfd(-1, nmask, 0).int
-  if fdi == -1:
-    raiseOSError(osLastError())
-  setNonBlocking(fdi.cint)
+    let fdi = signalfd(-1, nmask, 0).int
+    if fdi == -1:
+      raiseOSError(osLastError())
+    setNonBlocking(fdi.cint)
 
-  s.checkFd(fdi)
-  doAssert(s.fds[fdi].ident == 0)
+    s.checkFd(fdi)
+    doAssert(s.fds[fdi].ident == 0)
 
-  var epv = epoll_event(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) == -1:
-    raiseOSError(osLastError())
-  s.setKey(fdi, pid, {Event.Process, Event.Oneshot}, pid, data)
-  inc(s.count)
-  result = fdi
+    var epv = epoll_event(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) == -1:
+      raiseOSError(osLastError())
+    s.setKey(fdi, pid, {Event.Process, Event.Oneshot}, pid, data)
+    inc(s.count)
+    result = fdi
 
 proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
   let fdi = int(ev.efd)
@@ -382,40 +412,60 @@ proc selectInto*[T](s: Selector[T], timeout: int,
         events.incl(Event.Error)
       if (pevents and EPOLLOUT) != 0:
         events.incl(Event.Write)
-      if (pevents and EPOLLIN) != 0:
-        if Event.Read in skey.events:
-          events.incl(Event.Read)
-        elif Event.Timer in skey.events:
-          var data: uint64 = 0
-          if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64):
-            raiseOSError(osLastError())
-          events = {Event.Timer}
-        elif Event.Signal in skey.events:
-          var data = SignalFdInfo()
-          if posix.read(fdi.cint, addr data,
-                        sizeof(SignalFdInfo)) != sizeof(SignalFdInfo):
-            raiseOsError(osLastError())
-          events = {Event.Signal}
-        elif Event.Process in skey.events:
-          var data = SignalFdInfo()
-          if posix.read(fdi.cint, addr data,
-                        sizeof(SignalFdInfo)) != sizeof(SignalFdInfo):
-            raiseOsError(osLastError())
-          if cast[int](data.ssi_pid) == skey.param:
-            events = {Event.Process}
-          else:
-            inc(i)
-            continue
-        elif Event.User in skey.events:
-          var data: uint64 = 0
-          if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64):
-            let err = osLastError()
-            if err == OSErrorCode(EAGAIN):
+      when not defined(android):
+        if (pevents and EPOLLIN) != 0:
+          if Event.Read in skey.events:
+            events.incl(Event.Read)
+          elif Event.Timer in skey.events:
+            var data: uint64 = 0
+            if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64):
+              raiseOSError(osLastError())
+            events = {Event.Timer}
+          elif Event.Signal in skey.events:
+            var data = SignalFdInfo()
+            if posix.read(fdi.cint, addr data,
+                          sizeof(SignalFdInfo)) != sizeof(SignalFdInfo):
+              raiseOsError(osLastError())
+            events = {Event.Signal}
+          elif Event.Process in skey.events:
+            var data = SignalFdInfo()
+            if posix.read(fdi.cint, addr data,
+                          sizeof(SignalFdInfo)) != sizeof(SignalFdInfo):
+              raiseOsError(osLastError())
+            if cast[int](data.ssi_pid) == skey.param:
+              events = {Event.Process}
+            else:
               inc(i)
               continue
-            else:
-              raiseOSError(err)
-          events = {Event.User}
+          elif Event.User in skey.events:
+            var data: uint64 = 0
+            if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64):
+              let err = osLastError()
+              if err == OSErrorCode(EAGAIN):
+                inc(i)
+                continue
+              else:
+                raiseOSError(err)
+            events = {Event.User}
+      else:
+        if (pevents and EPOLLIN) != 0:
+          if Event.Read in skey.events:
+            events.incl(Event.Read)
+          elif Event.Timer in skey.events:
+            var data: uint64 = 0
+            if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64):
+              raiseOSError(osLastError())
+            events = {Event.Timer}
+          elif Event.User in skey.events:
+            var data: uint64 = 0
+            if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64):
+              let err = osLastError()
+              if err == OSErrorCode(EAGAIN):
+                inc(i)
+                continue
+              else:
+                raiseOSError(err)
+            events = {Event.User}
 
       skey.key.events = events
       results[k] = skey.key
diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim
index 9a35cf3c8..ca5c1f64c 100644
--- a/lib/upcoming/asyncdispatch.nim
+++ b/lib/upcoming/asyncdispatch.nim
@@ -1092,11 +1092,6 @@ else:
   import ioselectors
   from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
                     MSG_NOSIGNAL
-
-  const supportedPlatform = defined(linux) or defined(freebsd) or
-                            defined(netbsd) or defined(openbsd) or
-                            defined(macosx)
-
   type
     AsyncFD* = distinct cint
     Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.}
@@ -1191,7 +1186,7 @@ else:
     var keys: array[64, ReadyKey[AsyncData]]
 
     let p = getGlobalDispatcher()
-    when supportedPlatform:
+    when ioselSupportedPlatform:
       let customSet = {Event.Timer, Event.Signal, Event.Process,
                        Event.Vnode, Event.User}
 
@@ -1225,7 +1220,7 @@ else:
               else:
                 break
 
-        when supportedPlatform:
+        when ioselSupportedPlatform:
           if (customSet * events) != {}:
             for node in keys[i].data.readCBs[].nodes():
               let cb = node.value
@@ -1234,6 +1229,15 @@ else:
               if cb(fd.AsyncFD):
                 keys[i].data.readCBs[].remove(node)
                 p.selector.unregister(fd)
+        else:
+          if Event.User in events or events == {Event.Error}:
+            for node in keys[i].data.readCBs[].nodes():
+              let cb = node.value
+              custom = true
+              if cb != nil:
+                if cb(fd.AsyncFD):
+                  keys[i].data.readCBs[].remove(node)
+                  p.selector.unregister(fd)
 
         # because state `data` can be modified in callback we need to update
         # descriptor events with currently registered callbacks.
@@ -1496,7 +1500,7 @@ else:
     addRead(socket, cb)
     return retFuture
 
-  when supportedPlatform:
+  when ioselSupportedPlatform:
 
     proc addTimer*(timeout: int, oneshot: bool, cb: Callback) =
       ## Start watching for timeout expiration, and then call the