diff options
author | Araq <rumpf_a@web.de> | 2014-03-22 02:52:33 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-03-22 02:52:33 +0100 |
commit | 5aac789e0e183a1a2193bd7615de0b4a29f4708c (patch) | |
tree | 6bf8e890cabd98705eabb6d5dfc48b928adc106c /lib | |
parent | e53fc91282bc8a5dabc4f12e041fa6ce5400c007 (diff) | |
parent | 13d26dc53db455ef07feb315871a7fceee5f7a01 (diff) | |
download | Nim-5aac789e0e183a1a2193bd7615de0b4a29f4708c.tar.gz |
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/asyncio2.nim | 94 | ||||
-rw-r--r-- | lib/pure/net.nim | 261 | ||||
-rw-r--r-- | lib/pure/selectors.nim | 36 | ||||
-rw-r--r-- | lib/system.nim | 28 | ||||
-rw-r--r-- | lib/wrappers/zip/zlib.nim | 2 |
5 files changed, 364 insertions, 57 deletions
diff --git a/lib/pure/asyncio2.nim b/lib/pure/asyncio2.nim index c37370b7b..eb31eca13 100644 --- a/lib/pure/asyncio2.nim +++ b/lib/pure/asyncio2.nim @@ -43,6 +43,14 @@ proc complete*[T](future: PFuture[T], val: T) = if future.cb != nil: future.cb() +proc complete*(future: PFuture[void]) = + ## Completes a void ``future``. + assert(not future.finished, "Future already finished, cannot finish twice.") + assert(future.error == nil) + future.finished = true + if future.cb != nil: + future.cb() + proc fail*[T](future: PFuture[T], error: ref EBase) = ## Completes ``future`` with ``error``. assert(not future.finished, "Future already finished, cannot finish twice.") @@ -76,7 +84,8 @@ proc read*[T](future: PFuture[T]): T = ## If the result of the future is an error then that error will be raised. if future.finished: if future.error != nil: raise future.error - return future.value + when T isnot void: + return future.value else: # TODO: Make a custom exception type for this? raise newException(EInvalidValue, "Future still in progress.") @@ -132,7 +141,6 @@ when defined(windows) or defined(nimdoc): cast[TCompletionKey](sock), 1) == 0: OSError(OSLastError()) p.handles.incl(sock) - # TODO: fd closure detection, we need to remove the fd from handles set proc verifyPresence(p: PDispatcher, sock: TSocketHandle) = ## Ensures that socket has been registered with the dispatcher. @@ -244,13 +252,13 @@ when defined(windows) or defined(nimdoc): RemoteSockaddr, RemoteSockaddrLength) proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort, - af = AF_INET): PFuture[int] = + af = AF_INET): PFuture[void] = ## Connects ``socket`` to server at ``address:port``. ## ## Returns a ``PFuture`` which will complete when the connection succeeds ## or an error occurs. verifyPresence(p, socket) - var retFuture = newFuture[int]()# TODO: Change to void when that regression is fixed. + var retFuture = newFuture[void]() # Apparently ``ConnectEx`` expects the socket to be initially bound: var saddr: Tsockaddr_in saddr.sin_family = int16(toInt(af)) @@ -272,7 +280,7 @@ when defined(windows) or defined(nimdoc): proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) = if not retFuture.finished: if errcode == TOSErrorCode(-1): - retFuture.complete(0) + retFuture.complete() else: retFuture.fail(newException(EOS, osErrorMsg(errcode))) ) @@ -282,7 +290,7 @@ when defined(windows) or defined(nimdoc): if ret: # Request to connect completed immediately. success = true - retFuture.complete(0) + retFuture.complete() # We don't deallocate ``ol`` here because even though this completed # immediately poll will still be notified about its completion and it will # free ``ol``. @@ -363,11 +371,11 @@ when defined(windows) or defined(nimdoc): # free ``ol``. return retFuture - proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[int] = + proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[void] = ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. verifyPresence(p, socket) - var retFuture = newFuture[int]() + var retFuture = newFuture[void]() var dataBuf: TWSABuf dataBuf.buf = data @@ -379,7 +387,7 @@ when defined(windows) or defined(nimdoc): proc (sock: TSocketHandle, bytesCount: DWord, errcode: TOSErrorCode) = if not retFuture.finished: if errcode == TOSErrorCode(-1): - retFuture.complete(0) + retFuture.complete() else: retFuture.fail(newException(EOS, osErrorMsg(errcode))) ) @@ -392,7 +400,7 @@ when defined(windows) or defined(nimdoc): retFuture.fail(newException(EOS, osErrorMsg(err))) dealloc(ol) else: - retFuture.complete(0) + retFuture.complete() # We don't deallocate ``ol`` here because even though this completed # immediately poll will still be notified about its completion and it will # free ``ol``. @@ -475,6 +483,11 @@ when defined(windows) or defined(nimdoc): result = socket(domain, typ, protocol) disp.register(result) + proc close*(disp: PDispatcher, socket: TSocketHandle) = + ## Closes a socket and ensures that it is unregistered. + socket.close() + disp.handles.excl(socket) + initAll() else: import selectors @@ -508,6 +521,10 @@ else: result = socket(domain, typ, protocol) disp.register(result) + proc close*(disp: PDispatcher, sock: TSocketHandle) = + sock.close() + disp.selector.unregister(sock) + proc addRead(p: PDispatcher, sock: TSocketHandle, cb: TCallback) = if sock notin p.selector: raise newException(EInvalidValue, "File descriptor not registered.") @@ -556,12 +573,12 @@ else: # (e.g. socket disconnected). proc connect*(p: PDispatcher, socket: TSocketHandle, address: string, port: TPort, - af = AF_INET): PFuture[int] = - var retFuture = newFuture[int]() + af = AF_INET): PFuture[void] = + var retFuture = newFuture[void]() proc cb(sock: TSocketHandle): bool = # We have connected. - retFuture.complete(0) + retFuture.complete() return true var aiList = getAddrInfo(address, port, af) @@ -573,7 +590,7 @@ else: if ret == 0: # Request to connect completed immediately. success = true - retFuture.complete(0) + retFuture.complete() break else: lastError = osLastError() @@ -627,8 +644,8 @@ else: addRead(p, socket, cb) return retFuture - proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[int] = - var retFuture = newFuture[int]() + proc send*(p: PDispatcher, socket: TSocketHandle, data: string): PFuture[void] = + var retFuture = newFuture[void]() var written = 0 @@ -648,7 +665,7 @@ else: if res != netSize: result = false # We still have data to send. else: - retFuture.complete(0) + retFuture.complete() addWrite(p, socket, cb) return retFuture @@ -781,12 +798,17 @@ macro async*(prc: stmt): stmt {.immediate.} = hint("Processing " & prc[0].getName & " as an async proc.") + let returnType = prc[3][0] + var subtypeName = "" # Verify that the return type is a PFuture[T] - if prc[3][0].kind == nnkIdent: - error("Expected return type of 'PFuture' got '" & $prc[3][0] & "'") - elif prc[3][0].kind == nnkBracketExpr: - if $prc[3][0][0] != "PFuture": - error("Expected return type of 'PFuture' got '" & $prc[3][0][0] & "'") + if returnType.kind == nnkIdent: + error("Expected return type of 'PFuture' got '" & $returnType & "'") + elif returnType.kind == nnkBracketExpr: + if $returnType[0] != "PFuture": + error("Expected return type of 'PFuture' got '" & $returnType[0] & "'") + subtypeName = $returnType[1].ident + elif returnType.kind == nnkEmpty: + subtypeName = "void" # TODO: Why can't I use genSym? I get illegal capture errors for Syms. # TODO: It seems genSym is broken. Change all usages back to genSym when fixed @@ -799,20 +821,24 @@ macro async*(prc: stmt): stmt {.immediate.} = newVarStmt(retFutureSym, newCall( newNimNode(nnkBracketExpr).add( - newIdentNode("newFuture"), - prc[3][0][1])))) # Get type from return type of this proc. - + newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`. + newIdentNode(subtypeName))))) # Get type from return type of this proc + echo(treeRepr(outerProcBody)) # -> iterator nameIter(): PFutureBase {.closure.} = # -> var result: T # -> <proc_body> # -> complete(retFuture, result) var iteratorNameSym = newIdentNode($prc[0].getName & "Iter") #genSym(nskIterator, $prc[0].ident & "Iter") var procBody = prc[6].processBody(retFutureSym) - procBody.insert(0, newNimNode(nnkVarSection).add( - newIdentDefs(newIdentNode("result"), prc[3][0][1]))) # -> var result: T - procBody.add( - newCall(newIdentNode("complete"), - retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result) + if subtypeName != "void": + procBody.insert(0, newNimNode(nnkVarSection).add( + newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T + procBody.add( + newCall(newIdentNode("complete"), + retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result) + else: + # -> complete(retFuture) + procBody.add(newCall(newIdentNode("complete"), retFutureSym)) var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")], procBody, nnkIteratorDef) @@ -847,6 +873,12 @@ macro async*(prc: stmt): stmt {.immediate.} = for i in 0 .. <result[4].len: if result[4][i].ident == !"async": result[4].del(i) + if subtypeName == "void": + # Add discardable pragma. + result[4].add(newIdentNode("discardable")) + if returnType.kind == nnkEmpty: + # Add PFuture[void] + result[3][0] = parseExpr("PFuture[void]") result[6] = outerProcBody @@ -892,7 +924,7 @@ proc recvLine*(p: PDispatcher, socket: TSocketHandle): PFuture[string] {.async.} when isMainModule: var p = newDispatcher() - var sock = socket() + var sock = p.socket() sock.setBlocking false diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 0ec007009..9ee98cbe6 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -9,7 +9,264 @@ ## This module implements a high-level cross-platform sockets interface. -import sockets2, os +import sockets2, os, strutils, unsigned + +type + IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address + IPv6, ## IPv6 address + IPv4 ## IPv4 address + + TIpAddress* = object ## stores an arbitrary IP address + case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6) + of IpAddressFamily.IPv6: + address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in case of IPv6 + of IpAddressFamily.IPv4: + address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in case of IPv4 + +proc IPv4_any*(): TIpAddress = + ## Returns the IPv4 any address, which can be used to listen on all available + ## network adapters + result = TIpAddress( + family: IpAddressFamily.IPv4, + address_v4: [0'u8, 0'u8, 0'u8, 0'u8]) + +proc IPv4_loopback*(): TIpAddress = + ## Returns the IPv4 loopback address (127.0.0.1) + result = TIpAddress( + family: IpAddressFamily.IPv4, + address_v4: [127'u8, 0'u8, 0'u8, 1'u8]) + +proc IPv4_broadcast*(): TIpAddress = + ## Returns the IPv4 broadcast address (255.255.255.255) + result = TIpAddress( + family: IpAddressFamily.IPv4, + address_v4: [255'u8, 255'u8, 255'u8, 255'u8]) + +proc IPv6_any*(): TIpAddress = + ## Returns the IPv6 any address (::0), which can be used + ## to listen on all available network adapters + result = TIpAddress( + family: IpAddressFamily.IPv6, + address_v6: [0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8]) + +proc IPv6_loopback*(): TIpAddress = + ## Returns the IPv6 loopback address (::1) + result = TIpAddress( + family: IpAddressFamily.IPv6, + address_v6: [0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,0'u8,1'u8]) + +proc `==`*(lhs, rhs: TIpAddress): bool = + ## Compares two IpAddresses for Equality. Returns two if the addresses are equal + if lhs.family != rhs.family: return false + if lhs.family == IpAddressFamily.IPv4: + for i in low(lhs.address_v4) .. high(lhs.address_v4): + if lhs.address_v4[i] != rhs.address_v4[i]: return false + else: # IPv6 + for i in low(lhs.address_v6) .. high(lhs.address_v6): + if lhs.address_v6[i] != rhs.address_v6[i]: return false + return true + +proc `$`*(address: TIpAddress): string = + ## Converts an TIpAddress into the textual representation + result = "" + case address.family + of IpAddressFamily.IPv4: + for i in 0 .. 3: + if i != 0: + result.add('.') + result.add($address.address_v4[i]) + of IpAddressFamily.IPv6: + var + currentZeroStart = -1 + currentZeroCount = 0 + biggestZeroStart = -1 + biggestZeroCount = 0 + # Look for the largest block of zeros + for i in 0..7: + var isZero = address.address_v6[i*2] == 0 and address.address_v6[i*2+1] == 0 + if isZero: + if currentZeroStart == -1: + currentZeroStart = i + currentZeroCount = 1 + else: + currentZeroCount.inc() + if currentZeroCount > biggestZeroCount: + biggestZeroCount = currentZeroCount + biggestZeroStart = currentZeroStart + else: + currentZeroStart = -1 + + if biggestZeroCount == 8: # Special case ::0 + result.add("::") + else: # Print address + var printedLastGroup = false + for i in 0..7: + var word:uint16 = (cast[uint16](address.address_v6[i*2])) shl 8 + word = word or cast[uint16](address.address_v6[i*2+1]) + + if biggestZeroCount != 0 and # Check if group is in skip group + (i >= biggestZeroStart and i < (biggestZeroStart + biggestZeroCount)): + if i == biggestZeroStart: # skip start + result.add("::") + printedLastGroup = false + else: + if printedLastGroup: + result.add(':') + var + afterLeadingZeros = false + mask = 0xF000'u16 + for j in 0'u16..3'u16: + var val = (mask and word) shr (4'u16*(3'u16-j)) + if val != 0 or afterLeadingZeros: + if val < 0xA: + result.add(chr(uint16(ord('0'))+val)) + else: # val >= 0xA + result.add(chr(uint16(ord('a'))+val-0xA)) + afterLeadingZeros = true + mask = mask shr 4 + printedLastGroup = true + +proc parseIPv4Address(address_str: string): TIpAddress = + ## Parses IPv4 adresses + ## Raises EInvalidValue on errors + var + byteCount = 0 + currentByte:uint16 = 0 + seperatorValid = false + + result.family = IpAddressFamily.IPv4 + + for i in 0 .. high(address_str): + if address_str[i] in strutils.Digits: # Character is a number + currentByte = currentByte * 10 + cast[uint16](ord(address_str[i]) - ord('0')) + if currentByte > 255'u16: + raise newException(EInvalidValue, "Invalid IP Address. Value is out of range") + seperatorValid = true + elif address_str[i] == '.': # IPv4 address separator + if not seperatorValid or byteCount >= 3: + raise newException(EInvalidValue, "Invalid IP Address. The address consists of too many groups") + result.address_v4[byteCount] = cast[uint8](currentByte) + currentByte = 0 + byteCount.inc + seperatorValid = false + else: + raise newException(EInvalidValue, "Invalid IP Address. Address contains an invalid character") + + if byteCount != 3 or not seperatorValid: + raise newException(EInvalidValue, "Invalid IP Address") + result.address_v4[byteCount] = cast[uint8](currentByte) + +proc parseIPv6Address(address_str: string): TIpAddress = + ## Parses IPv6 adresses + ## Raises EInvalidValue on errors + result.family = IpAddressFamily.IPv6 + if address_str.len < 2: raise newException(EInvalidValue, "Invalid IP Address") + + var + groupCount = 0 + currentGroupStart = 0 + currentShort:uint32 = 0 + seperatorValid = true + dualColonGroup = -1 + lastWasColon = false + v4StartPos = -1 + byteCount = 0 + + for i,c in address_str: + if c == ':': + if not seperatorValid: raise newException(EInvalidValue, "Invalid IP Address. Address contains an invalid seperator") + if lastWasColon: + if dualColonGroup != -1: raise newException(EInvalidValue, "Invalid IP Address. Address contains more than one \"::\" seperator") + dualColonGroup = groupCount + seperatorValid = false + elif i != 0 and i != high(address_str): + if groupCount >= 8: raise newException(EInvalidValue, "Invalid IP Address. The address consists of too many groups") + result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8) + result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) + currentShort = 0 + groupCount.inc() + if dualColonGroup != -1: seperatorValid = false + elif i == 0: # only valid if address starts with :: + if address_str[1] != ':': + raise newException(EInvalidValue, "Invalid IP Address. Address may not start with \":\"") + else: # i == high(address_str) - only valid if address ends with :: + if address_str[high(address_str)-1] != ':': + raise newException(EInvalidValue, "Invalid IP Address. Address may not end with \":\"") + lastWasColon = true + currentGroupStart = i + 1 + elif c == '.': # Switch to parse IPv4 mode + if i < 3 or not seperatorValid or groupCount >= 7: raise newException(EInvalidValue, "Invalid IP Address") + v4StartPos = currentGroupStart + currentShort = 0 + seperatorValid = false + break + elif c in strutils.HexDigits: + if c in strutils.Digits: # Normal digit + currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('0')) + elif c >= 'a' and c <= 'f': # Lower case hex + currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('a')) + 10 + else: # Upper case hex + currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10 + if currentShort > 65535'u32: + raise newException(EInvalidValue, "Invalid IP Address. Value is out of range") + lastWasColon = false + seperatorValid = true + else: + raise newException(EInvalidValue, "Invalid IP Address. Address contains an invalid character") + + + if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff + if seperatorValid: # Copy remaining data + if groupCount >= 8: raise newException(EInvalidValue, "Invalid IP Address. The address consists of too many groups") + result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8) + result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) + groupCount.inc() + else: # Must parse IPv4 address + for i,c in address_str[v4StartPos..high(address_str)]: + if c in strutils.Digits: # Character is a number + currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0')) + if currentShort > 255'u32: + raise newException(EInvalidValue, "Invalid IP Address. Value is out of range") + seperatorValid = true + elif c == '.': # IPv4 address separator + if not seperatorValid or byteCount >= 3: + raise newException(EInvalidValue, "Invalid IP Address") + result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort) + currentShort = 0 + byteCount.inc() + seperatorValid = false + else: # Invalid character + raise newException(EInvalidValue, "Invalid IP Address. Address contains an invalid character") + + if byteCount != 3 or not seperatorValid: + raise newException(EInvalidValue, "Invalid IP Address") + result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort) + groupCount += 2 + + # Shift and fill zeros in case of :: + if groupCount > 8: + raise newException(EInvalidValue, "Invalid IP Address. The address consists of too many groups") + elif groupCount < 8: # must fill + if dualColonGroup == -1: raise newException(EInvalidValue, "Invalid IP Address. The address consists of too few groups") + var toFill = 8 - groupCount # The number of groups to fill + var toShift = groupCount - dualColonGroup # Nr of known groups after :: + for i in 0..2*toShift-1: # shift + result.address_v6[15-i] = result.address_v6[groupCount*2-i-1] + for i in 0..2*toFill-1: # fill with 0s + result.address_v6[dualColonGroup*2+i] = 0 + elif dualColonGroup != -1: raise newException(EInvalidValue, "Invalid IP Address. The address consists of too many groups") + + +proc parseIpAddress*(address_str: string): TIpAddress = + ## Parses an IP address + ## Raises EInvalidValue on error + if address_str == nil: + raise newException(EInvalidValue, "IP Address string is nil") + if address_str.contains(':'): + return parseIPv6Address(address_str) + else: + return parseIPv4Address(address_str) + type TSocket* = TSocketHandle @@ -52,4 +309,4 @@ proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].} = 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 + osError(osLastError()) diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index a113e3362..085344e3e 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -60,7 +60,6 @@ when defined(linux) or defined(nimdoc): events: set[TEvent]): PSelectorKey {.discardable.} = ## Updates the events which ``fd`` wants notifications for. if s.fds[fd].events != events: - echo("Update ", fd.cint, " to ", events) var event = createEventStruct(events, fd) s.fds[fd].events = events @@ -70,7 +69,9 @@ when defined(linux) or defined(nimdoc): proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} = if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0: - OSError(OSLastError()) + let err = OSLastError() + if err.cint notin {ENOENT, EBADF}: # TODO: Why do we sometimes get an EBADF? Is this normal? + OSError(err) result = s.fds[fd] s.fds.del(fd) @@ -78,6 +79,15 @@ when defined(linux) or defined(nimdoc): if s.epollFD.close() != 0: OSError(OSLastError()) dealloc(addr s.events) # TODO: Test this + proc epollHasFd(s: PSelector, fd: TSocketHandle): bool = + result = true + var event = createEventStruct(s.fds[fd].events, fd) + if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0: + let err = osLastError() + if err.cint in {ENOENT, EBADF}: + return false + OSError(OSLastError()) + proc select*(s: PSelector, timeout: int): seq[TReadyInfo] = ## ## The ``events`` field of the returned ``key`` contains the original events @@ -85,24 +95,19 @@ when defined(linux) or defined(nimdoc): ## of the ``TReadyInfo`` tuple which determines which events are ready ## on the ``fd``. result = @[] - let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint) if evNum < 0: OSError(OSLastError()) if evNum == 0: return @[] for i in 0 .. <evNum: + let fd = s.events[i].data.fd.TSocketHandle + var evSet: set[TEvent] = {} if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead} if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite} - let selectorKey = s.fds[s.events[i].data.fd.TSocketHandle] + let selectorKey = s.fds[fd] assert selectorKey != nil result.add((selectorKey, evSet)) - - if (s.events[i].events and EPOLLHUP) != 0 or - (s.events[i].events and EPOLLRDHUP) != 0: - # fd closed - #echo("fd closed ", s.events[i].data.fd) - s.unregister(s.events[i].data.fd.TSocketHandle) - + #echo("Epoll: ", result[i].key.fd, " ", result[i].events, " ", result[i].key.events) proc newSelector*(): PSelector = @@ -116,15 +121,8 @@ when defined(linux) or defined(nimdoc): proc contains*(s: PSelector, fd: TSocketHandle): bool = ## Determines whether selector contains a file descriptor. if s.fds.hasKey(fd): - result = true - # Ensure the underlying epoll instance still contains this fd. - var event = createEventStruct(s.fds[fd].events, fd) - if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0: - let err = osLastError() - if err.cint in {ENOENT, EBADF}: - return false - OSError(OSLastError()) + result = epollHasFd(s, fd) else: return false diff --git a/lib/system.nim b/lib/system.nim index 41624bb05..be57ba192 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2364,12 +2364,32 @@ when not defined(JS): #and not defined(NimrodVM): when not defined(NimrodVM): proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} - ## can be used to mark a condition to be likely. This is a hint for the - ## optimizer. + ## Hints the optimizer that `val` is likely going to be true. + ## + ## You can use this proc to decorate a branch condition. On certain + ## platforms this can help the processor predict better which branch is + ## going to be run. Example: + ## + ## .. code-block:: nimrod + ## for value in inputValues: + ## if likely(value <= 100): + ## process(value) + ## else: + ## echo "Value too big!" proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} - ## can be used to mark a condition to be unlikely. This is a hint for the - ## optimizer. + ## Hints the optimizer that `val` is likely going to be false. + ## + ## You can use this proc to decorate a branch condition. On certain + ## platforms this can help the processor predict better which branch is + ## going to be run. Example: + ## + ## .. code-block:: nimrod + ## for value in inputValues: + ## if unlikely(value > 100): + ## echo "Value too big!" + ## else: + ## process(value) proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = ## retrieves the raw proc pointer of the closure `x`. This is diff --git a/lib/wrappers/zip/zlib.nim b/lib/wrappers/zip/zlib.nim index cd3a765c1..f505b95a7 100644 --- a/lib/wrappers/zip/zlib.nim +++ b/lib/wrappers/zip/zlib.nim @@ -7,7 +7,7 @@ when defined(windows): elif defined(macosx): const libz = "libz.dylib" else: - const libz = "libz.so" + const libz = "libz.so.1" type Uint* = int32 |