diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2020-06-16 02:43:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-16 11:43:48 +0200 |
commit | dfe51d10a1f204d0c3ab1a8be1e109029cc54f9b (patch) | |
tree | 17eb11f3545d9f690329e02dadd7e015460838e6 | |
parent | 45cac4afda2272182ea1eb7572493d6c71e2da4e (diff) | |
download | Nim-dfe51d10a1f204d0c3ab1a8be1e109029cc54f9b.tar.gz |
`addQuitProc` now works with closures, and c, js(node/browser) backend; fix some bugs in testament (#14342)
* make addQuitProc great again * fix bugs in testament * fix test * change 2016 => 2020 * addQuitProc => addExitProc + locks * move to std/exitprocs
-rw-r--r-- | lib/core/locks.nim | 13 | ||||
-rw-r--r-- | lib/pure/quitprocs.nim | 28 | ||||
-rw-r--r-- | lib/std/exitprocs.nim | 65 | ||||
-rw-r--r-- | lib/system.nim | 9 | ||||
-rw-r--r-- | testament/categories.nim | 4 | ||||
-rw-r--r-- | testament/specs.nim | 7 | ||||
-rw-r--r-- | testament/testament.nim | 12 | ||||
-rw-r--r-- | tests/converter/tor_in_converter.nim | 2 | ||||
-rw-r--r-- | tests/stdlib/texitprocs.nim | 21 |
9 files changed, 117 insertions, 44 deletions
diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 7e2f4ad34..bddd6d864 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -9,6 +9,10 @@ ## This module contains Nim's support for locks and condition vars. +#[ +for js, for now we treat locks as noop's to avoid pushing `when defined(js)` +in client code that uses locks. +]# when not compileOption("threads") and not defined(nimdoc): when false: # fix #12330 @@ -26,7 +30,8 @@ type proc initLock*(lock: var Lock) {.inline.} = ## Initializes the given lock. - initSysLock(lock) + when not defined(js): + initSysLock(lock) proc deinitLock*(lock: var Lock) {.inline.} = ## Frees the resources associated with the lock. @@ -38,11 +43,13 @@ proc tryAcquire*(lock: var Lock): bool = proc acquire*(lock: var Lock) = ## Acquires the given lock. - acquireSys(lock) + when not defined(js): + acquireSys(lock) proc release*(lock: var Lock) = ## Releases the given lock. - releaseSys(lock) + when not defined(js): + releaseSys(lock) proc initCond*(cond: var Cond) {.inline.} = diff --git a/lib/pure/quitprocs.nim b/lib/pure/quitprocs.nim deleted file mode 100644 index 76bbcdb2b..000000000 --- a/lib/pure/quitprocs.nim +++ /dev/null @@ -1,28 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2016 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## ``system.addQuitProc`` is nice and very useful but due to its C-based -## implementation it doesn't support closures which limits its usefulness. -## This module fixes this. Later versions of this module will also -## support the JavaScript backend. - -var - gClosures: seq[proc () {.closure.}] - -proc callClosures() {.noconv.} = - for i in countdown(gClosures.len-1, 0): - gClosures[i]() - -proc addQuitClosure*(cl: proc () {.closure.}) = - ## Like ``system.addQuitProc`` but it supports closures. - if gClosures.len == 0: - addQuitProc(callClosures) - gClosures = @[cl] - else: - gClosures.add(cl) diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim new file mode 100644 index 000000000..b2811735c --- /dev/null +++ b/lib/std/exitprocs.nim @@ -0,0 +1,65 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import locks + +type + FunKind = enum kClosure, kNoconv # extend as needed + Fun = object + case kind: FunKind + of kClosure: fun1: proc () {.closure.} + of kNoconv: fun2: proc () {.noconv.} + +var + gFunsLock: Lock + gFuns: seq[Fun] + +initLock(gFunsLock) + +when defined(js): + proc addAtExit(quitProc: proc() {.noconv.}) = + when defined(nodejs): + asm """ + process.on('exit', `quitProc`); + """ + elif defined(js): + asm """ + window.onbeforeunload = `quitProc`; + """ +else: + proc addAtExit(quitProc: proc() {.noconv.}) {. + importc: "atexit", header: "<stdlib.h>".} + +proc callClosures() {.noconv.} = + withLock gFunsLock: + for i in countdown(gFuns.len-1, 0): + let fun = gFuns[i] + case fun.kind + of kClosure: fun.fun1() + of kNoconv: fun.fun2() + +template fun() = + if gFuns.len == 0: + addAtExit(callClosures) + +proc addExitProc*(cl: proc () {.closure.}) = + ## Adds/registers a quit procedure. Each call to `addExitProc` registers + ## another quit procedure. They are executed on a last-in, first-out basis. + # Support for `addExitProc` is done by Ansi C's facilities here. + # In case of an unhandled exception the exit handlers should + # not be called explicitly! The user may decide to do this manually though. + withLock gFunsLock: + fun() + gFuns.add Fun(kind: kClosure, fun1: cl) + +proc addExitProc*(cl: proc() {.noconv.}) = + ## overload for `noconv` procs. + withLock gFunsLock: + fun() + gFuns.add Fun(kind: kNoconv, fun2: cl) diff --git a/lib/system.nim b/lib/system.nim index 85be43cba..2235b8b70 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1147,8 +1147,8 @@ when defined(nimdoc): proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} ## Stops the program immediately with an exit code. ## - ## Before stopping the program the "quit procedures" are called in the - ## opposite order they were added with `addQuitProc <#addQuitProc,proc>`_. + ## Before stopping the program the "exit procedures" are called in the + ## opposite order they were added with `addExitProc <exitprocs.html#addExitProc,proc>`_. ## ``quit`` never returns and ignores any exception that may have been raised ## by the quit procedures. It does *not* call the garbage collector to free ## all the memory, unless a quit procedure calls `GC_fullCollect @@ -1426,8 +1426,8 @@ proc toBiggestInt*(f: BiggestFloat): BiggestInt {.noSideEffect.} = ## Same as `toInt <#toInt,float>`_ but for ``BiggestFloat`` to ``BiggestInt``. if f >= 0: BiggestInt(f+0.5) else: BiggestInt(f-0.5) -proc addQuitProc*(quitProc: proc() {.noconv.}) {. - importc: "atexit", header: "<stdlib.h>".} +proc addQuitProc*(quitProc: proc() {.noconv.}) {. + importc: "atexit", header: "<stdlib.h>", deprecated: "use exitprocs.addExitProc".} ## Adds/registers a quit procedure. ## ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30 @@ -1440,7 +1440,6 @@ proc addQuitProc*(quitProc: proc() {.noconv.}) {. # In case of an unhandled exception the exit handlers should # not be called explicitly! The user may decide to do this manually though. - proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} ## Swaps the values `a` and `b`. ## diff --git a/testament/categories.nim b/testament/categories.nim index 4e83fa1a9..45a2113a6 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -269,8 +269,8 @@ proc debuggerTests(r: var TResults, cat: Category, options: string) = proc jsTests(r: var TResults, cat: Category, options: string) = template test(filename: untyped) = - testSpec r, makeTest(filename, options & " -d:nodejs", cat), {targetJS} - testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat), {targetJS} + testSpec r, makeTest(filename, options, cat), {targetJS} + testSpec r, makeTest(filename, options & " -d:release", cat), {targetJS} for t in os.walkFiles("tests/js/t*.nim"): test(t) diff --git a/testament/specs.nim b/testament/specs.nim index 964d53d24..7405c5055 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -87,6 +87,13 @@ const targetToExt*: array[TTarget, string] = ["nim.c", "nim.cpp", "nim.m", "js"] targetToCmd*: array[TTarget, string] = ["c", "cpp", "objc", "js"] +proc defaultOptions*(a: TTarget): string = + case a + of targetJS: "-d:nodejs" + # once we start testing for `nim js -d:nimbrowser` (eg selenium or similar), + # we can adapt this logic; or a given js test can override with `-u:nodejs`. + else: "" + when not declared(parseCfgBool): # candidate for the stdlib: proc parseCfgBool(s: string): bool = diff --git a/testament/testament.nim b/testament/testament.nim index 69b7e322e..098c07ac5 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -135,7 +135,10 @@ proc nimcacheDir(filename, options: string, target: TTarget): string = proc prepareTestArgs(cmdTemplate, filename, options, nimcache: string, target: TTarget, extraOptions = ""): seq[string] = - let options = options & " " & quoteShell("--nimCache:" & nimcache) & " " & extraOptions + var options = target.defaultOptions & " " & options + # improve pending https://github.com/nim-lang/Nim/issues/14343 + if nimcache.len > 0: options.add " " & ("--nimCache:" & nimcache).quoteShell + options.add " " & extraOptions result = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], "options", options, "file", filename.quoteShell, "filedir", filename.getFileDir()]) @@ -192,9 +195,7 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, proc callCCompiler(cmdTemplate, filename, options: string, target: TTarget): TSpec = - let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], - "options", options, "file", filename.quoteShell, - "filedir", filename.getFileDir()]) + let c = prepareTestArgs(cmdTemplate, filename, options, nimcache = "", target) var p = startProcess(command="gcc", args=c[5 .. ^1], options={poStdErrToStdOut, poUsePath}) let outp = p.outputStream @@ -254,7 +255,8 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, # test.name is easier to find than test.name.extractFilename # A bit hacky but simple and works with tests/testament/tshould_not_work.nim var name = test.name.replace(DirSep, '/') - name.add " " & $target & test.options + name.add " " & $target + if test.options.len > 0: name.add " " & test.options let duration = epochTime() - test.startTime let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout diff --git a/tests/converter/tor_in_converter.nim b/tests/converter/tor_in_converter.nim index 5674526a1..df2334647 100644 --- a/tests/converter/tor_in_converter.nim +++ b/tests/converter/tor_in_converter.nim @@ -4,7 +4,7 @@ test''' """ # bug #4537 -# nim js --d:nodejs +# nim js -d:nodejs type Str = distinct string diff --git a/tests/stdlib/texitprocs.nim b/tests/stdlib/texitprocs.nim new file mode 100644 index 000000000..9d5378fe8 --- /dev/null +++ b/tests/stdlib/texitprocs.nim @@ -0,0 +1,21 @@ +discard """ +targets: "c cpp js" +output: ''' +ok4 +ok3 +ok2 +ok1 +''' +""" + +import std/exitprocs + +proc fun1() {.noconv.} = echo "ok1" +proc fun2() = echo "ok2" +proc fun3() {.noconv.} = echo "ok3" +proc fun4() = echo "ok4" + +addExitProc(fun1) +addExitProc(fun2) +addExitProc(fun3) +addExitProc(fun4) |