Merge branch 'devel' into sighashes

This commit is contained in:
Araq 2016-12-17 23:04:34 +01:00
commit 24239c2361
14 changed files with 341 additions and 216 deletions

View file

@ -973,7 +973,11 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
r = mangleName(p.module, sym) r = mangleName(p.module, sym)
sym.loc.r = r # but be consequent! sym.loc.r = r # but be consequent!
res.add($r) 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: if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
for x in splitLines(res): for x in splitLines(res):

View file

@ -659,8 +659,14 @@ proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq,
proc getLinkCmd(projectfile, objfiles: string): string = proc getLinkCmd(projectfile, objfiles: string): string =
if optGenStaticLib in gGlobalOptions: if optGenStaticLib in gGlobalOptions:
let name = splitFile(gProjectName).name var libname: string
result = CC[cCompiler].buildLib % ["libfile", (libNameTmpl() % name), 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] "objfiles", objfiles]
else: else:
var linkerExe = getConfigVar(cCompiler, ".linkerexe") var linkerExe = getConfigVar(cCompiler, ".linkerexe")

View file

@ -48,7 +48,7 @@ type
errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected, errCastNotInSafeMode, errExprCannotBeCastToX, errCommaOrParRiExpected,
errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
errMagicOnlyInSystem, errPowerOfTwoExpected, errMagicOnlyInSystem, errPowerOfTwoExpected,
errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
@ -229,7 +229,7 @@ const
errExprHasNoType: "expression has no type", errExprHasNoType: "expression has no type",
errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)", errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)",
errCastNotInSafeMode: "\'cast\' not allowed in safe mode", errCastNotInSafeMode: "\'cast\' not allowed in safe mode",
errExprCannotBeCastedToX: "expression cannot be casted to $1", errExprCannotBeCastToX: "expression cannot be cast to $1",
errCommaOrParRiExpected: "',' or ')' expected", errCommaOrParRiExpected: "',' or ')' expected",
errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected", errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected",
errSectionExpected: "section (\'type\', \'proc\', etc.) expected", errSectionExpected: "section (\'type\', \'proc\', etc.) expected",

View file

@ -460,8 +460,22 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
result = newNode(nkAsmStmt, n.info) result = newNode(nkAsmStmt, n.info)
proc pragmaEmit(c: PContext, n: PNode) = proc pragmaEmit(c: PContext, n: PNode) =
discard getStrLitNode(c, n) if n.kind != nkExprColonExpr:
n.sons[1] = semAsmOrEmit(c, n, '`') 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) = proc noVal(n: PNode) =
if n.kind == nkExprColonExpr: invalidPragma(n) if n.kind == nkExprColonExpr: invalidPragma(n)

View file

@ -127,7 +127,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
discard discard
proc isCastable(dst, src: PType): bool = 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 ## Casting is very unrestrictive; casts are allowed as long as
## castDest.size >= src.size, and typeAllowed(dst, skParam) ## castDest.size >= src.size, and typeAllowed(dst, skParam)
#const #const
@ -223,7 +223,7 @@ proc semCast(c: PContext, n: PNode): PNode =
addSon(result, copyTree(n.sons[0])) addSon(result, copyTree(n.sons[0]))
addSon(result, semExprWithType(c, n.sons[1])) addSon(result, semExprWithType(c, n.sons[1]))
if not isCastable(result.typ, result.sons[1].typ): if not isCastable(result.typ, result.sons[1].typ):
localError(result.info, errExprCannotBeCastedToX, localError(result.info, errExprCannotBeCastToX,
typeToString(result.typ)) typeToString(result.typ))
proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =

View file

@ -760,8 +760,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
internalAssert st.kind in {tyPtr, tyRef} internalAssert st.kind in {tyPtr, tyRef}
internalAssert st.lastSon.sym == nil internalAssert st.lastSon.sym == nil
incl st.flags, tfRefsAnonObj 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) getCurrOwner(), s.info)
obj.typ = st.lastSon
st.lastSon.sym = obj
proc checkForMetaFields(n: PNode) = proc checkForMetaFields(n: PNode) =

View file

@ -26,9 +26,6 @@ It can also be used as a statement, in that case it takes a list of *renamings*.
Stream = ref object Stream = ref object
{.deprecated: [TFile: File, PStream: Stream].} {.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 noSideEffect pragma
------------------- -------------------
@ -678,14 +675,15 @@ Example:
{.push stackTrace:off.} {.push stackTrace:off.}
proc embedsC() = proc embedsC() =
var nimVar = 89 var nimVar = 89
# use backticks to access Nim symbols within an emit section: # access Nim symbols within an emit section outside of string literals:
{.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".} {.emit: ["""fprintf(stdout, "%d\n", cvariable + (int)""", nimVar, ");"].}
{.pop.} {.pop.}
embedsC() embedsC()
As can be seen from the example, to Nim symbols can be referred via backticks. For backwards compatibility, if the argument to the ``emit`` statement
Use two backticks to produce a single verbatim backtick. 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 For a toplevel emit statement the section where in the generated C/C++ file
the code should be emitted can be influenced via the the code should be emitted can be influenced via the

View file

@ -18,10 +18,12 @@
## Supported features: files, sockets, pipes, timers, processes, signals ## Supported features: files, sockets, pipes, timers, processes, signals
## and user events. ## 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), ## Partially supported OS: Windows (only sockets and user events),
## Solaris (files, sockets, handles 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. ## TODO: ``/dev/poll``, ``event ports`` and filesystem events.
@ -29,9 +31,11 @@ import os
const hasThreadSupport = compileOption("threads") and defined(threadsafe) const hasThreadSupport = compileOption("threads") and defined(threadsafe)
const supportedPlatform = defined(macosx) or defined(freebsd) or const ioselSupportedPlatform* = defined(macosx) or defined(freebsd) or
defined(netbsd) or defined(openbsd) or defined(netbsd) or defined(openbsd) or
defined(linux) (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 const bsdPlatform = defined(macosx) or defined(freebsd) or
defined(netbsd) or defined(openbsd) defined(netbsd) or defined(openbsd)
@ -244,7 +248,7 @@ else:
skey.key.fd = pkeyfd skey.key.fd = pkeyfd
skey.key.data = pdata skey.key.data = pdata
when supportedPlatform: when ioselSupportedPlatform:
template blockSignals(newmask: var Sigset, oldmask: var Sigset) = template blockSignals(newmask: var Sigset, oldmask: var Sigset) =
when hasThreadSupport: when hasThreadSupport:
if posix.pthread_sigmask(SIG_BLOCK, newmask, oldmask) == -1: if posix.pthread_sigmask(SIG_BLOCK, newmask, oldmask) == -1:

View file

@ -14,27 +14,29 @@ import posix, times
# Maximum number of events that can be returned # Maximum number of events that can be returned
const MAX_EPOLL_RESULT_EVENTS = 64 const MAX_EPOLL_RESULT_EVENTS = 64
type when not defined(android):
SignalFdInfo* {.importc: "struct signalfd_siginfo", type
header: "<sys/signalfd.h>", pure, final.} = object SignalFdInfo* {.importc: "struct signalfd_siginfo",
ssi_signo*: uint32 header: "<sys/signalfd.h>", pure, final.} = object
ssi_errno*: int32 ssi_signo*: uint32
ssi_code*: int32 ssi_errno*: int32
ssi_pid*: uint32 ssi_code*: int32
ssi_uid*: uint32 ssi_pid*: uint32
ssi_fd*: int32 ssi_uid*: uint32
ssi_tid*: uint32 ssi_fd*: int32
ssi_band*: uint32 ssi_tid*: uint32
ssi_overrun*: uint32 ssi_band*: uint32
ssi_trapno*: uint32 ssi_overrun*: uint32
ssi_status*: int32 ssi_trapno*: uint32
ssi_int*: int32 ssi_status*: int32
ssi_ptr*: uint64 ssi_int*: int32
ssi_utime*: uint64 ssi_ptr*: uint64
ssi_stime*: uint64 ssi_utime*: uint64
ssi_addr*: uint64 ssi_stime*: uint64
pad* {.importc: "__pad".}: array[0..47, uint8] ssi_addr*: uint64
pad* {.importc: "__pad".}: array[0..47, uint8]
type
eventFdData {.importc: "eventfd_t", eventFdData {.importc: "eventfd_t",
header: "<sys/eventfd.h>", pure, final.} = uint64 header: "<sys/eventfd.h>", pure, final.} = uint64
epoll_data {.importc: "union epoll_data", header: "<sys/epoll.h>", 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, proc timerfd_settime(ufd: cint, flags: cint,
utmr: var Itimerspec, otmr: var Itimerspec): cint utmr: var Itimerspec, otmr: var Itimerspec): cint
{.cdecl, importc: "timerfd_settime", header: "<sys/timerfd.h>".} {.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 proc eventfd(count: cuint, flags: cint): cint
{.cdecl, importc: "eventfd", header: "<sys/eventfd.h>".} {.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: when hasThreadSupport:
type type
@ -97,7 +109,10 @@ type
SelectEvent* = ptr SelectEventImpl SelectEvent* = ptr SelectEventImpl
proc newSelector*[T](): Selector[T] = 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) doAssert(maxFD > 0)
var epollFD = epoll_create(MAX_EPOLL_RESULT_EVENTS) 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) doAssert(pkey.ident != 0)
if pkey.events != {}: if pkey.events != {}:
if pkey.events * {Event.Read, Event.Write} != {}: when not defined(android):
var epv = epoll_event() if pkey.events * {Event.Read, Event.Write} != {}:
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1: var epv = epoll_event()
raiseOSError(osLastError()) if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
dec(s.count) raiseOSError(osLastError())
elif Event.Timer in pkey.events: dec(s.count)
var epv = epoll_event() elif Event.Timer in pkey.events:
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1: var epv = epoll_event()
raiseOSError(osLastError()) if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
discard posix.close(fdi.cint) raiseOSError(osLastError())
dec(s.count) discard posix.close(fdi.cint)
elif Event.Signal in pkey.events: dec(s.count)
var epv = epoll_event() elif Event.Signal in pkey.events:
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1: var epv = epoll_event()
raiseOSError(osLastError()) if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
var nmask, omask: Sigset raiseOSError(osLastError())
discard sigemptyset(nmask) var nmask, omask: Sigset
discard sigemptyset(omask) discard sigemptyset(nmask)
discard sigaddset(nmask, cint(s.fds[fdi].param)) discard sigemptyset(omask)
unblockSignals(nmask, omask) discard sigaddset(nmask, cint(s.fds[fdi].param))
discard posix.close(fdi.cint) unblockSignals(nmask, omask)
dec(s.count) discard posix.close(fdi.cint)
elif Event.Process in pkey.events: dec(s.count)
var epv = epoll_event() elif Event.Process in pkey.events:
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1: var epv = epoll_event()
raiseOSError(osLastError()) if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) == -1:
var nmask, omask: Sigset raiseOSError(osLastError())
discard sigemptyset(nmask) var nmask, omask: Sigset
discard sigemptyset(omask) discard sigemptyset(nmask)
discard sigaddset(nmask, SIGCHLD) discard sigemptyset(omask)
unblockSignals(nmask, omask) discard sigaddset(nmask, SIGCHLD)
discard posix.close(fdi.cint) unblockSignals(nmask, omask)
dec(s.count) 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.ident = 0
pkey.events = {} pkey.events = {}
@ -280,60 +309,61 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool,
inc(s.count) inc(s.count)
result = fdi result = fdi
proc registerSignal*[T](s: Selector[T], signal: int, when not defined(android):
data: T): int {.discardable.} = proc registerSignal*[T](s: Selector[T], signal: int,
var data: T): int {.discardable.} =
nmask: Sigset var
omask: Sigset nmask: Sigset
omask: Sigset
discard sigemptyset(nmask) discard sigemptyset(nmask)
discard sigemptyset(omask) discard sigemptyset(omask)
discard sigaddset(nmask, cint(signal)) discard sigaddset(nmask, cint(signal))
blockSignals(nmask, omask) blockSignals(nmask, omask)
let fdi = signalfd(-1, nmask, 0).int let fdi = signalfd(-1, nmask, 0).int
if fdi == -1: if fdi == -1:
raiseOSError(osLastError()) raiseOSError(osLastError())
setNonBlocking(fdi.cint) setNonBlocking(fdi.cint)
s.checkFd(fdi) s.checkFd(fdi)
doAssert(s.fds[fdi].ident == 0) doAssert(s.fds[fdi].ident == 0)
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP) var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
epv.data.u64 = fdi.uint epv.data.u64 = fdi.uint
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) == -1: if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) == -1:
raiseOSError(osLastError()) raiseOSError(osLastError())
s.setKey(fdi, signal, {Event.Signal}, signal, data) s.setKey(fdi, signal, {Event.Signal}, signal, data)
inc(s.count) inc(s.count)
result = fdi result = fdi
proc registerProcess*[T](s: Selector, pid: int, proc registerProcess*[T](s: Selector, pid: int,
data: T): int {.discardable.} = data: T): int {.discardable.} =
var var
nmask: Sigset nmask: Sigset
omask: Sigset omask: Sigset
discard sigemptyset(nmask) discard sigemptyset(nmask)
discard sigemptyset(omask) discard sigemptyset(omask)
discard sigaddset(nmask, posix.SIGCHLD) discard sigaddset(nmask, posix.SIGCHLD)
blockSignals(nmask, omask) blockSignals(nmask, omask)
let fdi = signalfd(-1, nmask, 0).int let fdi = signalfd(-1, nmask, 0).int
if fdi == -1: if fdi == -1:
raiseOSError(osLastError()) raiseOSError(osLastError())
setNonBlocking(fdi.cint) setNonBlocking(fdi.cint)
s.checkFd(fdi) s.checkFd(fdi)
doAssert(s.fds[fdi].ident == 0) doAssert(s.fds[fdi].ident == 0)
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP) var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
epv.data.u64 = fdi.uint epv.data.u64 = fdi.uint
epv.events = EPOLLIN or EPOLLRDHUP epv.events = EPOLLIN or EPOLLRDHUP
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) == -1: if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fdi.cint, addr epv) == -1:
raiseOSError(osLastError()) raiseOSError(osLastError())
s.setKey(fdi, pid, {Event.Process, Event.Oneshot}, pid, data) s.setKey(fdi, pid, {Event.Process, Event.Oneshot}, pid, data)
inc(s.count) inc(s.count)
result = fdi result = fdi
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) = proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
let fdi = int(ev.efd) let fdi = int(ev.efd)
@ -382,40 +412,60 @@ proc selectInto*[T](s: Selector[T], timeout: int,
events.incl(Event.Error) events.incl(Event.Error)
if (pevents and EPOLLOUT) != 0: if (pevents and EPOLLOUT) != 0:
events.incl(Event.Write) events.incl(Event.Write)
if (pevents and EPOLLIN) != 0: when not defined(android):
if Event.Read in skey.events: if (pevents and EPOLLIN) != 0:
events.incl(Event.Read) if Event.Read in skey.events:
elif Event.Timer in skey.events: events.incl(Event.Read)
var data: uint64 = 0 elif Event.Timer in skey.events:
if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64): var data: uint64 = 0
raiseOSError(osLastError()) if posix.read(fdi.cint, addr data, sizeof(uint64)) != sizeof(uint64):
events = {Event.Timer} raiseOSError(osLastError())
elif Event.Signal in skey.events: events = {Event.Timer}
var data = SignalFdInfo() elif Event.Signal in skey.events:
if posix.read(fdi.cint, addr data, var data = SignalFdInfo()
sizeof(SignalFdInfo)) != sizeof(SignalFdInfo): if posix.read(fdi.cint, addr data,
raiseOsError(osLastError()) sizeof(SignalFdInfo)) != sizeof(SignalFdInfo):
events = {Event.Signal} raiseOsError(osLastError())
elif Event.Process in skey.events: events = {Event.Signal}
var data = SignalFdInfo() elif Event.Process in skey.events:
if posix.read(fdi.cint, addr data, var data = SignalFdInfo()
sizeof(SignalFdInfo)) != sizeof(SignalFdInfo): if posix.read(fdi.cint, addr data,
raiseOsError(osLastError()) sizeof(SignalFdInfo)) != sizeof(SignalFdInfo):
if cast[int](data.ssi_pid) == skey.param: raiseOsError(osLastError())
events = {Event.Process} if cast[int](data.ssi_pid) == skey.param:
else: events = {Event.Process}
inc(i) else:
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):
inc(i) inc(i)
continue continue
else: elif Event.User in skey.events:
raiseOSError(err) var data: uint64 = 0
events = {Event.User} 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 skey.key.events = events
results[k] = skey.key results[k] = skey.key

View file

@ -1092,11 +1092,6 @@ else:
import ioselectors import ioselectors
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
MSG_NOSIGNAL MSG_NOSIGNAL
const supportedPlatform = defined(linux) or defined(freebsd) or
defined(netbsd) or defined(openbsd) or
defined(macosx)
type type
AsyncFD* = distinct cint AsyncFD* = distinct cint
Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.} Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.}
@ -1191,7 +1186,7 @@ else:
var keys: array[64, ReadyKey[AsyncData]] var keys: array[64, ReadyKey[AsyncData]]
let p = getGlobalDispatcher() let p = getGlobalDispatcher()
when supportedPlatform: when ioselSupportedPlatform:
let customSet = {Event.Timer, Event.Signal, Event.Process, let customSet = {Event.Timer, Event.Signal, Event.Process,
Event.Vnode, Event.User} Event.Vnode, Event.User}
@ -1225,7 +1220,7 @@ else:
else: else:
break break
when supportedPlatform: when ioselSupportedPlatform:
if (customSet * events) != {}: if (customSet * events) != {}:
for node in keys[i].data.readCBs[].nodes(): for node in keys[i].data.readCBs[].nodes():
let cb = node.value let cb = node.value
@ -1234,6 +1229,15 @@ else:
if cb(fd.AsyncFD): if cb(fd.AsyncFD):
keys[i].data.readCBs[].remove(node) keys[i].data.readCBs[].remove(node)
p.selector.unregister(fd) 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 # because state `data` can be modified in callback we need to update
# descriptor events with currently registered callbacks. # descriptor events with currently registered callbacks.
@ -1496,7 +1500,7 @@ else:
addRead(socket, cb) addRead(socket, cb)
return retFuture return retFuture
when supportedPlatform: when ioselSupportedPlatform:
proc addTimer*(timeout: int, oneshot: bool, cb: Callback) = proc addTimer*(timeout: int, oneshot: bool, cb: Callback) =
## Start watching for timeout expiration, and then call the ## Start watching for timeout expiration, and then call the

View file

@ -12,11 +12,10 @@ template processTest(t, x: untyped) =
if not x: echo(t & " FAILED\r\n") if not x: echo(t & " FAILED\r\n")
when not defined(windows): when not defined(windows):
import os, posix, osproc, nativesockets, times import os, posix, nativesockets, times
const supportedPlatform = defined(macosx) or defined(freebsd) or when ioselSupportedPlatform:
defined(netbsd) or defined(openbsd) or import osproc
defined(linux)
proc socket_notification_test(): bool = proc socket_notification_test(): bool =
proc create_test_socket(): SocketHandle = proc create_test_socket(): SocketHandle =
@ -143,7 +142,7 @@ when not defined(windows):
selector.close() selector.close()
result = true result = true
when supportedPlatform: when ioselSupportedPlatform:
proc timer_notification_test(): bool = proc timer_notification_test(): bool =
var selector = newSelector[int]() var selector = newSelector[int]()
var timer = selector.registerTimer(100, false, 0) var timer = selector.registerTimer(100, false, 0)
@ -462,7 +461,7 @@ when not defined(windows):
when hasThreadSupport: when hasThreadSupport:
processTest("Multithreaded user event notification test...", processTest("Multithreaded user event notification test...",
mt_event_test()) mt_event_test())
when supportedPlatform: when ioselSupportedPlatform:
processTest("Timer notification test...", timer_notification_test()) processTest("Timer notification test...", timer_notification_test())
processTest("Process notification test...", process_notification_test()) processTest("Process notification test...", process_notification_test())
processTest("Signal notification test...", signal_notification_test()) processTest("Signal notification test...", signal_notification_test())

View file

@ -8,11 +8,12 @@ OK
""" """
when defined(upcoming): 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 proc delayedSet(ev: AsyncEvent, timeout: int): Future[void] {.async.} =
defined(netbsd) or defined(openbsd) or await sleepAsync(timeout)
defined(macosx) ev.setEvent()
proc waitEvent(ev: AsyncEvent, closeEvent = false): Future[void] = proc waitEvent(ev: AsyncEvent, closeEvent = false): Future[void] =
var retFuture = newFuture[void]("waitEvent") var retFuture = newFuture[void]("waitEvent")
@ -25,56 +26,55 @@ when defined(upcoming):
addEvent(ev, cb) addEvent(ev, cb)
return retFuture 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() = proc eventTest() =
var event = newAsyncEvent() var event = newAsyncEvent()
var fut = waitEvent(event) var fut = waitEvent(event)
asyncCheck(delayedSet(event, 500)) asyncCheck(delayedSet(event, 500))
waitFor(fut or waitTimer(1000)) waitFor(fut or sleepAsync(1000))
if fut.finished: if fut.finished:
echo "OK" echo "OK"
else: else:
echo "eventTest: Timeout expired before event received!" echo "eventTest: Timeout expired before event received!"
proc processTest() = when ioselSupportedPlatform or defined(windows):
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 supportedPlatform: import osproc
import posix
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"
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] = proc waitSignal(signal: int): Future[void] =
var retFuture = newFuture[void]("waitSignal") var retFuture = newFuture[void]("waitSignal")
@ -97,7 +97,7 @@ when defined(upcoming):
else: else:
echo "signalTest: Timeout expired before signal received!" echo "signalTest: Timeout expired before signal received!"
when supportedPlatform: when ioselSupportedPlatform:
timerTest() timerTest()
eventTest() eventTest()
processTest() processTest()

22
tests/cpp/temitlist.nim Normal file
View file

@ -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()

View file

@ -55,6 +55,28 @@ Compiler Additions
Language 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 Bugfixes
-------- --------