diff options
author | Araq <rumpf_a@web.de> | 2016-12-17 23:04:34 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2016-12-17 23:04:34 +0100 |
commit | 24239c23619e9d64562699b5d890fa2575e9c9cb (patch) | |
tree | 7b68d65e1bc5c12a465dd29814e6328cb25e30b4 | |
parent | 3a4ec7f101f539fb536086b59c84e1b2c095ef82 (diff) | |
parent | d4c33df91996e30ded5f7f2014e7cd49176b5b05 (diff) | |
download | Nim-24239c23619e9d64562699b5d890fa2575e9c9cb.tar.gz |
Merge branch 'devel' into sighashes
-rw-r--r-- | compiler/ccgstmts.nim | 6 | ||||
-rw-r--r-- | compiler/extccomp.nim | 10 | ||||
-rw-r--r-- | compiler/msgs.nim | 4 | ||||
-rw-r--r-- | compiler/pragmas.nim | 18 | ||||
-rw-r--r-- | compiler/semexprs.nim | 4 | ||||
-rw-r--r-- | compiler/semstmts.nim | 4 | ||||
-rw-r--r-- | doc/manual/pragmas.txt | 12 | ||||
-rw-r--r-- | lib/pure/ioselectors.nim | 14 | ||||
-rw-r--r-- | lib/pure/ioselects/ioselectors_epoll.nim | 320 | ||||
-rw-r--r-- | lib/upcoming/asyncdispatch.nim | 20 | ||||
-rw-r--r-- | tests/async/tioselectors.nim | 11 | ||||
-rw-r--r-- | tests/async/tupcoming_async.nim | 88 | ||||
-rw-r--r-- | tests/cpp/temitlist.nim | 22 | ||||
-rw-r--r-- | web/news/e029_version_0_16_0.rst | 22 |
14 files changed, 340 insertions, 215 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 7282e6af5..123d627b5 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -973,7 +973,11 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = r = mangleName(p.module, sym) sym.loc.r = r # but be consequent! res.add($r) - else: internalError(t.sons[i].info, "genAsmOrEmitStmt()") + else: + var a: TLoc + initLocExpr(p, t.sons[i], a) + res.add($a.rdLoc) + #internalError(t.sons[i].info, "genAsmOrEmitStmt()") if isAsmStmt and hasGnuAsm in CC[cCompiler].props: for x in splitLines(res): diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 1acc98836..175e8d831 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -659,8 +659,14 @@ proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq, proc getLinkCmd(projectfile, objfiles: string): string = if optGenStaticLib in gGlobalOptions: - let name = splitFile(gProjectName).name - result = CC[cCompiler].buildLib % ["libfile", (libNameTmpl() % name), + var libname: string + if options.outFile.len > 0: + libname = options.outFile.expandTilde + if not libname.isAbsolute(): + libname = getCurrentDir() / libname + else: + libname = (libNameTmpl() % splitFile(gProjectName).name) + result = CC[cCompiler].buildLib % ["libfile", libname, "objfiles", objfiles] else: var linkerExe = getConfigVar(cCompiler, ".linkerexe") diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 94b0bee00..e6a2b75a6 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -48,7 +48,7 @@ type errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, - errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected, + errCastNotInSafeMode, errExprCannotBeCastToX, errCommaOrParRiExpected, errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, errMagicOnlyInSystem, errPowerOfTwoExpected, errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, @@ -229,7 +229,7 @@ const errExprHasNoType: "expression has no type", errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)", errCastNotInSafeMode: "\'cast\' not allowed in safe mode", - errExprCannotBeCastedToX: "expression cannot be casted to $1", + errExprCannotBeCastToX: "expression cannot be cast to $1", errCommaOrParRiExpected: "',' or ')' expected", errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected", errSectionExpected: "section (\'type\', \'proc\', etc.) expected", diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 6697abe5e..b9f00399e 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -460,8 +460,22 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = result = newNode(nkAsmStmt, n.info) proc pragmaEmit(c: PContext, n: PNode) = - discard getStrLitNode(c, n) - n.sons[1] = semAsmOrEmit(c, n, '`') + if n.kind != nkExprColonExpr: + localError(n.info, errStringLiteralExpected) + else: + let n1 = n[1] + if n1.kind == nkBracket: + var b = newNodeI(nkBracket, n1.info, n1.len) + for i in 0..<n1.len: + b.sons[i] = c.semExpr(c, n1[i]) + n.sons[1] = b + else: + n.sons[1] = c.semConstExpr(c, n1) + case n.sons[1].kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + n.sons[1] = semAsmOrEmit(c, n, '`') + else: + localError(n.info, errStringLiteralExpected) proc noVal(n: PNode) = if n.kind == nkExprColonExpr: invalidPragma(n) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5e6611064..9076ce99b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -127,7 +127,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus = discard proc isCastable(dst, src: PType): bool = - ## Checks whether the source type can be casted to the destination type. + ## Checks whether the source type can be cast to the destination type. ## Casting is very unrestrictive; casts are allowed as long as ## castDest.size >= src.size, and typeAllowed(dst, skParam) #const @@ -223,7 +223,7 @@ proc semCast(c: PContext, n: PNode): PNode = addSon(result, copyTree(n.sons[0])) addSon(result, semExprWithType(c, n.sons[1])) if not isCastable(result.typ, result.sons[1].typ): - localError(result.info, errExprCannotBeCastedToX, + localError(result.info, errExprCannotBeCastToX, typeToString(result.typ)) proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index fb57f6500..ec4279e60 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -760,8 +760,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = internalAssert st.kind in {tyPtr, tyRef} internalAssert st.lastSon.sym == nil incl st.flags, tfRefsAnonObj - st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"), + let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"), getCurrOwner(), s.info) + obj.typ = st.lastSon + st.lastSon.sym = obj proc checkForMetaFields(n: PNode) = diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index a19f41a34..2a276c2e7 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -26,9 +26,6 @@ It can also be used as a statement, in that case it takes a list of *renamings*. Stream = ref object {.deprecated: [TFile: File, PStream: Stream].} -The ``nimfix`` tool can be used to, without effort, automatically update your -code and refactor it by performing these renamings. - noSideEffect pragma ------------------- @@ -678,14 +675,15 @@ Example: {.push stackTrace:off.} proc embedsC() = var nimVar = 89 - # use backticks to access Nim symbols within an emit section: - {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".} + # access Nim symbols within an emit section outside of string literals: + {.emit: ["""fprintf(stdout, "%d\n", cvariable + (int)""", nimVar, ");"].} {.pop.} embedsC() -As can be seen from the example, to Nim symbols can be referred via backticks. -Use two backticks to produce a single verbatim backtick. +For backwards compatibility, if the argument to the ``emit`` statement +is a single string literal, Nim symbols can be referred to via backticks. +This usage is however deprecated. For a toplevel emit statement the section where in the generated C/C++ file the code should be emitted can be influenced via the 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 diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index 71d901e69..e6b4196a3 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -12,11 +12,10 @@ template processTest(t, x: untyped) = if not x: echo(t & " FAILED\r\n") when not defined(windows): - import os, posix, osproc, nativesockets, times + import os, posix, nativesockets, times - const supportedPlatform = defined(macosx) or defined(freebsd) or - defined(netbsd) or defined(openbsd) or - defined(linux) + when ioselSupportedPlatform: + import osproc proc socket_notification_test(): bool = proc create_test_socket(): SocketHandle = @@ -143,7 +142,7 @@ when not defined(windows): selector.close() result = true - when supportedPlatform: + when ioselSupportedPlatform: proc timer_notification_test(): bool = var selector = newSelector[int]() var timer = selector.registerTimer(100, false, 0) @@ -462,7 +461,7 @@ when not defined(windows): when hasThreadSupport: processTest("Multithreaded user event notification test...", mt_event_test()) - when supportedPlatform: + when ioselSupportedPlatform: processTest("Timer notification test...", timer_notification_test()) processTest("Process notification test...", process_notification_test()) processTest("Signal notification test...", signal_notification_test()) diff --git a/tests/async/tupcoming_async.nim b/tests/async/tupcoming_async.nim index 137794afd..7d255f213 100644 --- a/tests/async/tupcoming_async.nim +++ b/tests/async/tupcoming_async.nim @@ -8,11 +8,12 @@ OK """ when defined(upcoming): - import asyncdispatch, times, osproc, streams + import asyncdispatch, times, streams, posix + from ioselectors import ioselSupportedPlatform - const supportedPlatform = defined(linux) or defined(freebsd) or - defined(netbsd) or defined(openbsd) or - defined(macosx) + proc delayedSet(ev: AsyncEvent, timeout: int): Future[void] {.async.} = + await sleepAsync(timeout) + ev.setEvent() proc waitEvent(ev: AsyncEvent, closeEvent = false): Future[void] = var retFuture = newFuture[void]("waitEvent") @@ -25,56 +26,55 @@ when defined(upcoming): addEvent(ev, cb) return retFuture - proc waitTimer(timeout: int): Future[void] = - var retFuture = newFuture[void]("waitTimer") - proc cb(fd: AsyncFD): bool = - retFuture.complete() - addTimer(timeout, true, cb) - return retFuture - - proc waitProcess(p: Process): Future[void] = - var retFuture = newFuture[void]("waitProcess") - proc cb(fd: AsyncFD): bool = - retFuture.complete() - addProcess(p.processID(), cb) - return retFuture - - proc delayedSet(ev: AsyncEvent, timeout: int): Future[void] {.async.} = - await waitTimer(timeout) - ev.setEvent() - - proc timerTest() = - waitFor(waitTimer(200)) - echo "OK" - proc eventTest() = var event = newAsyncEvent() var fut = waitEvent(event) asyncCheck(delayedSet(event, 500)) - waitFor(fut or waitTimer(1000)) + waitFor(fut or sleepAsync(1000)) if fut.finished: echo "OK" else: echo "eventTest: Timeout expired before event received!" - proc processTest() = - when defined(windows): - var process = startProcess("ping.exe", "", - ["127.0.0.1", "-n", "2", "-w", "100"], nil, - {poStdErrToStdOut, poUsePath, poInteractive, - poDemon}) - else: - var process = startProcess("/bin/sleep", "", ["1"], nil, - {poStdErrToStdOut, poUsePath}) - var fut = waitProcess(process) - waitFor(fut or waitTimer(2000)) - if fut.finished and process.peekExitCode() == 0: + when ioselSupportedPlatform or defined(windows): + + import osproc + + proc waitTimer(timeout: int): Future[void] = + var retFuture = newFuture[void]("waitTimer") + proc cb(fd: AsyncFD): bool = + retFuture.complete() + addTimer(timeout, true, cb) + return retFuture + + proc waitProcess(p: Process): Future[void] = + var retFuture = newFuture[void]("waitProcess") + proc cb(fd: AsyncFD): bool = + retFuture.complete() + addProcess(p.processID(), cb) + return retFuture + + proc timerTest() = + waitFor(waitTimer(200)) echo "OK" - else: - echo "processTest: Timeout expired before process exited!" - when supportedPlatform: - import posix + proc processTest() = + when defined(windows): + var process = startProcess("ping.exe", "", + ["127.0.0.1", "-n", "2", "-w", "100"], nil, + {poStdErrToStdOut, poUsePath, poInteractive, + poDemon}) + else: + var process = startProcess("/bin/sleep", "", ["1"], nil, + {poStdErrToStdOut, poUsePath}) + var fut = waitProcess(process) + waitFor(fut or waitTimer(2000)) + if fut.finished and process.peekExitCode() == 0: + echo "OK" + else: + echo "processTest: Timeout expired before process exited!" + + when ioselSupportedPlatform: proc waitSignal(signal: int): Future[void] = var retFuture = newFuture[void]("waitSignal") @@ -97,7 +97,7 @@ when defined(upcoming): else: echo "signalTest: Timeout expired before signal received!" - when supportedPlatform: + when ioselSupportedPlatform: timerTest() eventTest() processTest() diff --git a/tests/cpp/temitlist.nim b/tests/cpp/temitlist.nim new file mode 100644 index 000000000..cef0fc52d --- /dev/null +++ b/tests/cpp/temitlist.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim cpp $file" + output: '''6.0''' +""" + +# bug #4730 + +type Vector* {.importcpp: "std::vector", header: "<vector>".}[T] = object + +template `[]=`*[T](v: var Vector[T], key: int, val: T) = + {.emit: [v, "[", key, "] = ", val, ";"].} + +proc setLen*[T](v: var Vector[T]; size: int) {.importcpp: "resize", nodecl.} +proc `[]`*[T](v: var Vector[T], key: int): T {.importcpp: "(#[#])", nodecl.} + +proc main = + var v: Vector[float] + v.setLen 1 + v[0] = 6.0 + echo v[0] + +main() diff --git a/web/news/e029_version_0_16_0.rst b/web/news/e029_version_0_16_0.rst index 2a0c81b46..905504791 100644 --- a/web/news/e029_version_0_16_0.rst +++ b/web/news/e029_version_0_16_0.rst @@ -55,6 +55,28 @@ Compiler Additions Language Additions ------------------ +- The ``emit`` pragma now takes a list of Nim expressions instead + of a single string literal. This list can easily contain non-strings + like template parameters. This means ``emit`` works out of the + box with templates and no new quoting rules needed to be introduced. + The old way with backtick quoting is still supported but will be + deprecated. + +.. code-block:: nim + type Vector* {.importcpp: "std::vector", header: "<vector>".}[T] = object + + template `[]=`*[T](v: var Vector[T], key: int, val: T) = + {.emit: [v, "[", key, "] = ", val, ";"].} + + proc setLen*[T](v: var Vector[T]; size: int) {.importcpp: "resize", nodecl.} + proc `[]`*[T](v: var Vector[T], key: int): T {.importcpp: "(#[#])", nodecl.} + + proc main = + var v: Vector[float] + v.setLen 1 + v[0] = 6.0 + echo v[0] + Bugfixes -------- |