Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

addQuitProc now works with closures, and c, js(node/browser) backend; fix some bugs in testament #14342

Merged
merged 6 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions lib/core/locks.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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.} =
Expand Down
28 changes: 0 additions & 28 deletions lib/pure/quitprocs.nim

This file was deleted.

65 changes: 65 additions & 0 deletions lib/std/exitprocs.nim
Original file line number Diff line number Diff line change
@@ -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)
9 changes: 4 additions & 5 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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`.
##
Expand Down
4 changes: 2 additions & 2 deletions testament/categories.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions testament/specs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
12 changes: 7 additions & 5 deletions testament/testament.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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()])
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/converter/tor_in_converter.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ test'''
"""
# bug #4537

# nim js --d:nodejs
# nim js -d:nodejs

type
Str = distinct string
Expand Down
21 changes: 21 additions & 0 deletions tests/stdlib/texitprocs.nim
Original file line number Diff line number Diff line change
@@ -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)