From eb0d510195b5061ed840dc52cbe00cd21085f18a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Fri, 10 Feb 2017 17:25:22 +0200 Subject: Removed $ from echo calls (#5368) --- doc/tut1.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'doc') diff --git a/doc/tut1.rst b/doc/tut1.rst index 47cafc7fa..e79214dee 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -361,7 +361,7 @@ iterator: .. code-block:: nim echo "Counting to ten: " for i in countup(1, 10): - echo $i + echo i # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines The built-in `$ `_ operator turns an integer (``int``) and many @@ -374,7 +374,7 @@ Each value is ``echo``-ed. This code does the same: echo "Counting to 10: " var i = 1 while i <= 10: - echo $i + echo i inc(i) # increment i by 1 # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines @@ -383,7 +383,7 @@ Counting down can be achieved as easily (but is less often needed): .. code-block:: nim echo "Counting down from 10 to 1: " for i in countdown(10, 1): - echo $i + echo i # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines Since counting up occurs so often in programs, Nim also has a `.. @@ -827,7 +827,7 @@ Let's return to the boring counting example: .. code-block:: nim echo "Counting to ten: " for i in countup(1, 10): - echo $i + echo i Can a `countup `_ proc be written that supports this loop? Lets try: @@ -1035,15 +1035,15 @@ there is a difference between the ``$`` and ``repr`` outputs: myString = "nim" myInteger = 42 myFloat = 3.14 - echo $myBool, ":", repr(myBool) + echo myBool, ":", repr(myBool) # --> true:true - echo $myCharacter, ":", repr(myCharacter) + echo myCharacter, ":", repr(myCharacter) # --> n:'n' - echo $myString, ":", repr(myString) + echo myString, ":", repr(myString) # --> nim:0x10fa8c050"nim" - echo $myInteger, ":", repr(myInteger) + echo myInteger, ":", repr(myInteger) # --> 42:42 - echo $myFloat, ":", repr(myFloat) + echo myFloat, ":", repr(myFloat) # --> 3.1400000000000001e+00:3.1400000000000001e+00 @@ -1075,7 +1075,7 @@ at runtime by 0, the second by 1 and so on. Example: north, east, south, west var x = south # `x` is of type `Direction`; its value is `south` - echo $x # writes "south" to `stdout` + echo x # writes "south" to `stdout` All comparison operators can be used with enumeration types. @@ -1289,7 +1289,7 @@ value. Here the ``for`` statement is looping over the results from the .. code-block:: nim for i in @[3, 4, 5]: - echo $i + echo i # --> 3 # --> 4 # --> 5 -- cgit 1.4.1-2-gfad0 From 6fa1dba515e514ea9a4ac5850b0188fb6cf95fbf Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Mon, 13 Feb 2017 19:37:20 +0700 Subject: Add ``tearDownForeignThreadGc`` function (#5369) --- doc/backends.txt | 8 ++++ lib/system/gc_common.nim | 29 +++++++++----- lib/system/threads.nim | 16 +++++++- tests/gc/foreign_thr.nim | 88 ++++++++++++++++++++++++++++++++++++++++++ tests/testament/categories.nim | 1 + 5 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 tests/gc/foreign_thr.nim (limited to 'doc') diff --git a/doc/backends.txt b/doc/backends.txt index 5846cce9b..6446103ed 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -461,3 +461,11 @@ can then attach a GC to this thread via It is **not** safe to disable the garbage collector and enable it after the call from your background thread even if the code you are calling is short lived. + +Before the thread exits, you should tear down the thread's GC to prevent memory +leaks by calling + +.. code-block:: nim + + system.tearDownForeignThreadGc() + diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 269514ceb..6ab6bd920 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -128,13 +128,7 @@ iterator items(stack: ptr GcStack): ptr GcStack = yield s s = s.next -# There will be problems with GC in foreign threads if `threads` option is off or TLS emulation is enabled -const allowForeignThreadGc = compileOption("threads") and not compileOption("tlsEmulation") - -when allowForeignThreadGc: - var - localGcInitialized {.rtlThreadVar.}: bool - +when declared(threadType): proc setupForeignThreadGc*() {.gcsafe.} = ## Call this if you registered a callback that will be run from a thread not ## under your control. This has a cheap thread-local guard, so the GC for @@ -143,16 +137,33 @@ when allowForeignThreadGc: ## ## This function is available only when ``--threads:on`` and ``--tlsEmulation:off`` ## switches are used - if not localGcInitialized: - localGcInitialized = true + if threadType == ThreadType.None: initAllocator() var stackTop {.volatile.}: pointer setStackBottom(addr(stackTop)) initGC() + threadType = ThreadType.ForeignThread + + proc tearDownForeignThreadGc*() {.gcsafe.} = + ## Call this to tear down the GC, previously initialized by ``setupForeignThreadGc``. + ## If GC has not been previously initialized, or has already been torn down, the + ## call does nothing. + ## + ## This function is available only when ``--threads:on`` and ``--tlsEmulation:off`` + ## switches are used + if threadType != ThreadType.ForeignThread: + return + when declared(deallocOsPages): deallocOsPages() + threadType = ThreadType.None + when declared(gch): zeroMem(addr gch, sizeof(gch)) + else: template setupForeignThreadGc*() = {.error: "setupForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".} + template tearDownForeignThreadGc*() = + {.error: "tearDownForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".} + # ----------------- stack management -------------------------------------- # inspired from Smart Eiffel diff --git a/lib/system/threads.nim b/lib/system/threads.nim index e8b34bf2e..6e58638e9 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -285,7 +285,19 @@ when useStackMaskHack: when not defined(useNimRtl): when not useStackMaskHack: #when not defined(createNimRtl): initStackBottom() - when declared(initGC): initGC() + when declared(initGC): + initGC() + when not emulatedThreadVars: + type ThreadType {.pure.} = enum + None = 0, + NimThread = 1, + ForeignThread = 2 + var + threadType {.rtlThreadVar.}: ThreadType + + threadType = ThreadType.NimThread + + when emulatedThreadVars: if nimThreadVarsSize() > sizeof(ThreadLocalStorage): @@ -442,6 +454,8 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) = # init the GC for refc/markandsweep setStackBottom(addr(p)) initGC() + when declared(threadType): + threadType = ThreadType.NimThread when declared(registerThread): thrd.stackBottom = addr(thrd) registerThread(thrd) diff --git a/tests/gc/foreign_thr.nim b/tests/gc/foreign_thr.nim new file mode 100644 index 000000000..88ab95113 --- /dev/null +++ b/tests/gc/foreign_thr.nim @@ -0,0 +1,88 @@ +discard """ + output: ''' +Hello from thread +Hello from thread +Hello from thread +Hello from thread +''' + cmd: "nim $target --hints:on --threads:on --tlsEmulation:off $options $file" +""" +# Copied from stdlib +import strutils + +const + StackGuardSize = 4096 + ThreadStackMask = 1024*256*sizeof(int)-1 + ThreadStackSize = ThreadStackMask+1 - StackGuardSize + +type ThreadFunc = proc() {.thread.} + +when defined(posix): + import posix + + proc runInForeignThread(f: ThreadFunc) = + proc wrapper(p: pointer): pointer {.noconv.} = + let thr = cast[ThreadFunc](p) + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + result = nil + + var attrs {.noinit.}: PthreadAttr + doAssert pthread_attr_init(addr attrs) == 0 + doAssert pthread_attr_setstacksize(addr attrs, ThreadStackSize) == 0 + var tid: Pthread + doAssert pthread_create(addr tid, addr attrs, wrapper, f) == 0 + doAssert pthread_join(tid, nil) == 0 + +elif defined(windows): + import winlean + type + WinThreadProc = proc (x: pointer): int32 {.stdcall.} + + proc createThread(lpThreadAttributes: pointer, dwStackSize: DWORD, + lpStartAddress: WinThreadProc, + lpParameter: pointer, + dwCreationFlags: DWORD, + lpThreadId: var DWORD): Handle {. + stdcall, dynlib: "kernel32", importc: "CreateThread".} + + proc wrapper(p: pointer): int32 {.stdcall.} = + let thr = cast[ThreadFunc](p) + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + result = 0'i32 + + proc runInForeignThread(f: ThreadFunc) = + var dummyThreadId: DWORD + var h = createThread(nil, ThreadStackSize.int32, wrapper.WinThreadProc, cast[pointer](f), 0, dummyThreadId) + doAssert h != 0.Handle + doAssert waitForSingleObject(h, -1'i32) == 0.DWORD + +else: + {.fatal: "Unknown system".} + +proc runInNativeThread(f: ThreadFunc) = + proc wrapper(f: ThreadFunc) {.thread.} = + # These operations must be NOP + setupForeignThreadGc() + tearDownForeignThreadGc() + f() + f() + var thr: Thread[ThreadFunc] + createThread(thr, wrapper, f) + joinThread(thr) + +proc f {.thread.} = + var msg = "Hello " & "from thread" + echo msg + +runInForeignThread(f) +runInNativeThread(f) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 2dc8e3318..0685dd73a 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -147,6 +147,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) = testSpec r, makeTest("tests/gc" / filename, options & " -d:release --gc:boehm", cat, actionRun) + testWithoutBoehm "foreign_thr" test "gcemscripten" test "growobjcrash" test "gcbench" -- cgit 1.4.1-2-gfad0 From 5620e085637fb3b090ce05092a4258427cd3e41a Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 17 Feb 2017 00:00:39 +0100 Subject: minor documentation improvements --- doc/manual/pragmas.txt | 12 ++++++------ lib/pure/os.nim | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'doc') diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index 2a276c2e7..af955a3e0 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -1018,12 +1018,12 @@ the -d/--define option at compile time. The implementation currently provides the following possible options (various others may be added later). -=============== ============================================ -pragma description -=============== ============================================ -intdefine Reads in a build-time define as an integer -strdefine Reads in a build-time define as a string -=============== ============================================ +================= ============================================ +pragma description +================= ============================================ +`intdefine`:idx: Reads in a build-time define as an integer +`strdefine`:idx: Reads in a build-time define as a string +================= ============================================ .. code-block:: nim const FooBar {.intdefine.}: int = 5 diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 92e295820..6bf776a44 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1185,7 +1185,7 @@ proc createHardlink*(src, dest: string) = proc parseCmdLine*(c: string): seq[string] {. noSideEffect, rtl, extern: "nos$1".} = - ## Splits a command line into several components; + ## Splits a `command line`:idx: into several components; ## This proc is only occasionally useful, better use the `parseopt` module. ## ## On Windows, it uses the following parsing rules -- cgit 1.4.1-2-gfad0 From 8f426b974a38d141205cac182d1883e1ecf8c9ce Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 17 Feb 2017 18:03:56 +0100 Subject: new feature: .used pragma to suppress declared-but-not-used warning --- compiler/pragmas.nim | 20 ++++++++++++-------- compiler/wordrecg.nim | 4 ++-- doc/manual/pragmas.txt | 20 ++++++++++++++++++++ tests/pragmas/tused.nim | 13 +++++++++++++ web/news/e031_version_0_16_2.rst | 4 ++++ 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 tests/pragmas/tused.nim (limited to 'doc') diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 04dbd3612..1fe1c81d2 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -25,19 +25,19 @@ const wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, - wOverride, wConstructor, wExportNims} + wOverride, wConstructor, wExportNims, wUsed} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty, - wDelegator, wExportNims} + wDelegator, wExportNims, wUsed} macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator, - wExportNims} + wExportNims, wUsed} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, - wTags, wLocks, wGcSafe, wExportNims} + wTags, wLocks, wGcSafe, wExportNims, wUsed} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, @@ -55,16 +55,16 @@ const wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, - wBorrow, wGcSafe, wExportNims, wPartial} + wBorrow, wGcSafe, wExportNims, wPartial, wUsed} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, - wImportCpp, wImportObjC, wError, wGuard, wBitsize} + wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, - wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} + wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims, - wIntDefine, wStrDefine} + wIntDefine, wStrDefine, wUsed} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, wThread, wRaises, wLocks, wTags, wGcSafe} @@ -961,6 +961,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, sym.magic = mIntDefine of wStrDefine: sym.magic = mStrDefine + of wUsed: + noVal(it) + if sym == nil: invalidPragma(it) + else: sym.flags.incl sfUsed else: invalidPragma(it) else: invalidPragma(it) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index cf66b6358..6072bd64c 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -45,7 +45,7 @@ type wImportc, wExportc, wExportNims, wIncompleteStruct, wRequiresInit, wAlign, wNodecl, wPure, wSideeffect, wHeader, wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib, - wCompilerproc, wProcVar, wBase, + wCompilerproc, wProcVar, wBase, wUsed, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wLink, wCompile, wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger, @@ -131,7 +131,7 @@ const "incompletestruct", "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib", - "compilerproc", "procvar", "base", + "compilerproc", "procvar", "base", "used", "fatal", "error", "warning", "hint", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index af955a3e0..d30c37ff7 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -503,6 +503,26 @@ identifier that can be used to enable or disable it: This is often better than disabling all warnings at once. +used pragma +----------- + +Nim produces a warning for symbols that are not exported and not used either. +The ``used`` pragma can be attached to a symbol to suppress this warning. This +is particularly useful when the symbol was generated by a macro: + +.. code-block:: nim + template implementArithOps(T) = + proc echoAdd(a, b: T) {.used.} = + echo a + b + proc echoSub(a, b: T) {.used.} = + echo a - b + + # no warning produced for the unused 'echoSub' + implementArithOps(int) + echoAdd 3, 5 + + + experimental pragma ------------------- diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim new file mode 100644 index 000000000..f3126bd45 --- /dev/null +++ b/tests/pragmas/tused.nim @@ -0,0 +1,13 @@ +discard """ + output: '''8''' +""" + +template implementArithOps(T) = + proc echoAdd(a, b: T) {.used.} = + echo a + b + proc echoSub(a, b: T) {.used.} = + echo a - b + +# no warning produced for the unused 'echoSub' +implementArithOps(int) +echoAdd 3, 5 diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst index 171e4cef1..785285eaf 100644 --- a/web/news/e031_version_0_16_2.rst +++ b/web/news/e031_version_0_16_2.rst @@ -66,6 +66,10 @@ these procedures. In the near future we will be converting all exception types to refs to remove the need for the ``newException`` template. +- A new pragma ``.used`` can be used for symbols to prevent +the "declared but not used" warning. More details can be found `here `_. + + Bugfixes -------- -- cgit 1.4.1-2-gfad0 From ce4587d7b721839ffa8ed4c9d1c2abd8f308f99d Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Mon, 20 Feb 2017 09:31:52 +0100 Subject: Enabled explicitly unknown lock levels (#5409) * enabled explicitly unknown lock levels * allowing "unknown" as locks pragma * added test case for locks pragma * updated docs on locks pragma --- compiler/pragmas.nim | 8 +++++++- doc/manual/locking.txt | 19 +++++++++++++++++++ tests/pragmas/tlocks.nim | 13 +++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/pragmas/tlocks.nim (limited to 'doc') diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1fe1c81d2..bcb0461f2 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -582,7 +582,13 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel = if it.kind != nkExprColonExpr: invalidPragma(it) else: - if it[1].kind != nkNilLit: + case it[1].kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + if it[1].strVal == "unknown": + result = UnknownLockLevel + else: + localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")") + else: let x = expectIntLit(c, it) if x < 0 or x > MaxLockLevel: localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) diff --git a/doc/manual/locking.txt b/doc/manual/locking.txt index c00efdd91..c1bd5ca46 100644 --- a/doc/manual/locking.txt +++ b/doc/manual/locking.txt @@ -198,3 +198,22 @@ This is essential so that procs can be called within a ``locks`` section: As usual ``locks`` is an inferred effect and there is a subtype relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` iff (M <= N). + +The ``locks`` pragma can also take the special value ``"unknown"``. This +is useful in the context of dynamic method dispatching. In the following +example, the compiler can infer a lock level of 0 for the ``base`` case. +However, one of the overloaded methods calls a procvar which is +potentially locking. Thus, the lock level of calling ``g.testMethod`` +cannot be inferred statically, leading to compiler warnings. By using +``{.locks: "unknown".}``, the base method can be marked explicitly as +having unknown lock level as well: + +.. code-block:: nim + type SomeBase* = ref object of RootObj + type SomeDerived* = ref object of SomeBase + memberProc*: proc () + + method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard + method testMethod(g: SomeDerived) = + if g.memberProc != nil: + g.memberProc() diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim new file mode 100644 index 000000000..ba66a2dca --- /dev/null +++ b/tests/pragmas/tlocks.nim @@ -0,0 +1,13 @@ + +type SomeBase* = ref object of RootObj +type SomeDerived* = ref object of SomeBase + memberProc*: proc () + +method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard +method testMethod(g: SomeDerived) = + if g.memberProc != nil: + g.memberProc() + +# ensure int literals still work +proc plain*() {.locks: 0.} = + discard -- cgit 1.4.1-2-gfad0