summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-02-25 01:06:35 +0100
committerAraq <rumpf_a@web.de>2014-02-25 01:06:35 +0100
commit10768904eb65da1899d0d48cc1a2f3547af3bef0 (patch)
tree79676143be1663cacdbb5a8790451fde4e7366bc /lib
parentab72377ce64cf2b563ea90204925b793082971cb (diff)
parente6b0b7ecc9bb81d94eec19fbc4fc62e104f59253 (diff)
downloadNim-10768904eb65da1899d0d48cc1a2f3547af3bef0.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Conflicts:
	lib/system/jssys.nim
Diffstat (limited to 'lib')
-rw-r--r--lib/posix/epoll.nim8
-rw-r--r--lib/posix/linux.nim25
-rw-r--r--lib/posix/posix.nim3
-rw-r--r--lib/pure/asyncio2.nim231
-rw-r--r--lib/pure/net.nim17
-rw-r--r--lib/pure/osproc.nim273
-rw-r--r--lib/pure/pegs.nim8
-rw-r--r--lib/pure/selectors.nim355
-rw-r--r--lib/pure/sockets2.nim16
-rw-r--r--lib/system.nim6
-rw-r--r--lib/system/jssys.nim49
11 files changed, 662 insertions, 329 deletions
diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim
index d50394f60..366521551 100644
--- a/lib/posix/epoll.nim
+++ b/lib/posix/epoll.nim
@@ -7,6 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
+from posix import TSocketHandle
+
 const
   EPOLLIN* = 0x00000001
   EPOLLPRI* = 0x00000002
@@ -33,8 +35,8 @@ const
 type 
   epoll_data* {.importc: "union epoll_data", 
       header: "<sys/epoll.h>", pure, final.} = object # TODO: This is actually a union.
-    thePtr* {.importc: "ptr".}: pointer # \
-    #fd*: cint
+    #thePtr* {.importc: "ptr".}: pointer
+    fd*: cint # \
     #u32*: uint32
     #u64*: uint64
 
@@ -54,7 +56,7 @@ proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1",
   ## Same as epoll_create but with an FLAGS parameter.  The unused SIZE
   ##   parameter has been dropped.  
 
-proc epoll_ctl*(epfd: cint; op: cint; fd: cint; event: ptr epoll_event): cint {.
+proc epoll_ctl*(epfd: cint; op: cint; fd: cint | TSocketHandle; event: ptr epoll_event): cint {.
     importc: "epoll_ctl", header: "<sys/epoll.h>".}
   ## Manipulate an epoll instance "epfd". Returns 0 in case of success,
   ##   -1 in case of error ( the "errno" variable will contain the
diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim
new file mode 100644
index 000000000..1ed1af3b6
--- /dev/null
+++ b/lib/posix/linux.nim
@@ -0,0 +1,25 @@
+import posix
+
+const
+  CSIGNAL* = 0x000000FF
+  CLONE_VM* = 0x00000100
+  CLONE_FS* = 0x00000200
+  CLONE_FILES* = 0x00000400
+  CLONE_SIGHAND* = 0x00000800
+  CLONE_PTRACE* = 0x00002000
+  CLONE_VFORK* = 0x00004000
+  CLONE_PARENT* = 0x00008000
+  CLONE_THREAD* = 0x00010000
+  CLONE_NEWNS* = 0x00020000
+  CLONE_SYSVSEM* = 0x00040000
+  CLONE_SETTLS* = 0x00080000
+  CLONE_PARENT_SETTID* = 0x00100000
+  CLONE_CHILD_CLEARTID* = 0x00200000
+  CLONE_DETACHED* = 0x00400000
+  CLONE_UNTRACED* = 0x00800000
+  CLONE_CHILD_SETTID* = 0x01000000
+  CLONE_STOPPED* = 0x02000000
+
+# fn should be of type proc (a2: pointer): void {.cdecl.}
+proc clone*(fn: pointer; child_stack: pointer; flags: cint;
+            arg: pointer; ptid: ptr TPid; tls: pointer; ctid: ptr TPid): cint {.importc, header: "<sched.h>".}
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 41260b36f..3865a6bff 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -2066,6 +2066,7 @@ proc pthread_spin_unlock*(a1: ptr Tpthread_spinlock): cint {.
 proc pthread_testcancel*() {.importc, header: "<pthread.h>".}
 
 
+proc exitnow*(code: int): void {.importc: "_exit", header: "<unistd.h>".}
 proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".}
 proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
 proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
@@ -2356,7 +2357,7 @@ proc FD_ZERO*(a1: var TFdSet) {.importc, header: "<sys/select.h>".}
 
 proc pselect*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimespec,
          a6: var Tsigset): cint  {.importc, header: "<sys/select.h>".}
-proc select*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimeval): cint {.
+proc select*(a1: cint | TSocketHandle, a2, a3, a4: ptr TFdSet, a5: ptr Ttimeval): cint {.
              importc, header: "<sys/select.h>".}
 
 when hasSpawnH:
diff --git a/lib/pure/asyncio2.nim b/lib/pure/asyncio2.nim
index 8541b2ba7..12d4cb5a3 100644
--- a/lib/pure/asyncio2.nim
+++ b/lib/pure/asyncio2.nim
@@ -9,8 +9,6 @@
 
 import os, oids, tables, strutils, macros
 
-import winlean
-
 import sockets2, net
 
 ## Asyncio2 
@@ -93,7 +91,10 @@ proc failed*[T](future: PFuture[T]): bool =
   ## Determines whether ``future`` completed with an error.
   future.error != nil
 
-when defined(windows):
+# TODO: Get rid of register. Do it implicitly.
+
+when defined(windows) or defined(nimdoc):
+  import winlean
   type
     TCompletionKey = dword
 
@@ -293,7 +294,10 @@ when defined(windows):
   proc recv*(p: PDispatcher, socket: TSocketHandle, size: int,
              flags: int = 0): PFuture[string] =
     ## Reads ``size`` bytes from ``socket``. Returned future will complete once
-    ## all of the requested data is read.
+    ## all of the requested data is read. If socket is disconnected during the
+    ## recv operation then the future may complete with only a part of the
+    ## requested data read. If socket is disconnected and no data is available
+    ## to be read then the future will complete with a value of ``""``.
 
     var retFuture = newFuture[string]()
     
@@ -448,24 +452,206 @@ when defined(windows):
 
     return retFuture
 
-  proc accept*(p: PDispatcher, socket: TSocketHandle): PFuture[TSocketHandle] =
-    ## Accepts a new connection. Returns a future containing the client socket
-    ## corresponding to that connection.
-    ## The future will complete when the connection is successfully accepted.
-    var retFut = newFuture[TSocketHandle]()
-    var fut = p.acceptAddr(socket)
-    fut.callback =
-      proc (future: PFuture[tuple[address: string, client: TSocketHandle]]) =
-        assert future.finished
-        if future.failed:
-          retFut.fail(future.error)
-        else:
-          retFut.complete(future.read.client)
-    return retFut
-
   initAll()
 else:
-  # TODO: Selectors.
+  import selectors
+  from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK
+  type
+    TCallback = proc (sock: TSocketHandle): bool {.closure.}
+
+    PData* = ref object of PObject
+      sock: TSocketHandle
+      readCBs: seq[TCallback]
+      writeCBs: seq[TCallback]
+
+    PDispatcher* = ref object
+      selector: PSelector
+
+  proc newDispatcher*(): PDispatcher =
+    new result
+    result.selector = newSelector()
+
+  proc update(p: PDispatcher, sock: TSocketHandle, events: set[TEvent]) =
+    assert sock in p.selector
+    echo("Update: ", events)
+    if events == {}:
+      discard p.selector.unregister(sock)
+    else:
+      discard p.selector.update(sock, events)
+  
+  proc addRead(p: PDispatcher, sock: TSocketHandle, cb: TCallback) =
+    if sock notin p.selector:
+      var data = PData(sock: sock, readCBs: @[cb], writeCBs: @[])
+      p.selector.register(sock, {EvRead}, data.PObject)
+    else:
+      p.selector[sock].data.PData.readCBs.add(cb)
+      p.update(sock, p.selector[sock].events + {EvRead})
+  
+  proc addWrite(p: PDispatcher, sock: TSocketHandle, cb: TCallback) =
+    if sock notin p.selector:
+      var data = PData(sock: sock, readCBs: @[], writeCBs: @[cb])
+      p.selector.register(sock, {EvWrite}, data.PObject)
+    else:
+      p.selector[sock].data.PData.writeCBs.add(cb)
+      p.update(sock, p.selector[sock].events + {EvWrite})
+  
+  proc poll*(p: PDispatcher, timeout = 500) =
+    for info in p.selector.select(timeout):
+      let data = PData(info.key.data)
+      assert data.sock == info.key.fd
+      echo("R: ", data.readCBs.len, " W: ", data.writeCBs.len, ". ", info.events)
+      
+      if EvRead in info.events:
+        var newReadCBs: seq[TCallback] = @[]
+        for cb in data.readCBs:
+          if not cb(data.sock):
+            # Callback wants to be called again.
+            newReadCBs.add(cb)
+        data.readCBs = newReadCBs
+      
+      if EvWrite in info.events:
+        var newWriteCBs: seq[TCallback] = @[]
+        for cb in data.writeCBs:
+          if not cb(data.sock):
+            # Callback wants to be called again.
+            newWriteCBs.add(cb)
+        data.writeCBs = newWriteCBs
+  
+      var newEvents: set[TEvent]
+      if data.readCBs.len != 0: newEvents = {EvRead}
+      if data.writeCBs.len != 0: newEvents = newEvents + {EvWrite}
+      p.update(data.sock, newEvents)
+  
+  proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort,
+    af = AF_INET): PFuture[int] =
+    var retFuture = newFuture[int]()
+    
+    proc cb(sock: TSocketHandle): bool =
+      # We have connected.
+      retFuture.complete(0)
+      return true
+    
+    var aiList = getAddrInfo(address, port, af)
+    var success = false
+    var lastError: TOSErrorCode
+    var it = aiList
+    while it != nil:
+      var ret = connect(socket, it.ai_addr, it.ai_addrlen.TSocklen)
+      if ret == 0:
+        # Request to connect completed immediately.
+        success = true
+        retFuture.complete(0)
+        break
+      else:
+        lastError = osLastError()
+        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+          success = true
+          addWrite(p, socket, cb)
+          break
+        else:
+          success = false
+      it = it.ai_next
+
+    dealloc(aiList)
+    if not success:
+      retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+    return retFuture
+
+  proc recv*(p: PDispatcher, socket: TSocketHandle, size: int,
+             flags: int = 0): PFuture[string] =
+    var retFuture = newFuture[string]()
+    
+    var readBuffer = newString(size)
+    var sizeRead = 0
+    
+    proc cb(sock: TSocketHandle): bool =
+      result = true
+      let netSize = size - sizeRead
+      let res = recv(sock, addr readBuffer[sizeRead], netSize, flags.cint)
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: 
+          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      elif res == 0:
+        # Disconnected
+        if sizeRead == 0:
+          retFuture.complete("")
+        else:
+          readBuffer.setLen(sizeRead)
+          retFuture.complete(readBuffer)
+      else:
+        sizeRead.inc(res)
+        if res != netSize:
+          result = false # We want to read all the data requested.
+        else:
+          retFuture.complete(readBuffer)
+  
+    addRead(p, socket, cb)
+    return retFuture
+
+  proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[int] =
+    var retFuture = newFuture[int]()
+    
+    var written = 0
+    
+    proc cb(sock: TSocketHandle): bool =
+      result = true
+      let netSize = data.len-written
+      var d = data.cstring
+      let res = send(sock, addr d[written], netSize, 0.cint)
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      else:
+        written.inc(res)
+        if res != netSize:
+          result = false # We still have data to send.
+        else:
+          retFuture.complete(0)
+    addWrite(p, socket, cb)
+    return retFuture
+        
+
+  proc acceptAddr*(p: PDispatcher, socket: TSocketHandle): 
+      PFuture[tuple[address: string, client: TSocketHandle]] =
+    var retFuture = newFuture[tuple[address: string, client: TSocketHandle]]()
+    proc cb(sock: TSocketHandle): bool =
+      result = true
+      var sockAddress: Tsockaddr_in
+      var addrLen = sizeof(sockAddress).TSocklen
+      var client = accept(sock, cast[ptr TSockAddr](addr(sockAddress)),
+                          addr(addrLen))
+      if client == osInvalidSocket:
+        let lastError = osLastError()
+        assert lastError.int32 notin {EWOULDBLOCK, EAGAIN}
+        if lastError.int32 == EINTR:
+          return false
+        else:
+          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+      else:
+        retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client))
+    addRead(p, socket, cb)
+    return retFuture
+
+proc accept*(p: PDispatcher, socket: TSocketHandle): PFuture[TSocketHandle] =
+  ## Accepts a new connection. Returns a future containing the client socket
+  ## corresponding to that connection.
+  ## The future will complete when the connection is successfully accepted.
+  var retFut = newFuture[TSocketHandle]()
+  var fut = p.acceptAddr(socket)
+  fut.callback =
+    proc (future: PFuture[tuple[address: string, client: TSocketHandle]]) =
+      assert future.finished
+      if future.failed:
+        retFut.fail(future.error)
+      else:
+        retFut.complete(future.read.client)
+  return retFut
 
 # -- Await Macro
 
@@ -665,8 +851,7 @@ when isMainModule:
   
   var p = newDispatcher()
   var sock = socket()
-  #sock.setBlocking false
-  p.register(sock)
+  sock.setBlocking false
 
 
   when false:
@@ -706,7 +891,7 @@ when isMainModule:
             var recvF = p.recv(sock, 10)
             recvF.callback =
               proc (future: PFuture[string]) =
-                echo("Read: ", future.read)
+                echo("Read ", future.read.len, ": ", future.read.repr)
 
     else:
 
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index bdcae677e..0ec007009 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -37,4 +37,19 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
     if bindAddr(socket, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32:
       dealloc(aiList)
       osError(osLastError())
-    dealloc(aiList)
\ No newline at end of file
+    dealloc(aiList)
+
+proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].} =
+  ## Sets blocking mode on socket
+  when defined(Windows):
+    var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
+    if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
+      osError(osLastError())
+  else: # BSD sockets
+    var x: int = fcntl(s, F_GETFL, 0)
+    if x == -1:
+      osError(osLastError())
+    else:
+      var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
+      if fcntl(s, F_SETFL, mode) == -1:
+        osError(osLastError())
\ No newline at end of file
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 9a43c0a7d..2a685f3fb 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -13,13 +13,16 @@
 include "system/inclrtl"
 
 import
-  strutils, os, strtabs, streams, sequtils
+  strutils, os, strtabs, streams
 
 when defined(windows):
   import winlean
 else:
   import posix
 
+when defined(linux):
+  import linux
+
 type
   TProcess = object of TObject
     when defined(windows):
@@ -44,7 +47,7 @@ type
     poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
     poParentStreams      ## use the parent's streams
 
-template poUseShell*: TProcessOption {.deprecated.} = poUsePath
+const poUseShell* {.deprecated.} = poUsePath
   ## Deprecated alias for poUsePath.
 
 proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
@@ -590,6 +593,23 @@ elif not defined(useNimRtl):
       copyMem(result[i], addr(x[0]), x.len+1)
       inc(i)
 
+  type TStartProcessData = object
+    sysCommand: cstring
+    sysArgs: cstringArray
+    sysEnv: cstringArray
+    workingDir: cstring
+    pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint]
+    optionPoUsePath: bool
+    optionPoParentStreams: bool
+    optionPoStdErrToStdOut: bool
+
+  proc startProcessAuxSpawn(data: TStartProcessData): TPid {.tags: [FExecIO, FReadEnv].}
+  proc startProcessAuxFork(data: TStartProcessData): TPid {.tags: [FExecIO, FReadEnv].}
+  {.push stacktrace: off, profiler: off.}
+  proc startProcessAfterFork(data: ptr TStartProcessData) {.
+    tags: [FExecIO, FReadEnv], cdecl.}
+  {.pop.}
+
   proc startProcess(command: string,
                  workingDir: string = "",
                  args: openArray[string] = [],
@@ -604,100 +624,48 @@ elif not defined(useNimRtl):
          pipe(pStderr) != 0'i32:
         osError(osLastError())
 
-    var sys_command: string
-    var sys_args_raw: seq[string]
+    var sysCommand: string
+    var sysArgsRaw: seq[string]
     if poEvalCommand in options:
-      sys_command = "/bin/sh"
-      sys_args_raw = @[sys_command, "-c", command]
+      sysCommand = "/bin/sh"
+      sysArgsRaw = @[sysCommand, "-c", command]
       assert args.len == 0
     else:
-      sys_command = command
-      sys_args_raw = @[command]
+      sysCommand = command
+      sysArgsRaw = @[command]
       for arg in args.items:
-        sys_args_raw.add arg
-
-    var sys_args = allocCStringArray(sys_args_raw)
-    finally: deallocCStringArray(sys_args)
+        sysArgsRaw.add arg
 
     var pid: TPid
-    when defined(posix_spawn) and not defined(useFork):
-      var attr: Tposix_spawnattr
-      var fops: Tposix_spawn_file_actions
-
-      template chck(e: expr) =
-        if e != 0'i32: osError(osLastError())
-
-      chck posix_spawn_file_actions_init(fops)
-      chck posix_spawnattr_init(attr)
-
-      var mask: Tsigset
-      chck sigemptyset(mask)
-      chck posix_spawnattr_setsigmask(attr, mask)
-      chck posix_spawnattr_setpgroup(attr, 0'i32)
-
-      chck posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK or
-                                          POSIX_SPAWN_SETSIGMASK or
-                                          POSIX_SPAWN_SETPGROUP)
-
-      if poParentStreams notin options:
-        chck posix_spawn_file_actions_addclose(fops, pStdin[writeIdx])
-        chck posix_spawn_file_actions_adddup2(fops, pStdin[readIdx], readIdx)
-        chck posix_spawn_file_actions_addclose(fops, pStdout[readIdx])
-        chck posix_spawn_file_actions_adddup2(fops, pStdout[writeIdx], writeIdx)
-        chck posix_spawn_file_actions_addclose(fops, pStderr[readIdx])
-        if poStdErrToStdOut in options:
-          chck posix_spawn_file_actions_adddup2(fops, pStdout[writeIdx], 2)
-        else:
-          chck posix_spawn_file_actions_adddup2(fops, p_stderr[writeIdx], 2)
-
-      var sys_env = if env == nil: envToCStringArray() else: envToCStringArray(env)
-      var res: cint
-      # This is incorrect!
-      if workingDir.len > 0: os.setCurrentDir(workingDir)
-      if poUsePath in options:
-        res = posix_spawnp(pid, sys_command, fops, attr, sys_args, sys_env)
+
+    var sysArgs = allocCStringArray(sysArgsRaw)
+    finally: deallocCStringArray(sysArgs)
+
+    var sysEnv = if env == nil:
+        envToCStringArray()
       else:
-        res = posix_spawn(pid, sys_command, fops, attr, sys_args, sys_env)
-      deallocCStringArray(sys_env)
-      discard posix_spawn_file_actions_destroy(fops)
-      discard posix_spawnattr_destroy(attr)
-      chck res
+        envToCStringArray(env)
+
+    finally: deallocCStringArray(sysEnv)
+
+    var data: TStartProcessData
+    data.sysCommand = sysCommand
+    data.sysArgs = sysArgs
+    data.sysEnv = sysEnv
+    data.pStdin = pStdin
+    data.pStdout = pStdout
+    data.pStderr = pStderr
+    data.optionPoParentStreams = poParentStreams in options
+    data.optionPoUsePath = poUsePath in options
+    data.optionPoStdErrToStdOut = poStdErrToStdOut in options
+    data.workingDir = workingDir
+
 
+    when defined(posix_spawn) and not defined(useFork) and not defined(useClone) and not defined(linux):
+      pid = startProcessAuxSpawn(data)
     else:
-      pid = fork()
-      if pid < 0: osError(osLastError())
-      if pid == 0:
-        ## child process:
-
-        if poParentStreams notin options:
-          discard close(p_stdin[writeIdx])
-          if dup2(p_stdin[readIdx], readIdx) < 0: osError(osLastError())
-          discard close(p_stdout[readIdx])
-          if dup2(p_stdout[writeIdx], writeIdx) < 0: osError(osLastError())
-          discard close(p_stderr[readIdx])
-          if poStdErrToStdOut in options:
-            if dup2(p_stdout[writeIdx], 2) < 0: osError(osLastError())
-          else:
-            if dup2(p_stderr[writeIdx], 2) < 0: osError(osLastError())
-
-        # Create a new process group
-        if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
-
-        if workingDir.len > 0: os.setCurrentDir(workingDir)
-
-        if env == nil:
-          if poUsePath in options:
-            discard execvp(sys_command, sys_args)
-          else:
-            discard execv(sys_command, sys_args)
-        else:
-          var c_env = envToCStringArray(env)
-          if poUsePath in options:
-            discard execvpe(sys_command, sys_args, c_env)
-          else:
-            discard execve(sys_command, sys_args, c_env)
-        # too risky to raise an exception here:
-        quit("execve call failed: " & $strerror(errno))
+      pid = startProcessAuxFork(data)
+
     # Parent process. Copy process information.
     if poEchoCmd in options:
       echo(command, " ", join(args, " "))
@@ -723,6 +691,137 @@ elif not defined(useNimRtl):
       discard close(pStdin[readIdx])
       discard close(pStdout[writeIdx])
 
+  proc startProcessAuxSpawn(data: TStartProcessData): TPid =
+    var attr: Tposix_spawnattr
+    var fops: Tposix_spawn_file_actions
+
+    template chck(e: expr) =
+      if e != 0'i32: osError(osLastError())
+
+    chck posix_spawn_file_actions_init(fops)
+    chck posix_spawnattr_init(attr)
+
+    var mask: Tsigset
+    chck sigemptyset(mask)
+    chck posix_spawnattr_setsigmask(attr, mask)
+    chck posix_spawnattr_setpgroup(attr, 0'i32)
+
+    chck posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK or
+                                        POSIX_SPAWN_SETSIGMASK or
+                                        POSIX_SPAWN_SETPGROUP)
+
+    if not data.optionPoParentStreams:
+      chck posix_spawn_file_actions_addclose(fops, data.pStdin[writeIdx])
+      chck posix_spawn_file_actions_adddup2(fops, data.pStdin[readIdx], readIdx)
+      chck posix_spawn_file_actions_addclose(fops, data.pStdout[readIdx])
+      chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], writeIdx)
+      chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx])
+      if data.optionPoStdErrToStdOut:
+        chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], 2)
+      else:
+        chck posix_spawn_file_actions_adddup2(fops, data.pStderr[writeIdx], 2)
+
+    var res: cint
+    # FIXME: chdir is global to process
+    if data.workingDir.len > 0:
+      setCurrentDir($data.workingDir)
+    var pid: TPid
+
+    if data.optionPoUsePath:
+      res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
+    else:
+      res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
+
+    discard posix_spawn_file_actions_destroy(fops)
+    discard posix_spawnattr_destroy(attr)
+    chck res
+    return pid
+
+  proc startProcessAuxFork(data: TStartProcessData): TPid =
+    if pipe(data.pErrorPipe) != 0:
+        osError(osLastError())
+
+    finally:
+      discard close(data.pErrorPipe[readIdx])
+
+    var pid: TPid
+    var dataCopy = data
+
+    when defined(useClone):
+      const stackSize = 65536
+      let stackEnd = cast[clong](alloc(stackSize))
+      let stack = cast[pointer](stackEnd + stackSize)
+      let fn: pointer = startProcessAfterFork
+      pid = clone(fn, stack,
+                  cint(CLONE_VM or CLONE_VFORK or SIGCHLD),
+                  pointer(addr dataCopy), nil, nil, nil)
+      discard close(data.pErrorPipe[writeIdx])
+      dealloc(stack)
+    else:
+      pid = fork()
+      if pid == 0:
+        startProcessAfterFork(addr(dataCopy))
+        exitnow(1)
+
+    discard close(data.pErrorPipe[writeIdx])
+    if pid < 0: osError(osLastError())
+
+    var error: cint
+    let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error))
+    if sizeRead == sizeof(error):
+      osError($strerror(error))
+
+    return pid
+
+  {.push stacktrace: off, profiler: off.}
+  proc startProcessFail(data: ptr TStartProcessData) =
+    var error: cint = errno
+    discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
+    exitnow(1)
+
+  when defined(macosx):
+    var environ {.importc.}: cstringArray
+
+  proc startProcessAfterFork(data: ptr TStartProcessData) =
+    # Warning: no GC here!
+    # Or anythink that touches global structures - all called nimrod procs
+    # must be marked with noStackFrame. Inspect C code after making changes.
+    if not data.optionPoParentStreams:
+      discard close(data.pStdin[writeIdx])
+      if dup2(data.pStdin[readIdx], readIdx) < 0:
+        startProcessFail(data)
+      discard close(data.pStdout[readIdx])
+      if dup2(data.pStdout[writeIdx], writeIdx) < 0:
+        startProcessFail(data)
+      discard close(data.pStderr[readIdx])
+      if data.optionPoStdErrToStdOut:
+        if dup2(data.pStdout[writeIdx], 2) < 0:
+          startProcessFail(data)
+      else:
+        if dup2(data.pStderr[writeIdx], 2) < 0:
+          startProcessFail(data)
+
+    if data.workingDir.len > 0:
+      if chdir(data.workingDir) < 0:
+        startProcessFail(data)
+
+    discard close(data.pErrorPipe[readIdx])
+    discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC)
+
+    if data.optionPoUsePath:
+      when defined(macosx):
+        # MacOSX doesn't have execvpe, so we need workaround.
+        # On MacOSX we can arrive here only from fork, so this is safe:
+        environ = data.sysEnv
+        discard execvp(data.sysCommand, data.sysArgs)
+      else:
+        discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
+    else:
+      discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
+
+    startProcessFail(data)
+  {.pop}
+
   proc close(p: PProcess) =
     if p.inStream != nil: close(p.inStream)
     if p.outStream != nil: close(p.outStream)
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 70b617393..68b1ab223 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -836,9 +836,11 @@ iterator findAll*(s: string, pattern: TPeg, start = 0): string =
   while i < s.len:
     c.ml = 0
     var L = rawMatch(s, pattern, i, c)
-    if L < 0: break
-    yield substr(s, i, i+L-1)
-    inc(i, L)
+    if L < 0:
+      inc(i, 1)
+    else:
+      yield substr(s, i, i+L-1)
+      inc(i, L)
     
 proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
   nosideEffect, rtl, extern: "npegs$1".} = 
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 83c158da1..6482a01a6 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2013 Dominik Picheta
+#        (c) Copyright 2014 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,212 +9,211 @@
 
 # TODO: Docs.
 
-import tables, os, unsigned
-when defined(windows):
-  import winlean
-else:
-  import posix
+import tables, os, unsigned, hashes
+
+when defined(linux): import posix, epoll
+elif defined(windows): import winlean
+
+proc hash*(x: TSocketHandle): THash {.borrow.}
 
 type
   TEvent* = enum
     EvRead, EvWrite
 
-  TSelectorKey* = object
-    fd: cint
-    events: set[TEvent]
-    data: PObject
-
-  TReadyInfo* = tuple[key: TSelectorKey, events: set[TEvent]]
-
-  PSelector* = ref object of PObject ## Selector interface.
-    fds*: TTable[cint, TSelectorKey]
-    registerImpl*: proc (s: PSelector, fd: cint, events: set[TEvent],
-                    data: PObject): 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].}
-    closeImpl*: proc (s: PSelector) {.nimcall.}
-
-template initSelector(r: expr) =
-  new r
-  r.fds = initTable[cint, TSelectorKey]()
-
-proc register*(s: PSelector, fd: cint, events: set[TEvent], data: PObject):
-    TSelectorKey =
-  if not s.registerImpl.isNil: result = s.registerImpl(s, fd, events, data)
-
-proc unregister*(s: PSelector, fd: cint): TSelectorKey =
-  ##
-  ## **Note:** For the ``epoll`` implementation the resulting ``TSelectorKey``
-  ## will only have the ``fd`` field set. This is an optimisation and may
-  ## change in the future if a viable use case is presented. 
-  if not s.unregisterImpl.isNil: result = s.unregisterImpl(s, fd)
-
-proc select*(s: PSelector, timeout = 500): seq[TReadyInfo] =
-  ##
-  ## The ``events`` field of the returned ``key`` contains the original events
-  ## for which the ``fd`` was bound. This is contrary to the ``events`` field
-  ## of the ``TReadyInfo`` tuple which determines which events are ready
-  ## on the ``fd``.
-
-  if not s.selectImpl.isNil: result = s.selectImpl(s, timeout)
+  PSelectorKey* = ref object
+    fd*: TSocketHandle
+    events*: set[TEvent] ## The events which ``fd`` listens for.
+    data*: PObject ## User object.
 
-proc close*(s: PSelector) =
-  if not s.closeImpl.isNil: s.closeImpl(s)
+  TReadyInfo* = tuple[key: PSelectorKey, events: set[TEvent]]
 
-# ---- Select() ----------------------------------------------------------------
-
-type
-  PSelectSelector* = ref object of PSelector ## Implementation of select()
-
-proc ssRegister(s: PSelector, fd: cint, events: set[TEvent],
-    data: PObject): TSelectorKey =
-  if s.fds.hasKey(fd):
-    raise newException(EInvalidValue, "FD already exists in selector.")
-  var sk = TSelectorKey(fd: fd, events: events, data: data)
-  s.fds[fd] = sk
-  result = sk
-
-proc ssUnregister(s: PSelector, fd: cint): TSelectorKey =
-  result = s.fds[fd]
-  s.fds.del(fd)
-
-proc ssClose(s: PSelector) = nil
-
-proc timeValFromMilliseconds(timeout: int): TTimeVal =
-  if timeout != -1:
-    var seconds = timeout div 1000
-    result.tv_sec = seconds.int32
-    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
-
-proc createFdSet(rd, wr: var TFdSet, fds: TTable[cint, TSelectorKey],
-    m: var int) =
-  FD_ZERO(rd); FD_ZERO(wr)
-  for k, v in pairs(fds):
-    if EvRead in v.events: 
-      m = max(m, int(k))
-      FD_SET(k, rd)
-    if EvWrite in v.events:
-      m = max(m, int(k))
-      FD_SET(k, wr)
-   
-proc getReadyFDs(rd, wr: var TFdSet, fds: TTable[cint, TSelectorKey]):
-    seq[TReadyInfo] =
-  result = @[]
-  for k, v in pairs(fds):
-    var events: set[TEvent] = {}
-    if FD_ISSET(k, rd) != 0'i32:
-      events = events + {EvRead}
-    if FD_ISSET(k, wr) != 0'i32:
-      events = events + {EvWrite}
-    result.add((v, events))
-
-proc select(fds: TTable[cint, TSelectorKey], timeout = 500):
-  seq[TReadyInfo] =
-  var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
-  
-  var rd, wr: TFdSet
-  var m = 0
-  createFdSet(rd, wr, fds, m)
-  
-  var retCode = 0
-  if timeout != -1:
-    retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
-  else:
-    retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
-  
-  if retCode < 0:
-    OSError(OSLastError())
-  elif retCode == 0:
-    return @[]
-  else:
-    return getReadyFDs(rd, wr, fds)
-
-proc ssSelect(s: PSelector, timeout: int): seq[TReadyInfo] =
-  result = select(s.fds, timeout)
-
-proc newSelectSelector*(): PSelectSelector =
-  initSelector(result)
-  result.registerImpl = ssRegister
-  result.unregisterImpl = ssUnregister
-  result.selectImpl = ssSelect
-  result.closeImpl = ssClose
-
-# ---- Epoll -------------------------------------------------------------------
-
-when defined(linux):
-  import epoll
+when defined(linux) or defined(nimdoc):
   type
-    PEpollSelector* = ref object of PSelector
+    PSelector* = ref object
       epollFD: cint
       events: array[64, ptr epoll_event]
+      fds: TTable[TSocketHandle, PSelectorKey]
   
-    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],
-      data: PObject): TSelectorKey =
-    var es = PEpollSelector(s)
-    var event: epoll_event
+  proc createEventStruct(events: set[TEvent], fd: TSocketHandle): epoll_event =
     if EvRead in events:
-      event.events = EPOLLIN
+      result.events = EPOLLIN
     if EvWrite in events:
-      event.events = event.events or EPOLLOUT
-    
-    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
+      result.events = result.events or EPOLLOUT
+    result.data.fd = fd.cint
+  
+  proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent],
+      data: PObject): PSelectorKey {.discardable.} =
+    ## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
+    ## ``events``.
+    if s.fds.hasKey(fd):
+      raise newException(EInvalidValue, "File descriptor already exists.")
     
-    if epoll_ctl(es.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
+    var event = createEventStruct(events, fd)
+  
+    if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
       OSError(OSLastError())
-    
-    result = TSelectorKey(fd: fd, events: events, data: data)
   
-  proc esUnregister(s: PSelector, fd: cint): TSelectorKey =
-    # We cannot find out the information about this ``fd`` from the epoll
-    # context. As such I will simply return an almost empty TSelectorKey.
-    var es = PEpollSelector(s)
-    if epoll_ctl(es.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
+    var key = PSelectorKey(fd: fd, events: events, data: data)
+  
+    s.fds[fd] = key
+    result = key
+  
+  proc update*(s: PSelector, fd: TSocketHandle,
+      events: set[TEvent]): PSelectorKey {.discardable.} =
+    ## Updates the events which ``fd`` wants notifications for.
+    if not s.fds.hasKey(fd):
+      raise newException(EInvalidValue, "File descriptor not found.")
+    var event = createEventStruct(events, fd)
+    
+    s.fds[fd].events = events
+    echo("About to update")
+    if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
       OSError(OSLastError())
-    # We could fill in the ``fds`` TTable to get the info, but that wouldn't
-    # be nice for our memory.
-    result = TSelectorKey(fd: fd, events: {}, data: nil)
-
-  proc esClose(s: PSelector) =
-    var es = PEpollSelector(s)
-    if es.epollFD.close() != 0: OSError(OSLastError())
-    dealloc(addr es.events) # TODO: Test this
+    echo("finished updating")
+    result = s.fds[fd]
   
-  proc esSelect(s: PSelector, timeout: int): seq[TReadyInfo] =
+  proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
+    if not s.fds.hasKey(fd):
+      raise newException(EInvalidValue, "File descriptor not found.")
+    if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
+      OSError(OSLastError())
+    result = s.fds[fd]
+    s.fds.del(fd)
+
+  proc close*(s: PSelector) =
+    if s.epollFD.close() != 0: OSError(OSLastError())
+    dealloc(addr s.events) # TODO: Test this
+  
+  proc select*(s: PSelector, timeout: int): seq[TReadyInfo] =
+    ##
+    ## The ``events`` field of the returned ``key`` contains the original events
+    ## for which the ``fd`` was bound. This is contrary to the ``events`` field
+    ## of the ``TReadyInfo`` tuple which determines which events are ready
+    ## on the ``fd``.
     result = @[]
-    var es = PEpollSelector(s)
     
-    let evNum = epoll_wait(es.epollFD, es.events[0], 64.cint, timeout.cint)
+    let evNum = epoll_wait(s.epollFD, s.events[0], 64.cint, timeout.cint)
     if evNum < 0: OSError(OSLastError())
     if evNum == 0: return @[]
     for i in 0 .. <evNum:
       var evSet: set[TEvent] = {}
-      if (es.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
-      if (es.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
-      let dw = cast[ptr TDataWrapper](es.events[i].data.thePtr)
+      if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
+      if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
       
-      let selectorKey = TSelectorKey(fd: dw.fd, events: dw.boundEvents, 
-          data: dw.data)
+      let selectorKey = s.fds[s.events[i].data.fd.TSocketHandle]
       result.add((selectorKey, evSet))
   
-  proc newEpollSelector*(): PEpollSelector =
+  proc newSelector*(): PSelector =
     new result
     result.epollFD = epoll_create(64)
     result.events = cast[array[64, ptr epoll_event]](alloc0(sizeof(epoll_event)*64))
+    result.fds = initTable[TSocketHandle, PSelectorKey]()
     if result.epollFD < 0:
       OSError(OSLastError())
-    result.registerImpl = esRegister
-    result.unregisterImpl = esUnregister
-    result.closeImpl = esClose
-    result.selectImpl = esSelect
+
+  proc contains*(s: PSelector, fd: TSocketHandle): bool =
+    ## Determines whether selector contains a file descriptor.
+    return s.fds.hasKey(fd)
+
+  proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
+    ## Retrieves the selector key for ``fd``.
+    return s.fds[fd]
+
+elif defined(windows):
+  type
+    PSelector* = ref object
+      fds: TTable[TSocketHandle, PSelectorKey]
+
+  proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent],
+      data: PObject): PSelectorKey {.discardable.} =
+    if s.fds.hasKey(fd):
+      raise newException(EInvalidValue, "File descriptor already exists.")
+    var sk = PSelectorKey(fd: fd, events: events, data: data)
+    s.fds[fd] = sk
+    result = sk
+
+  proc update*(s: PSelector, fd: TSocketHandle,
+      events: set[TEvent]): PSelectorKey {.discardable.} =
+    ## Updates the events which ``fd`` wants notifications for.
+    if not s.fds.hasKey(fd):
+      raise newException(EInvalidValue, "File descriptor not found.")
+
+    s.fds[fd].events = events
+    result = s.fds[fd]
+
+  proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
+    result = s.fds[fd]
+    s.fds.del(fd)
+
+  proc close*(s: PSelector) = nil
+
+  proc timeValFromMilliseconds(timeout: int): TTimeVal =
+    if timeout != -1:
+      var seconds = timeout div 1000
+      result.tv_sec = seconds.int32
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+
+  proc createFdSet(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey],
+      m: var int) =
+    FD_ZERO(rd); FD_ZERO(wr)
+    for k, v in pairs(fds):
+      if EvRead in v.events: 
+        m = max(m, int(k))
+        FD_SET(k, rd)
+      if EvWrite in v.events:
+        m = max(m, int(k))
+        FD_SET(k, wr)
+     
+  proc getReadyFDs(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey]):
+      seq[TReadyInfo] =
+    result = @[]
+    for k, v in pairs(fds):
+      var events: set[TEvent] = {}
+      if FD_ISSET(k, rd) != 0'i32:
+        events = events + {EvRead}
+      if FD_ISSET(k, wr) != 0'i32:
+        events = events + {EvWrite}
+      result.add((v, events))
+
+  proc select(fds: TTable[TSocketHandle, PSelectorKey], timeout = 500):
+    seq[TReadyInfo] =
+    var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
+    
+    var rd, wr: TFdSet
+    var m = 0
+    createFdSet(rd, wr, fds, m)
+    
+    var retCode = 0
+    if timeout != -1:
+      retCode = int(select(TSocketHandle(m+1), addr(rd), addr(wr), nil, addr(tv)))
+    else:
+      retCode = int(select(TSocketHandle(m+1), addr(rd), addr(wr), nil, nil))
+    
+    if retCode < 0:
+      OSError(OSLastError())
+    elif retCode == 0:
+      return @[]
+    else:
+      return getReadyFDs(rd, wr, fds)
+
+  proc select*(s: PSelector, timeout: int): seq[TReadyInfo] =
+    result = select(s.fds, timeout)
+
+  proc newSelector*(): PSelector =
+    new result
+    result.fds = initTable[TSocketHandle, PSelectorKey]()
+
+  proc contains*(s: PSelector, fd: TSocketHandle): bool =
+    return s.fds.hasKey(fd)
+
+  proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey =
+    return s.fds[fd]
+
+elif defined(bsd) or defined(macosx):
+  # TODO: kqueue
+  {.error: "Sorry your platform is not supported yet.".}
+else:
+  {.error: "Sorry your platform is not supported.".}
 
 when isMainModule:
   # Select()
@@ -224,11 +223,12 @@ when isMainModule:
       sock: TSocket
   
   var sock = socket()
+  sock.setBlocking(false)
   sock.connect("irc.freenode.net", TPort(6667))
   
-  var selector = newEpollSelector()
+  var selector = newSelector()
   var data = PSockWrapper(sock: sock)
-  let key = selector.register(sock.getFD.cint, {EvRead}, data)
+  let key = selector.register(sock.getFD, {EvWrite}, data)
   var i = 0
   while true:
     let ready = selector.select(1000)
@@ -236,6 +236,7 @@ when isMainModule:
     if ready.len > 0: echo ready[0].events
     i.inc
     if i == 6:
+      assert selector.unregister(sock.getFD).fd == sock.getFD
       selector.close()
       break
   
diff --git a/lib/pure/sockets2.nim b/lib/pure/sockets2.nim
index 22624bbad..031217b90 100644
--- a/lib/pure/sockets2.nim
+++ b/lib/pure/sockets2.nim
@@ -17,11 +17,13 @@ when hostos == "solaris":
 
 when defined(Windows):
   import winlean
+  export ioctlsocket
 else:
   import posix
+  export fcntl, F_GETFL, O_NONBLOCK, F_SETFL
 
 export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen,
-  inet_ntoa
+  inet_ntoa, recv, `==`, connect, send, accept
 
 type
   
@@ -63,10 +65,10 @@ type
 
 when defined(windows):
   let
-    OSInvalidSocket* = winlean.INVALID_SOCKET
+    osInvalidSocket* = winlean.INVALID_SOCKET
 else:
   let
-    OSInvalidSocket* = posix.INVALID_SOCKET
+    osInvalidSocket* = posix.INVALID_SOCKET
 
 proc `==`*(a, b: TPort): bool {.borrow.}
   ## ``==`` for ports.
@@ -89,7 +91,7 @@ when defined(posix):
     of AF_UNIX:        result = posix.AF_UNIX
     of AF_INET:        result = posix.AF_INET
     of AF_INET6:       result = posix.AF_INET6
-    else: nil
+    else: discard
 
   proc toInt(typ: TType): cint =
     case typ
@@ -97,7 +99,7 @@ when defined(posix):
     of SOCK_DGRAM:     result = posix.SOCK_DGRAM
     of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
     of SOCK_RAW:       result = posix.SOCK_RAW
-    else: nil
+    else: discard
 
   proc toInt(p: TProtocol): cint =
     case p
@@ -107,7 +109,7 @@ when defined(posix):
     of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
     of IPPROTO_RAW:    result = posix.IPPROTO_RAW
     of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
-    else: nil
+    else: discard
 
 else:
   proc toInt(domain: TDomain): cint = 
@@ -199,4 +201,4 @@ proc htons*(x: int16): int16 =
 
 when defined(Windows):
   var wsa: TWSADATA
-  if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
\ No newline at end of file
+  if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
diff --git a/lib/system.nim b/lib/system.nim
index 27be9f815..869658727 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2014,8 +2014,10 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Flushes `f`'s buffer.
 
     proc readAll*(file: TFile): TaintedString {.tags: [FReadIO].}
-      ## Reads all data from the stream `file`. Raises an IO exception
-      ## in case of an error
+      ## Reads all data from the stream `file`.
+      ##
+      ## Raises an IO exception in case of an error. It is an error if the
+      ## current file position is not at the beginning of the file.
     
     proc readFile*(filename: string): TaintedString {.tags: [FReadIO].}
       ## Opens a file named `filename` for reading. Then calls `readAll`
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index a19c456f7..1720804c4 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -418,58 +418,58 @@ proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
     return Math.floor(`a` % `b`);
   """
 
-proc NegInt(a: int): int {.compilerproc.} =
+proc negInt(a: int): int {.compilerproc.} =
   result = a*(-1)
 
-proc NegInt64(a: int64): int64 {.compilerproc.} =
+proc negInt64(a: int64): int64 {.compilerproc.} =
   result = a*(-1)
 
-proc AbsInt(a: int): int {.compilerproc.} =
+proc absInt(a: int): int {.compilerproc.} =
   result = if a < 0: a*(-1) else: a
 
-proc AbsInt64(a: int64): int64 {.compilerproc.} =
+proc absInt64(a: int64): int64 {.compilerproc.} =
   result = if a < 0: a*(-1) else: a
 
-proc LeU(a, b: int): bool {.compilerproc.} =
+proc leU(a, b: int): bool {.compilerproc.} =
   result = abs(a) <= abs(b)
 
-proc LtU(a, b: int): bool {.compilerproc.} =
+proc ltU(a, b: int): bool {.compilerproc.} =
   result = abs(a) < abs(b)
 
-proc LeU64(a, b: int64): bool {.compilerproc.} =
+proc leU64(a, b: int64): bool {.compilerproc.} =
   result = abs(a) <= abs(b)
-
-proc LtU64(a, b: int64): bool {.compilerproc.} =
+proc ltU64(a, b: int64): bool {.compilerproc.} =
   result = abs(a) < abs(b)
 
-proc AddU(a, b: int): int {.compilerproc.} =
+proc addU(a, b: int): int {.compilerproc.} =
   result = abs(a) + abs(b)
-proc AddU64(a, b: int64): int64 {.compilerproc.} =
+proc addU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) + abs(b)
 
-proc SubU(a, b: int): int {.compilerproc.} =
+proc subU(a, b: int): int {.compilerproc.} =
   result = abs(a) - abs(b)
-proc SubU64(a, b: int64): int64 {.compilerproc.} =
+proc subU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) - abs(b)
 
-proc MulU(a, b: int): int {.compilerproc.} =
+proc mulU(a, b: int): int {.compilerproc.} =
   result = abs(a) * abs(b)
-proc MulU64(a, b: int64): int64 {.compilerproc.} =
+proc mulU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) * abs(b)
 
-proc DivU(a, b: int): int {.compilerproc.} =
+proc divU(a, b: int): int {.compilerproc.} =
   result = abs(a) div abs(b)
-proc DivU64(a, b: int64): int64 {.compilerproc.} =
+proc divU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) div abs(b)
 
-proc ModU(a, b: int): int {.compilerproc.} =
+proc modU(a, b: int): int {.compilerproc.} =
   result = abs(a) mod abs(b)
-proc ModU64(a, b: int64): int64 {.compilerproc.} =
+proc modU64(a, b: int64): int64 {.compilerproc.} =
   result = abs(a) mod abs(b)
 
-proc Ze(a: int): int {.compilerproc.} =
+proc ze*(a: int): int {.compilerproc.} =
   result = a
-proc Ze64(a: int64): int64 {.compilerproc.} =
+
+proc ze64*(a: int64): int64 {.compilerproc.} =
   result = a
 
 proc ToU8(a: int): int8 {.asmNoStackFrame, compilerproc.} =
@@ -487,7 +487,6 @@ proc ToU32(a: int): int32 {.asmNoStackFrame, compilerproc.} =
     return `a`;
   """
 
-
 proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
 proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
 
@@ -500,9 +499,9 @@ proc isFatPointer(ti: PNimType): bool =
     tyArray, tyArrayConstr, tyTuple,
     tyOpenArray, tySet, tyVar, tyRef, tyPtr}
 
-proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
+proc nimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
 
-proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
+proc nimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
   case n.kind
   of nkNone: sysAssert(false, "NimCopyAux")
   of nkSlot:
@@ -518,7 +517,7 @@ proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
       }
     """
 
-proc NimCopy(x: pointer, ti: PNimType): pointer =
+proc nimCopy(x: pointer, ti: PNimType): pointer =
   case ti.kind
   of tyPtr, tyRef, tyVar, tyNil:
     if not isFatPointer(ti):