# # # Nim's Runtime Library # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## The compiler depends on the System module to work properly and the System ## module depends on the compiler. Most of the routines listed here use ## special compiler magic. ## ## Each module implicitly imports the System module; it must not be listed ## explicitly. Because of this there cannot be a user-defined module named ## `system`. ## ## System module ## ============= ## ## .. include:: ./system_overview.rst type float* {.magic: Float.} ## Default floating point type. float32* {.magic: Float32.} ## 32 bit floating point type. float64* {.magic: Float.} ## 64 bit floating point type. # 'float64' is now an alias to 'float'; this solves many problems type char* {.magic: Char.} ## Built-in 8 bit character type (unsigned). string* {.magic: String.} ## Built-in string type. cstring* {.magic: Cstring.} ## Built-in cstring (*compatible string*) type. pointer* {.magic: Pointer.} ## Built-in pointer type, use the `addr` ## operator to get a pointer to a variable. typedesc* {.magic: TypeDesc.} ## Meta type to denote a type description. type `ptr`*[T] {.magic: Pointer.} ## Built-in generic untraced pointer type. `ref`*[T] {.magic: Pointer.} ## Built-in generic traced pointer type. `nil` {.magic: "Nil".} void* {.magic: "VoidType".} ## Meta type to denote the absence of any type. auto* {.magic: Expr.} ## Meta type for automatic type determination. any* {.deprecated: "Deprecated since v1.5; Use auto instead.".} = distinct auto ## Deprecated; Use `auto` instead. See https://github.com/nim-lang/RFCs/issues/281 untyped* {.magic: Expr.} ## Meta type to denote an expression that ## is not resolved (for templates). typed* {.magic: Stmt.} ## Meta type to denote an expression that ## is resolved (for templates). include "system/basic_types" proc compileOption*(option: string): bool {. magic: "CompileOption", noSideEffect.} ## Can be used to determine an `on|off` compile-time option. ## ## See also: ## * `compileOption <#compileOption,string,string>`_ for enum options ## * `defined <#defined,untyped>`_ ## * `std/compilesettings module `_ ## ## Example: ## ## .. code-block:: Nim ## when compileOption("floatchecks"): ## echo "compiled with floating point NaN and Inf checks" proc compileOption*(option, arg: string): bool {. magic: "CompileOptionArg", noSideEffect.} ## Can be used to determine an enum compile-time option. ## ## See also: ## * `compileOption <#compileOption,string>`_ for `on|off` options ## * `defined <#defined,untyped>`_ ## * `std/compilesettings module `_ ## ## Example: ## ## .. code-block:: Nim ## when compileOption("opt", "size") and compileOption("gc", "boehm"): ## echo "compiled with optimization for size and uses Boehm's GC" {.push warning[GcMem]: off, warning[Uninit]: off.} {.push hints: off.} proc `or`*(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} ## Constructs an `or` meta class. proc `and`*(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} ## Constructs an `and` meta class. proc `not`*(a: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} ## Constructs an `not` meta class. type SomeFloat* = float|float32|float64 ## Type class matching all floating point number types. SomeNumber* = SomeInteger|SomeFloat ## Type class matching all number types. proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## defined. ## ## See also: ## * `compileOption <#compileOption,string>`_ for `on|off` options ## * `compileOption <#compileOption,string,string>`_ for enum options ## * `define pragmas `_ ## ## `x` is an external symbol introduced through the compiler's ## `-d:x switch `_ to enable ## build time conditionals: ## ## .. code-block:: Nim ## when not defined(release): ## # Do here programmer friendly expensive sanity checks. ## # Put here the normal code when defined(nimHashOrdinalFixed): type Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, ## bool, character, and enumeration types ## as well as their subtypes. See also ## `SomeOrdinal`. else: # bootstrap <= 0.20.0 type OrdinalImpl[T] {.magic: Ordinal.} Ordinal* = OrdinalImpl | uint | uint64 proc runnableExamples*(rdoccmd = "", body: untyped) {.magic: "RunnableExamples".} ## A section you should use to mark `runnable example`:idx: code with. ## ## - In normal debug and release builds code within ## a `runnableExamples` section is ignored. ## - The documentation generator is aware of these examples and considers them ## part of the `##` doc comment. As the last step of documentation ## generation each runnableExample is put in its own file `$file_examples$i.nim`, ## compiled and tested. The collected examples are ## put into their own module to ensure the examples do not refer to ## non-exported symbols. ## ## Usage: ## ## .. code-block:: Nim ## proc double*(x: int): int = ## ## This proc doubles a number. ## runnableExamples: ## ## at module scope ## assert double(5) == 10 ## block: ## at block scope ## defer: echo "done" ## result = 2 * x ## runnableExamples "-d:foo -b:cpp": ## import std/compilesettings ## doAssert querySetting(backend) == "cpp" ## runnableExamples "-r:off": ## this one is only compiled ## import std/browsers ## openDefaultBrowser "https://forum.nim-lang.org/" when defined(nimHasDeclaredMagic): proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## declared. `x` has to be an identifier or a qualified identifier. ## ## See also: ## * `declaredInScope <#declaredInScope,untyped>`_ ## ## This can be used to check whether a library provides a certain ## feature or not: ## ## .. code-block:: Nim ## when not declared(strutils.toUpper): ## # provide our own toUpper proc here, because strutils is ## # missing it. else: proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} when defined(nimHasDeclaredMagic): proc declaredInScope*(x: untyped): bool {.magic: "DeclaredInScope", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## declared in the current scope. `x` has to be an identifier. else: proc declaredInScope*(x: untyped): bool {.magic: "DefinedInScope", noSideEffect, compileTime.} proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory location. ## Cannot be overloaded. ## ## See also: ## * `unsafeAddr <#unsafeAddr,T>`_ ## ## .. code-block:: Nim ## var ## buf: seq[char] = @['a','b','c'] ## p = buf[1].addr ## echo p.repr # ref 0x7faa35c40059 --> 'b' ## echo p[] # b discard proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory ## location. This works even for `let` variables or parameters ## for better interop with C and so it is considered even more ## unsafe than the ordinary `addr <#addr,T>`_. ## ## **Note**: When you use it to write a wrapper for a C library, you should ## always check that the original library does never write to data behind the ## pointer that is returned from this procedure. ## ## Cannot be overloaded. discard type `static`*[T] {.magic: "Static".} ## Meta type representing all values that can be evaluated at compile-time. ## ## The type coercion `static(x)` can be used to force the compile-time ## evaluation of the given expression `x`. `type`*[T] {.magic: "Type".} ## Meta type representing the type of all type values. ## ## The coercion `type(x)` can be used to obtain the type of the given ## expression `x`. type TypeOfMode* = enum ## Possible modes of `typeof`. typeOfProc, ## Prefer the interpretation that means `x` is a proc call. typeOfIter ## Prefer the interpretation that means `x` is an iterator call. proc typeof*(x: untyped; mode = typeOfIter): typedesc {. magic: "TypeOf", noSideEffect, compileTime.} = ## Builtin `typeof` operation for accessing the type of an expression. ## Since version 0.20.0. runnableExamples: proc myFoo(): float = 0.0 iterator myFoo(): string = yield "abc" iterator myFoo2(): string = yield "abc" iterator myFoo3(): string {.closure.} = yield "abc" doAssert type(myFoo()) is string doAssert typeof(myFoo()) is string doAssert typeof(myFoo(), typeOfIter) is string doAssert typeof(myFoo3) is "iterator" doAssert typeof(myFoo(), typeOfProc) is float doAssert typeof(0.0, typeOfProc) is float doAssert typeof(myFoo3, typeOfProc) is "iterator" doAssert not compiles(typeof(myFoo2(), typeOfProc)) # this would give: Error: attempting to call routine: 'myFoo2' # since `typeOfProc` expects a typed expression and `myFoo2()` can # only be used in a `for` context. const ThisIsSystem = true proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} ## Leaked implementation detail. Do not use. when true: proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. magic: "NewFinalize", noSideEffect.} ## Creates a new object of type `T` and returns a safe (traced) ## reference to it in `a`. ## ## When the garbage collector frees the object, `finalizer` is called. ## The `finalizer` may not keep a reference to the ## object pointed to by `x`. The `finalizer` cannot prevent the GC from ## freeing the object. ## ## **Note**: The `finalizer` refers to the type `T`, not to the object! ## This means that for each object of type `T` the finalizer will be called! proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} = ## Resets an object `obj` to its initial (binary zero) value to signify ## it was "moved" and to signify its destructor should do nothing and ## ideally be optimized away. discard proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = result = x wasMoved(x) type range*[T]{.magic: "Range".} ## Generic type to construct range types. array*[I, T]{.magic: "Array".} ## Generic type to construct ## fixed-length arrays. openArray*[T]{.magic: "OpenArray".} ## Generic type to construct open arrays. ## Open arrays are implemented as a ## pointer to the array data and a ## length field. varargs*[T]{.magic: "Varargs".} ## Generic type to construct a varargs type. seq*[T]{.magic: "Seq".} ## Generic type to construct sequences. set*[T]{.magic: "Set".} ## Generic type to construct bit sets. type UncheckedArray*[T]{.magic: "UncheckedArray".} ## Array with no bounds checking. type sink*[T]{.magic: "BuiltinType".} type lent*[T]{.magic: "BuiltinType".} proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect, deprecated: "Deprecated since v1.4; there should not be `high(value)`. Use `high(type)`.".} ## Returns the highest possible value of an ordinal value `x`. ## ## As a special semantic rule, `x` may also be a type identifier. ## ## **This proc is deprecated**, use this one instead: ## * `high(typedesc) <#high,typedesc[T]>`_ ## ## .. code-block:: Nim ## high(2) # => 9223372036854775807 proc high*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "High", noSideEffect.} ## Returns the highest possible value of an ordinal or enum type. ## ## `high(int)` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:. ## ## See also: ## * `low(typedesc) <#low,typedesc[T]>`_ ## ## .. code-block:: Nim ## high(int) # => 9223372036854775807 proc high*[T](x: openArray[T]): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a sequence `x`. ## ## See also: ## * `low(openArray) <#low,openArray[T]>`_ ## ## .. code-block:: Nim ## var s = @[1, 2, 3, 4, 5, 6, 7] ## high(s) # => 6 ## for i in low(s)..high(s): ## echo s[i] proc high*[I, T](x: array[I, T]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array `x`. ## ## See also: ## * `low(array) <#low,array[I,T]>`_ ## ## .. code-block:: Nim ## var arr = [1, 2, 3, 4, 5, 6, 7] ## high(arr) # => 6 ## for i in low(arr)..high(arr): ## echo arr[i] proc high*[I, T](x: typedesc[array[I, T]]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array type. ## ## See also: ## * `low(typedesc[array]) <#low,typedesc[array[I,T]]>`_ ## ## .. code-block:: Nim ## high(array[7, int]) # => 6 proc high*(x: cstring): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a compatible string `x`. ## This is sometimes an O(n) operation. ## ## See also: ## * `low(cstring) <#low,cstring>`_ proc high*(x: string): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a string `x`. ## ## See also: ## * `low(string) <#low,string>`_ ## ## .. code-block:: Nim ## var str = "Hello world!" ## high(str) # => 11 proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect, deprecated: "Deprecated since v1.4; there should not be `low(value)`. Use `low(type)`.".} ## Returns the lowest possible value of an ordinal value `x`. As a special ## semantic rule, `x` may also be a type identifier. ## ## **This proc is deprecated**, use this one instead: ## * `low(typedesc) <#low,typedesc[T]>`_ ## ## .. code-block:: Nim ## low(2) # => -9223372036854775808 proc low*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "Low", noSideEffect.} ## Returns the lowest possible value of an ordinal or enum type. ## ## `low(int)` is Nim's way of writing `INT_MIN`:idx: or `MIN_INT`:idx:. ## ## See also: ## * `high(typedesc) <#high,typedesc[T]>`_ ## ## .. code-block:: Nim ## low(int) # => -9223372036854775808 proc low*[T](x: openArray[T]): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a sequence `x`. ## ## See also: ## * `high(openArray) <#high,openArray[T]>`_ ## ## .. code-block:: Nim ## var s = @[1, 2, 3, 4, 5, 6, 7] ## low(s) # => 0 ## for i in low(s)..high(s): ## echo s[i] proc low*[I, T](x: array[I, T]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array `x`. ## ## See also: ## * `high(array) <#high,array[I,T]>`_ ## ## .. code-block:: Nim ## var arr = [1, 2, 3, 4, 5, 6, 7] ## low(arr) # => 0 ## for i in low(arr)..high(arr): ## echo arr[i] proc low*[I, T](x: typedesc[array[I, T]]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array type. ## ## See also: ## * `high(typedesc[array]) <#high,typedesc[array[I,T]]>`_ ## ## .. code-block:: Nim ## low(array[7, int]) # => 0 proc low*(x: cstring): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a compatible string `x`. ## ## See also: ## * `high(cstring) <#high,cstring>`_ proc low*(x: string): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a string `x`. ## ## See also: ## * `high(string) <#high,string>`_ ## ## .. code-block:: Nim ## var str = "Hello world!" ## low(str) # => 0 proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} ## Use this instead of `=` for a `shallow copy`:idx:. ## ## The shallow copy only changes the semantics for sequences and strings ## (and types which contain those). ## ## Be careful with the changed semantics though! ## There is a reason why the default assignment does a deep copy of sequences ## and strings. # :array|openArray|string|seq|cstring|tuple proc `[]`*[I: Ordinal;T](a: T; i: I): T {. noSideEffect, magic: "ArrGet".} proc `[]=`*[I: Ordinal;T,S](a: T; i: I; x: sink S) {.noSideEffect, magic: "ArrPut".} proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} proc arrGet[I: Ordinal;T](a: T; i: I): T {. noSideEffect, magic: "ArrGet".} proc arrPut[I: Ordinal;T,S](a: T; i: I; x: S) {.noSideEffect, magic: "ArrPut".} proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = ## Generic `destructor`:idx: implementation that can be overridden. discard proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} = ## Generic `sink`:idx: implementation that can be overridden. shallowCopy(x, y) type HSlice*[T, U] = object ## "Heterogeneous" slice type. a*: T ## The lower bound (inclusive). b*: U ## The upper bound (inclusive). Slice*[T] = HSlice[T, T] ## An alias for `HSlice[T, T]`. proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} = ## Binary `slice`:idx: operator that constructs an interval `[a, b]`, both `a` ## and `b` are inclusive. ## ## Slices can also be used in the set constructor and in ordinal case ## statements, but then they are special-cased by the compiler. ## ## .. code-block:: Nim ## let a = [10, 20, 30, 40, 50] ## echo a[2 .. 3] # @[30, 40] result = HSlice[T, U](a: a, b: b) proc `..`*[T](b: sink T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} = ## Unary `slice`:idx: operator that constructs an interval `[default(int), b]`. ## ## .. code-block:: Nim ## let a = [10, 20, 30, 40, 50] ## echo a[.. 2] # @[10, 20, 30] result = HSlice[int, T](a: 0, b: b) when defined(hotCodeReloading): {.pragma: hcrInline, inline.} else: {.pragma: hcrInline.} {.push profiler: off.} let nimvm* {.magic: "Nimvm", compileTime.}: bool = false ## May be used only in `when` expression. ## It is true in Nim VM context and false otherwise. {.pop.} include "system/arithmetics" include "system/comparisons" const appType* {.magic: "AppType"}: string = "" ## A string that describes the application type. Possible values: ## `"console"`, `"gui"`, `"lib"`. include "system/inclrtl" const NoFakeVars* = defined(nimscript) ## `true` if the backend doesn't support \ ## "fake variables" like `var EBADF {.importc.}: cint`. const notJSnotNims = not defined(js) and not defined(nimscript) when not defined(js) and not defined(nimSeqsV2): type TGenericSeq {.compilerproc, pure, inheritable.} = object len, reserved:
#
#
#            Nim's Runtime Library
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Thread support for Nim. **Note**: This is part of the system module.
## Do not import it directly. To activate thread support you need to compile
## with the ``--threads:on`` command line switch.
##
## Nim's memory model for threads is quite different from other common
## programming languages (C, Pascal): Each thread has its own
## (garbage collected) heap and sharing of memory is restricted. This helps
## to prevent race conditions and improves efficiency. See `the manual for
## details of this memory model <manual.html#threads>`_.
##
## Example:
##
## .. code-block:: Nim
##
##  import locks
##
##  var
##    thr: array[0..4, Thread[tuple[a,b: int]]]
##    L: Lock
##
##  proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
##    for i in interval.a..interval.b:
##      acquire(L) # lock stdout
##      echo i
##      release(L)
##
##  initLock(L)
##
##  for i in 0..high(thr):
##    createThread(thr[i], threadFunc, (i*10, i*10+5))
##  joinThreads(thr)

when not declared(NimString):
  {.error: "You must not import this module explicitly".}

const
  maxRegisters = 256 # don't think there is an arch with more registers
  useStackMaskHack = false ## use the stack mask hack for better performance
  StackGuardSize = 4096
  ThreadStackMask = 1024*256*sizeof(int)-1
  ThreadStackSize = ThreadStackMask+1 - StackGuardSize

when defined(windows):
  type
    SysThread* = Handle
    WinThreadProc = proc (x: pointer): int32 {.stdcall.}
  {.deprecated: [TSysThread: SysThread, TWinThreadProc: WinThreadProc].}

  proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
                     lpStartAddress: WinThreadProc,
                     lpParameter: pointer,
                     dwCreationFlags: int32,
                     lpThreadId: var int32): SysThread {.
    stdcall, dynlib: "kernel32", importc: "CreateThread".}

  proc winSuspendThread(hThread: SysThread): int32 {.
    stdcall, dynlib: "kernel32", importc: "SuspendThread".}

  proc winResumeThread(hThread: SysThread): int32 {.
    stdcall, dynlib: "kernel32", importc: "ResumeThread".}

  proc waitForMultipleObjects(nCount: int32,
                              lpHandles: ptr SysThread,
                              bWaitAll: int32,
                              dwMilliseconds: int32): int32 {.
    stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}

  proc terminateThread(hThread: SysThread, dwExitCode: int32): int32 {.
    stdcall, dynlib: "kernel32", importc: "TerminateThread".}

  type
    ThreadVarSlot = distinct int32

  when true:
    proc threadVarAlloc(): ThreadVarSlot {.
      importc: "TlsAlloc", stdcall, header: "<windows.h>".}
    proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
      importc: "TlsSetValue", stdcall, header: "<windows.h>".}
    proc tlsGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
      importc: "TlsGetValue", stdcall, header: "<windows.h>".}

    proc getLastError(): uint32 {.
      importc: "GetLastError", stdcall, header: "<windows.h>".}
    proc setLastError(x: uint32) {.
      importc: "SetLastError", stdcall, header: "<windows.h>".}

    proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer =
      let realLastError = getLastError()
      result = tlsGetValue(dwTlsIndex)
      setLastError(realLastError)
  else:
    proc threadVarAlloc(): ThreadVarSlot {.
      importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
    proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
      importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
    proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
      importc: "TlsGetValue", stdcall, dynlib: "kernel32".}

  proc setThreadAffinityMask(hThread: SysThread, dwThreadAffinityMask: uint) {.
    importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".}

else:
  when not defined(macosx):
    {.passL: "-pthread".}

  {.passC: "-pthread".}
  const
    schedh = "#define _GNU_SOURCE\n#include <sched.h>"
    pthreadh = "#define _GNU_SOURCE\n#include <pthread.h>"

  when defined(linux):
    type Time = clong
  else:
    type Time = int

  type
    SysThread* {.importc: "pthread_t", header: "<sys/types.h>",
                 final, pure.} = object
    Pthread_attr {.importc: "pthread_attr_t",
                     header: "<sys/types.h>", final, pure.} = object

    Timespec {.importc: "struct timespec",
                header: "<time.h>", final, pure.} = object
      tv_sec: Time
      tv_nsec: clong
  {.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr,
                Ttimespec: Timespec].}

  proc pthread_attr_init(a1: var PthreadAttr) {.
    importc, header: pthreadh.}
  proc pthread_attr_setstacksize(a1: var PthreadAttr, a2: int) {.
    importc, header: pthreadh.}

  proc pthread_create(a1: var SysThread, a2: var PthreadAttr,
            a3: proc (x: pointer): pointer {.noconv.},
            a4: pointer): cint {.importc: "pthread_create",
            header: pthreadh.}
  proc pthread_join(a1: SysThread, a2: ptr pointer): cint {.
    importc, header: pthreadh.}

  proc pthread_cancel(a1: SysThread): cint {.
    importc: "pthread_cancel", header: pthreadh.}

  type
    ThreadVarSlot {.importc: "pthread_key_t", pure, final,
                   header: "<sys/types.h>".} = object
  {.deprecated: [TThreadVarSlot: ThreadVarSlot].}

  proc pthread_getspecific(a1: ThreadVarSlot): pointer {.
    importc: "pthread_getspecific", header: pthreadh.}
  proc pthread_key_create(a1: ptr ThreadVarSlot,
                          destruct: proc (x: pointer) {.noconv.}): int32 {.
    importc: "pthread_key_create", header: pthreadh.}
  proc pthread_key_delete(a1: ThreadVarSlot): int32 {.
    importc: "pthread_key_delete", header: pthreadh.}

  proc pthread_setspecific(a1: ThreadVarSlot, a2: pointer): int32 {.
    importc: "pthread_setspecific", header: pthreadh.}

  proc threadVarAlloc(): ThreadVarSlot {.inline.} =
    discard pthread_key_create(addr(result), nil)
  proc threadVarSetValue(s: ThreadVarSlot, value: pointer) {.inline.} =
    discard pthread_setspecific(s, value)
  proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} =
    result = pthread_getspecific(s)

  when useStackMaskHack:
    proc pthread_attr_setstack(attr: var PthreadAttr, stackaddr: pointer,
                               size: int): cint {.
      importc: "pthread_attr_setstack", header: pthreadh.}

  type CpuSet {.importc: "cpu_set_t", header: schedh.} = object
  proc cpusetZero(s: var CpuSet) {.importc: "CPU_ZERO", header: schedh.}
  proc cpusetIncl(cpu: cint; s: var CpuSet) {.
    importc: "CPU_SET", header: schedh.}

  proc setAffinity(thread: SysThread; setsize: csize; s: var CpuSet) {.
    importc: "pthread_setaffinity_np", header: pthreadh.}

const
  emulatedThreadVars = compileOption("tlsEmulation")

when emulatedThreadVars:
  # the compiler generates this proc for us, so that we can get the size of
  # the thread local var block; we use this only for sanity checking though
  proc nimThreadVarsSize(): int {.noconv, importc: "NimThreadVarsSize".}

# we preallocate a fixed size for thread local storage, so that no heap
# allocations are needed. Currently less than 7K are used on a 64bit machine.
# We use ``float`` for proper alignment:
type
  ThreadLocalStorage = array[0..1_000, float]

  PGcThread = ptr GcThread
  GcThread {.pure, inheritable.} = object
    sys: SysThread
    when emulatedThreadVars and not useStackMaskHack:
      tls: ThreadLocalStorage
    else:
      nil
    when hasSharedHeap:
      next, prev: PGcThread
      stackBottom, stackTop: pointer
      stackSize: int
    else:
      nil
{.deprecated: [TThreadLocalStorage: ThreadLocalStorage, TGcThread: GcThread].}

when not defined(useNimRtl):
  when not useStackMaskHack:
    var mainThread: GcThread

#const globalsSlot = ThreadVarSlot(0)
#sysAssert checkSlot.int == globalsSlot.int

when emulatedThreadVars:
  # XXX it'd be more efficient to not use a global variable for the
  # thread storage slot, but to rely on the implementation to assign slot X
  # for us... ;-)
  var globalsSlot: ThreadVarSlot

  proc GetThreadLocalVars(): pointer {.compilerRtl, inl.} =
    result = addr(cast[PGcThread](threadVarGetValue(globalsSlot)).tls)

  proc initThreadVarsEmulation() {.compilerProc, inline.} =
    when not defined(useNimRtl):
      globalsSlot = threadVarAlloc()
      when declared(mainThread):
        threadVarSetValue(globalsSlot, addr(mainThread))

when useStackMaskHack:
  proc maskStackPointer(offset: int): pointer {.compilerRtl, inl.} =
    var x {.volatile.}: pointer
    x = addr(x)
    result = cast[pointer]((cast[int](x) and not ThreadStackMask) +%
      (0) +% offset)

# create for the main thread. Note: do not insert this data into the list
# of all threads; it's not to be stopped etc.
when not defined(useNimRtl):
  when not useStackMaskHack:
    #when not defined(createNimRtl): initStackBottom()
    when declared(initGC): initGC()

  when emulatedThreadVars:
    if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
      echo "too large thread local storage size requested"
      quit 1

  when hasSharedHeap and not defined(boehmgc) and not defined(gogc) and not defined(nogc):
    var
      threadList: PGcThread

    proc registerThread(t: PGcThread) =
      # we need to use the GC global lock here!
      acquireSys(HeapLock)
      t.prev = nil
      t.next = threadList
      if threadList != nil:
        sysAssert(threadList.prev == nil, "threadList.prev == nil")
        threadList.prev = t
      threadList = t
      releaseSys(HeapLock)

    proc unregisterThread(t: PGcThread) =
      # we need to use the GC global lock here!
      acquireSys(HeapLock)
      if t == threadList: threadList = t.next
      if t.next != nil: t.next.prev = t.prev
      if t.prev != nil: t.prev.next = t.next
      # so that a thread can be unregistered twice which might happen if the
      # code executes `destroyThread`:
      t.next = nil
      t.prev = nil
      releaseSys(HeapLock)

    # on UNIX, the GC uses ``SIGFREEZE`` to tell every thread to stop so that
    # the GC can examine the stacks?
    proc stopTheWord() = discard

# We jump through some hops here to ensure that Nim thread procs can have
# the Nim calling convention. This is needed because thread procs are
# ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.

type
  Thread* {.pure, final.}[TArg] =
      object of GcThread  ## Nim thread. A thread is a heavy object (~14K)
                          ## that **must not** be part of a message! Use
                          ## a ``ThreadId`` for that.
    when TArg is void:
      dataFn: proc () {.nimcall, gcsafe.}
    else:
      dataFn: proc (m: TArg) {.nimcall, gcsafe.}
      data: TArg
  ThreadId*[TArg] = ptr Thread[TArg]  ## the current implementation uses
                                       ## a pointer as a thread ID.
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}

when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcstack):
  proc deallocOsPages()

when defined(boehmgc):
  type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
  proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer)
    {.importc: "GC_call_with_stack_base", boehmGC.}
  proc boehmGC_register_my_thread(sb: pointer)
    {.importc: "GC_register_my_thread", boehmGC.}
  proc boehmGC_unregister_my_thread()
    {.importc: "GC_unregister_my_thread", boehmGC.}

  proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} =
    boehmGC_register_my_thread(sb)
    let thrd = cast[ptr Thread[TArg]](thrd)
    when TArg is void:
      thrd.dataFn()
    else:
      thrd.dataFn(thrd.data)
    boehmGC_unregister_my_thread()
else:
  proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) =
    when TArg is void:
      thrd.dataFn()
    else:
      var x: TArg
      deepCopy(x, thrd.data)
      thrd.dataFn(x)

proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
  when defined(boehmgc):
    boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd)
  elif not defined(nogc) and not defined(gogc) and not defined(gcstack):
    var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall.} =
      threadProcWrapDispatch[TArg]
    when not hasSharedHeap:
      # init the GC for refc/markandsweep
      setStackBottom(addr(p))
      initGC()
    when declared(registerThread):
      thrd.stackBottom = addr(thrd)
      registerThread(thrd)
    p(thrd)
    when declared(registerThread): unregisterThread(thrd)
    when declared(deallocOsPages): deallocOsPages()
  else:
    threadProcWrapDispatch(thrd)

template threadProcWrapperBody(closure: expr) {.immediate.} =
  when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
  when declared(initAllocator):
    initAllocator()
  var thrd = cast[ptr Thread[TArg]](closure)
  threadProcWrapStackFrame(thrd)
  # Since an unhandled exception terminates the whole process (!), there is
  # no need for a ``try finally`` here, nor would it be correct: The current
  # exception is tried to be re-raised by the code-gen after the ``finally``!
  # However this is doomed to fail, because we already unmapped every heap
  # page!

  # mark as not running anymore:
  thrd.dataFn = nil

{.push stack_trace:off.}
when defined(windows):
  proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} =
    threadProcWrapperBody(closure)
    # implicitly return 0
else:
  proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} =
    threadProcWrapperBody(closure)
{.pop.}

proc running*[TArg](t: Thread[TArg]): bool {.inline.} =
  ## returns true if `t` is running.
  result = t.dataFn != nil

proc handle*[TArg](t: Thread[TArg]): SysThread {.inline.} =
  ## returns the thread handle of `t`.
  result = t.sys

when hostOS == "windows":
  proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
    ## waits for the thread `t` to finish.
    discard waitForSingleObject(t.sys, -1'i32)

  proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
    ## waits for every thread in `t` to finish.
    var a: array[0..255, SysThread]
    sysAssert a.len >= t.len, "a.len >= t.len"
    for i in 0..t.high: a[i] = t[i].sys
    discard waitForMultipleObjects(t.len.int32,
                                   cast[ptr SysThread](addr(a)), 1, -1)

else:
  proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
    ## waits for the thread `t` to finish.
    discard pthread_join(t.sys, nil)

  proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
    ## waits for every thread in `t` to finish.
    for i in 0..t.high: joinThread(t[i])

when false:
  # XXX a thread should really release its heap here somehow:
  proc destroyThread*[TArg](t: var Thread[TArg]) =
    ## forces the thread `t` to terminate. This is potentially dangerous if
    ## you don't have full control over `t` and its acquired resources.
    when hostOS == "windows":
      discard TerminateThread(t.sys, 1'i32)
    else:
      discard pthread_cancel(t.sys)
    when declared(registerThread): unregisterThread(addr(t))
    t.dataFn = nil

when hostOS == "windows":
  proc createThread*[TArg](t: var Thread[TArg],
                           tp: proc (arg: TArg) {.thread, nimcall.},
                           param: TArg) =
    ## creates a new thread `t` and starts its execution. Entry point is the
    ## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you
    ## don't need to pass any data to the thread.
    when TArg isnot void: t.data = param
    t.dataFn = tp
    when hasSharedHeap: t.stackSize = ThreadStackSize
    var dummyThreadId: int32
    t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg],
                         addr(t), 0'i32, dummyThreadId)
    if t.sys <= 0:
      raise newException(ResourceExhaustedError, "cannot create thread")

  proc pinToCpu*[Arg](t: