mirror of
https://github.com/nim-lang/Nim.git
synced 2026-05-01 11:34:43 +00:00
improved documentation for several modules (#10752)
More detailed documentation for: * md5 * hashes Mostly cosmetic improvements for: * threadpool * typetraits * channels * threads
This commit is contained in:
@@ -8,6 +8,12 @@
|
||||
#
|
||||
|
||||
## Implements Nim's `spawn <manual.html#parallel-amp-spawn>`_.
|
||||
##
|
||||
## **See also:**
|
||||
## * `threads module <threads.html>`_
|
||||
## * `chanels module <channels.html>`_
|
||||
## * `locks module <locks.html>`_
|
||||
## * `asyncdispatch module <asyncdispatch.html>`_
|
||||
|
||||
when not compileOption("threads"):
|
||||
{.error: "Threadpool requires --threads:on option.".}
|
||||
@@ -53,7 +59,7 @@ type
|
||||
cacheAlign: array[CacheLineSize-4*sizeof(int), byte]
|
||||
left: int
|
||||
cacheAlign2: array[CacheLineSize-sizeof(int), byte]
|
||||
interest: bool ## wether the master is interested in the "all done" event
|
||||
interest: bool # whether the master is interested in the "all done" event
|
||||
|
||||
proc barrierEnter(b: ptr Barrier) {.compilerProc, inline.} =
|
||||
# due to the signaling between threads, it is ensured we are the only
|
||||
@@ -93,11 +99,10 @@ type
|
||||
cv: Semaphore
|
||||
idx: int
|
||||
|
||||
FlowVarBase* = ref FlowVarBaseObj ## untyped base class for 'FlowVar[T]'
|
||||
FlowVarBase* = ref FlowVarBaseObj ## Untyped base class for ``FlowVar[T]``.
|
||||
FlowVarBaseObj = object of RootObj
|
||||
ready, usesSemaphore, awaited: bool
|
||||
cv: Semaphore #\
|
||||
# for 'blockUntilAny' support
|
||||
cv: Semaphore # for 'blockUntilAny' support
|
||||
ai: ptr AwaitInfo
|
||||
idx: int
|
||||
data: pointer # we incRef and unref it to keep it alive; note this MUST NOT
|
||||
@@ -107,7 +112,7 @@ type
|
||||
FlowVarObj[T] = object of FlowVarBaseObj
|
||||
blob: T
|
||||
|
||||
FlowVar*{.compilerProc.}[T] = ref FlowVarObj[T] ## a data flow variable
|
||||
FlowVar*{.compilerProc.}[T] = ref FlowVarObj[T] ## A data flow variable.
|
||||
|
||||
ToFreeQueue = object
|
||||
len: int
|
||||
@@ -129,8 +134,9 @@ type
|
||||
readyForTask: Semaphore
|
||||
|
||||
proc blockUntil*(fv: FlowVarBase) =
|
||||
## waits until the value for the flowVar arrives. Usually it is not necessary
|
||||
## to call this explicitly.
|
||||
## Waits until the value for the ``fv`` arrives.
|
||||
##
|
||||
## Usually it is not necessary to call this explicitly.
|
||||
if fv.usesSemaphore and not fv.awaited:
|
||||
fv.awaited = true
|
||||
blockUntil(fv.cv)
|
||||
@@ -216,10 +222,12 @@ proc nimFlowVarSignal(fv: FlowVarBase) {.compilerProc.} =
|
||||
signal(fv.cv)
|
||||
|
||||
proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
|
||||
## blocks until the ``fv`` is available and then passes its value
|
||||
## to ``action``. Note that due to Nim's parameter passing semantics this
|
||||
## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can
|
||||
## sometimes be more efficient than ``^``.
|
||||
## Blocks until the ``fv`` is available and then passes its value
|
||||
## to ``action``.
|
||||
##
|
||||
## Note that due to Nim's parameter passing semantics this
|
||||
## means that ``T`` doesn't need to be copied so ``awaitAndThen`` can
|
||||
## sometimes be more efficient than `^ proc <#^,FlowVar[T]>`_.
|
||||
blockUntil(fv)
|
||||
when T is string or T is seq:
|
||||
action(cast[T](fv.data))
|
||||
@@ -230,18 +238,18 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
|
||||
finished(fv)
|
||||
|
||||
proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T =
|
||||
## blocks until the value is available and then returns this value.
|
||||
## Blocks until the value is available and then returns this value.
|
||||
blockUntil(fv)
|
||||
result = cast[ptr T](fv.data)
|
||||
|
||||
proc `^`*[T](fv: FlowVar[ref T]): ref T =
|
||||
## blocks until the value is available and then returns this value.
|
||||
## Blocks until the value is available and then returns this value.
|
||||
blockUntil(fv)
|
||||
let src = cast[ref T](fv.data)
|
||||
deepCopy result, src
|
||||
|
||||
proc `^`*[T](fv: FlowVar[T]): T =
|
||||
## blocks until the value is available and then returns this value.
|
||||
## Blocks until the value is available and then returns this value.
|
||||
blockUntil(fv)
|
||||
when T is string or T is seq:
|
||||
# XXX closures? deepCopy?
|
||||
@@ -250,11 +258,14 @@ proc `^`*[T](fv: FlowVar[T]): T =
|
||||
result = fv.blob
|
||||
|
||||
proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int =
|
||||
## awaits any of the given flowVars. Returns the index of one flowVar for
|
||||
## which a value arrived. A flowVar only supports one call to 'blockUntilAny' at
|
||||
## the same time. That means if you blockUntilAny([a,b]) and blockUntilAny([b,c]) the second
|
||||
## call will only blockUntil 'c'. If there is no flowVar left to be able to wait
|
||||
## on, -1 is returned.
|
||||
## Awaits any of the given ``flowVars``. Returns the index of one ``flowVar``
|
||||
## for which a value arrived.
|
||||
##
|
||||
## A ``flowVar`` only supports one call to ``blockUntilAny`` at the same time.
|
||||
## That means if you ``blockUntilAny([a,b])`` and ``blockUntilAny([b,c])``
|
||||
## the second call will only block until ``c``. If there is no ``flowVar`` left
|
||||
## to be able to wait on, -1 is returned.
|
||||
##
|
||||
## **Note**: This results in non-deterministic behaviour and should be avoided.
|
||||
var ai: AwaitInfo
|
||||
ai.cv.initSemaphore()
|
||||
@@ -278,7 +289,7 @@ proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int =
|
||||
proc isReady*(fv: FlowVarBase): bool =
|
||||
## Determines whether the specified ``FlowVarBase``'s value is available.
|
||||
##
|
||||
## If ``true`` awaiting ``fv`` will not block.
|
||||
## If ``true``, awaiting ``fv`` will not block.
|
||||
if fv.usesSemaphore and not fv.awaited:
|
||||
acquire(fv.cv.L)
|
||||
result = fv.cv.counter > 0
|
||||
@@ -291,9 +302,9 @@ proc nimArgsPassingDone(p: pointer) {.compilerProc.} =
|
||||
signal(w.taskStarted)
|
||||
|
||||
const
|
||||
MaxThreadPoolSize* = 256 ## maximal size of the thread pool. 256 threads
|
||||
MaxThreadPoolSize* = 256 ## Maximum size of the thread pool. 256 threads
|
||||
## should be good enough for anybody ;-)
|
||||
MaxDistinguishedThread* = 32 ## maximal number of "distinguished" threads.
|
||||
MaxDistinguishedThread* = 32 ## Maximum number of "distinguished" threads.
|
||||
|
||||
type
|
||||
ThreadId* = range[0..MaxDistinguishedThread-1]
|
||||
@@ -368,12 +379,12 @@ when defined(nimPinToCpu):
|
||||
var gCpus: Natural
|
||||
|
||||
proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) =
|
||||
## sets the minimal thread pool size. The default value of this is 4.
|
||||
## Sets the minimum thread pool size. The default value of this is 4.
|
||||
minPoolSize = size
|
||||
|
||||
proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) =
|
||||
## sets the maximal thread pool size. The default value of this
|
||||
## is ``MaxThreadPoolSize``.
|
||||
## Sets the maximum thread pool size. The default value of this
|
||||
## is ``MaxThreadPoolSize`` (256).
|
||||
maxPoolSize = size
|
||||
if currentPoolSize > maxPoolSize:
|
||||
for i in maxPoolSize..currentPoolSize-1:
|
||||
@@ -413,37 +424,46 @@ proc setup() =
|
||||
for i in 0..<currentPoolSize: activateWorkerThread(i)
|
||||
|
||||
proc preferSpawn*(): bool =
|
||||
## Use this proc to determine quickly if a 'spawn' or a direct call is
|
||||
## preferable. If it returns 'true' a 'spawn' may make sense. In general
|
||||
## it is not necessary to call this directly; use 'spawnX' instead.
|
||||
## Use this proc to determine quickly if a ``spawn`` or a direct call is
|
||||
## preferable.
|
||||
##
|
||||
## If it returns ``true``, a ``spawn`` may make sense. In general
|
||||
## it is not necessary to call this directly; use `spawnX template
|
||||
## <#spawnX.t>`_ instead.
|
||||
result = gSomeReady.counter > 0
|
||||
|
||||
proc spawn*(call: typed): void {.magic: "Spawn".}
|
||||
## always spawns a new task, so that the 'call' is never executed on
|
||||
## the calling thread. 'call' has to be proc call 'p(...)' where 'p'
|
||||
## is gcsafe and has a return type that is either 'void' or compatible
|
||||
## with ``FlowVar[T]``.
|
||||
## Always spawns a new task, so that the ``call`` is never executed on
|
||||
## the calling thread.
|
||||
##
|
||||
## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a
|
||||
## return type that is either ``void`` or compatible with ``FlowVar[T]``.
|
||||
|
||||
proc pinnedSpawn*(id: ThreadId; call: typed): void {.magic: "Spawn".}
|
||||
## always spawns a new task on the worker thread with ``id``, so that
|
||||
## the 'call' is **always** executed on
|
||||
## the thread. 'call' has to be proc call 'p(...)' where 'p'
|
||||
## is gcsafe and has a return type that is either 'void' or compatible
|
||||
## with ``FlowVar[T]``.
|
||||
## Always spawns a new task on the worker thread with ``id``, so that
|
||||
## the ``call`` is **always** executed on the thread.
|
||||
##
|
||||
## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a
|
||||
## return type that is either ``void`` or compatible with ``FlowVar[T]``.
|
||||
|
||||
template spawnX*(call): void =
|
||||
## spawns a new task if a CPU core is ready, otherwise executes the
|
||||
## call in the calling thread. Usually it is advised to
|
||||
## use 'spawn' in order to not block the producer for an unknown
|
||||
## amount of time. 'call' has to be proc call 'p(...)' where 'p'
|
||||
## is gcsafe and has a return type that is either 'void' or compatible
|
||||
## with ``FlowVar[T]``.
|
||||
## Spawns a new task if a CPU core is ready, otherwise executes the
|
||||
## call in the calling thread.
|
||||
##
|
||||
## Usually it is advised to use `spawn proc <#spawn,typed>`_ in order to
|
||||
## not block the producer for an unknown amount of time.
|
||||
##
|
||||
## ``call`` has to be proc call ``p(...)`` where ``p`` is gcsafe and has a
|
||||
## return type that is either 'void' or compatible with ``FlowVar[T]``.
|
||||
(if preferSpawn(): spawn call else: call)
|
||||
|
||||
proc parallel*(body: untyped) {.magic: "Parallel".}
|
||||
## a parallel section can be used to execute a block in parallel. ``body``
|
||||
## has to be in a DSL that is a particular subset of the language. Please
|
||||
## refer to the manual for further information.
|
||||
## A parallel section can be used to execute a block in parallel.
|
||||
##
|
||||
## ``body`` has to be in a DSL that is a particular subset of the language.
|
||||
##
|
||||
## Please refer to `the manual <manual.html#parallel-amp-spawn>`_
|
||||
## for further information.
|
||||
|
||||
var
|
||||
state: ThreadPoolState
|
||||
@@ -547,8 +567,9 @@ proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerProc.} =
|
||||
|
||||
|
||||
proc sync*() =
|
||||
## a simple barrier to wait for all spawn'ed tasks. If you need more elaborate
|
||||
## waiting, you have to use an explicit barrier.
|
||||
## A simple barrier to wait for all ``spawn``'ed tasks.
|
||||
##
|
||||
## If you need more elaborate waiting, you have to use an explicit barrier.
|
||||
var toRelease = 0
|
||||
while true:
|
||||
var allReady = true
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
## This module implements efficient computations of hash values for diverse
|
||||
## Nim types. All the procs are based on these two building blocks:
|
||||
## - `!& proc <#!&>`_ used to start or mix a hash value, and
|
||||
## - `!$ proc <#!$>`_ used to *finish* the hash value.
|
||||
## If you want to implement hash procs for
|
||||
## your custom types you will end up writing the following kind of skeleton of
|
||||
## code:
|
||||
## - `!& proc <#!&,Hash,int>`_ used to start or mix a hash value, and
|
||||
## - `!$ proc <#!$,Hash>`_ used to *finish* the hash value.
|
||||
##
|
||||
## If you want to implement hash procs for your custom types,
|
||||
## you will end up writing the following kind of skeleton of code:
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## proc hash(x: Something): Hash =
|
||||
@@ -37,31 +37,40 @@
|
||||
## h = h !& hash(x.foo)
|
||||
## h = h !& hash(x.bar)
|
||||
## result = !$h
|
||||
##
|
||||
## **See also:**
|
||||
## * `md5 module <md5.html>`_ for MD5 checksum algorithm
|
||||
## * `base64 module <base64.html>`_ for a base64 encoder and decoder
|
||||
## * `std/sha1 module <sha1.html>`_ for a sha1 encoder and decoder
|
||||
## * `tables modlule <tables.html>`_ for hash tables
|
||||
|
||||
|
||||
import
|
||||
strutils
|
||||
|
||||
type
|
||||
Hash* = int ## a hash value; hash tables using these values should
|
||||
Hash* = int ## A hash value. Hash tables using these values should
|
||||
## always have a size of a power of two and can use the ``and``
|
||||
## operator instead of ``mod`` for truncation of the hash value.
|
||||
|
||||
proc `!&`*(h: Hash, val: int): Hash {.inline.} =
|
||||
## mixes a hash value `h` with `val` to produce a new hash value. This is
|
||||
## only needed if you need to implement a hash proc for a new datatype.
|
||||
## Mixes a hash value `h` with `val` to produce a new hash value.
|
||||
##
|
||||
## This is only needed if you need to implement a hash proc for a new datatype.
|
||||
result = h +% val
|
||||
result = result +% result shl 10
|
||||
result = result xor (result shr 6)
|
||||
|
||||
proc `!$`*(h: Hash): Hash {.inline.} =
|
||||
## finishes the computation of the hash value. This is
|
||||
## only needed if you need to implement a hash proc for a new datatype.
|
||||
## Finishes the computation of the hash value.
|
||||
##
|
||||
## This is only needed if you need to implement a hash proc for a new datatype.
|
||||
result = h +% h shl 3
|
||||
result = result xor (result shr 11)
|
||||
result = result +% result shl 15
|
||||
|
||||
proc hashData*(data: pointer, size: int): Hash =
|
||||
## hashes an array of bytes of size `size`
|
||||
## Hashes an array of bytes of size `size`.
|
||||
var h: Hash = 0
|
||||
when defined(js):
|
||||
var p: cstring
|
||||
@@ -80,7 +89,7 @@ when defined(js):
|
||||
var objectID = 0
|
||||
|
||||
proc hash*(x: pointer): Hash {.inline.} =
|
||||
## efficient hashing of pointers
|
||||
## Efficient hashing of pointers.
|
||||
when defined(js):
|
||||
asm """
|
||||
if (typeof `x` == "object") {
|
||||
@@ -97,45 +106,57 @@ proc hash*(x: pointer): Hash {.inline.} =
|
||||
|
||||
when not defined(booting):
|
||||
proc hash*[T: proc](x: T): Hash {.inline.} =
|
||||
## efficient hashing of proc vars; closures are supported too.
|
||||
## Efficient hashing of proc vars. Closures are supported too.
|
||||
when T is "closure":
|
||||
result = hash(rawProc(x)) !& hash(rawEnv(x))
|
||||
else:
|
||||
result = hash(pointer(x))
|
||||
|
||||
proc hash*(x: int): Hash {.inline.} =
|
||||
## efficient hashing of integers
|
||||
## Efficient hashing of integers.
|
||||
result = x
|
||||
|
||||
proc hash*(x: int64): Hash {.inline.} =
|
||||
## efficient hashing of int64 integers
|
||||
## Efficient hashing of `int64` integers.
|
||||
result = toU32(x)
|
||||
|
||||
proc hash*(x: uint): Hash {.inline.} =
|
||||
## efficient hashing of unsigned integers
|
||||
## Efficient hashing of unsigned integers.
|
||||
result = cast[int](x)
|
||||
|
||||
proc hash*(x: uint64): Hash {.inline.} =
|
||||
## efficient hashing of uint64 integers
|
||||
## Efficient hashing of `uint64` integers.
|
||||
result = toU32(cast[int](x))
|
||||
|
||||
proc hash*(x: char): Hash {.inline.} =
|
||||
## efficient hashing of characters
|
||||
## Efficient hashing of characters.
|
||||
result = ord(x)
|
||||
|
||||
proc hash*[T: Ordinal](x: T): Hash {.inline.} =
|
||||
## efficient hashing of other ordinal types (e.g., enums)
|
||||
## Efficient hashing of other ordinal types (e.g. enums).
|
||||
result = ord(x)
|
||||
|
||||
proc hash*(x: string): Hash =
|
||||
## efficient hashing of strings
|
||||
## Efficient hashing of strings.
|
||||
##
|
||||
## See also:
|
||||
## * `hashIgnoreStyle <#hashIgnoreStyle,string>`_
|
||||
## * `hashIgnoreCase <#hashIgnoreCase,string>`_
|
||||
runnableExamples:
|
||||
doAssert hash("abracadabra") == -5600162842546114722
|
||||
doAssert hash("Abracadabra") == 2068684413884279454
|
||||
|
||||
var h: Hash = 0
|
||||
for i in 0..x.len-1:
|
||||
h = h !& ord(x[i])
|
||||
result = !$h
|
||||
|
||||
proc hash*(x: cstring): Hash =
|
||||
## efficient hashing of null-terminated strings
|
||||
## Efficient hashing of null-terminated strings.
|
||||
runnableExamples:
|
||||
doAssert hash(cstring"abracadabra") == -5600162842546114722
|
||||
doAssert hash(cstring"Abracadabra") == 2068684413884279454
|
||||
|
||||
var h: Hash = 0
|
||||
var i = 0
|
||||
when defined(js):
|
||||
@@ -149,17 +170,27 @@ proc hash*(x: cstring): Hash =
|
||||
result = !$h
|
||||
|
||||
proc hash*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos`
|
||||
## Efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos` (included).
|
||||
##
|
||||
## ``hash(myStr, 0, myStr.high)`` is equivalent to ``hash(myStr)``
|
||||
## ``hash(myStr, 0, myStr.high)`` is equivalent to ``hash(myStr)``.
|
||||
runnableExamples:
|
||||
var a = "abracadabra"
|
||||
doAssert hash(a, 0, 3) == hash(a, 7, 10)
|
||||
|
||||
var h: Hash = 0
|
||||
for i in sPos..ePos:
|
||||
h = h !& ord(sBuf[i])
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreStyle*(x: string): Hash =
|
||||
## efficient hashing of strings; style is ignored
|
||||
## Efficient hashing of strings; style is ignored.
|
||||
##
|
||||
## See also:
|
||||
## * `hashIgnoreCase <#hashIgnoreCase,string>`_
|
||||
runnableExamples:
|
||||
doAssert hashIgnoreStyle("aBr_aCa_dAB_ra") == hash("abracadabra")
|
||||
|
||||
var h: Hash = 0
|
||||
var i = 0
|
||||
let xLen = x.len
|
||||
@@ -176,11 +207,15 @@ proc hashIgnoreStyle*(x: string): Hash =
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos`; style is ignored
|
||||
## Efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos` (included); style is ignored.
|
||||
##
|
||||
## ``hashIgnoreStyle(myBuf, 0, myBuf.high)`` is equivalent
|
||||
## to ``hashIgnoreStyle(myBuf)``
|
||||
## to ``hashIgnoreStyle(myBuf)``.
|
||||
runnableExamples:
|
||||
var a = "ABracada_b_r_a"
|
||||
doAssert hashIgnoreStyle(a, 0, 3) == hashIgnoreStyle(a, 7, a.high)
|
||||
|
||||
var h: Hash = 0
|
||||
var i = sPos
|
||||
while i <= ePos:
|
||||
@@ -195,7 +230,13 @@ proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash =
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreCase*(x: string): Hash =
|
||||
## efficient hashing of strings; case is ignored
|
||||
## Efficient hashing of strings; case is ignored.
|
||||
##
|
||||
## See also:
|
||||
## * `hashIgnoreStyle <#hashIgnoreStyle,string>`_
|
||||
runnableExamples:
|
||||
doAssert hashIgnoreCase("ABRAcaDABRA") == hashIgnoreCase("abRACAdabra")
|
||||
|
||||
var h: Hash = 0
|
||||
for i in 0..x.len-1:
|
||||
var c = x[i]
|
||||
@@ -205,11 +246,15 @@ proc hashIgnoreCase*(x: string): Hash =
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos`; case is ignored
|
||||
## Efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos` (included); case is ignored.
|
||||
##
|
||||
## ``hashIgnoreCase(myBuf, 0, myBuf.high)`` is equivalent
|
||||
## to ``hashIgnoreCase(myBuf)``
|
||||
## to ``hashIgnoreCase(myBuf)``.
|
||||
runnableExamples:
|
||||
var a = "ABracadabRA"
|
||||
doAssert hashIgnoreCase(a, 0, 3) == hashIgnoreCase(a, 7, 10)
|
||||
|
||||
var h: Hash = 0
|
||||
for i in sPos..ePos:
|
||||
var c = sBuf[i]
|
||||
@@ -219,7 +264,7 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
|
||||
result = !$h
|
||||
|
||||
proc hash*(x: float): Hash {.inline.} =
|
||||
## efficient hashing of floats.
|
||||
## Efficient hashing of floats.
|
||||
var y = x + 1.0
|
||||
result = cast[ptr Hash](addr(y))[]
|
||||
|
||||
@@ -231,34 +276,40 @@ proc hash*[A](x: set[A]): Hash
|
||||
|
||||
|
||||
proc hash*[T: tuple](x: T): Hash =
|
||||
## efficient hashing of tuples.
|
||||
## Efficient hashing of tuples.
|
||||
for f in fields(x):
|
||||
result = result !& hash(f)
|
||||
result = !$result
|
||||
|
||||
proc hash*[A](x: openArray[A]): Hash =
|
||||
## efficient hashing of arrays and sequences.
|
||||
## Efficient hashing of arrays and sequences.
|
||||
for it in items(x): result = result !& hash(it)
|
||||
result = !$result
|
||||
|
||||
proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash =
|
||||
## efficient hashing of portions of arrays and sequences.
|
||||
## Efficient hashing of portions of arrays and sequences, from starting
|
||||
## position `sPos` to ending position `ePos` (included).
|
||||
##
|
||||
## ``hash(myBuf, 0, myBuf.high)`` is equivalent to ``hash(myBuf)``
|
||||
## ``hash(myBuf, 0, myBuf.high)`` is equivalent to ``hash(myBuf)``.
|
||||
runnableExamples:
|
||||
let a = [1, 2, 5, 1, 2, 6]
|
||||
doAssert hash(a, 0, 1) == hash(a, 3, 4)
|
||||
|
||||
for i in sPos..ePos:
|
||||
result = result !& hash(aBuf[i])
|
||||
result = !$result
|
||||
|
||||
proc hash*[A](x: set[A]): Hash =
|
||||
## efficient hashing of sets.
|
||||
## Efficient hashing of sets.
|
||||
for it in items(x): result = result !& hash(it)
|
||||
result = !$result
|
||||
|
||||
|
||||
when isMainModule:
|
||||
doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) )
|
||||
doAssert( hash("aa bb aaaa1234") == hash(cstring("aa bb aaaa1234")) )
|
||||
doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") )
|
||||
doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") )
|
||||
doAssert( hashIgnoreCase("aA bb aAAa1234") == hash("aa bb aaaa1234") )
|
||||
doAssert( hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234") )
|
||||
let xx = @['H','e','l','l','o']
|
||||
let ss = "Hello"
|
||||
doAssert( hash(xx) == hash(ss) )
|
||||
|
||||
107
lib/pure/md5.nim
107
lib/pure/md5.nim
@@ -7,13 +7,20 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Module for computing MD5 checksums.
|
||||
## Module for computing `MD5 checksums <https://en.wikipedia.org/wiki/MD5>`_.
|
||||
##
|
||||
## **See also:**
|
||||
## * `base64 module<base64.html>`_ implements a base64 encoder and decoder
|
||||
## * `std/sha1 module <sha1.html>`_ for a sha1 encoder and decoder
|
||||
## * `hashes module<hashes.html>`_ for efficient computations of hash values
|
||||
## for diverse Nim types
|
||||
|
||||
type
|
||||
MD5State = array[0..3, uint32]
|
||||
MD5Block = array[0..15, uint32]
|
||||
MD5CBits = array[0..7, uint8]
|
||||
MD5Digest* = array[0..15, uint8]
|
||||
MD5Digest* = array[0..15, uint8] ## \
|
||||
## MD5 checksum of a string, obtained with `toMD5 proc <#toMD5,string>`_.
|
||||
MD5Buffer = array[0..63, uint8]
|
||||
MD5Context* {.final.} = object
|
||||
state: MD5State
|
||||
@@ -161,8 +168,62 @@ proc transform(buffer: pointer, state: var MD5State) =
|
||||
state[2] = state[2] + c
|
||||
state[3] = state[3] + d
|
||||
|
||||
proc md5Init*(c: var MD5Context) {.raises: [], tags: [].}
|
||||
proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [], tags: [].}
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [].}
|
||||
|
||||
|
||||
proc toMD5*(s: string): MD5Digest =
|
||||
## Computes the `MD5Digest` value for a string `s`.
|
||||
##
|
||||
## See also:
|
||||
## * `getMD5 proc <#getMD5,string>`_ which returns a string representation
|
||||
## of the `MD5Digest`
|
||||
## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string
|
||||
runnableExamples:
|
||||
assert $toMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
md5Update(c, cstring(s), len(s))
|
||||
md5Final(c, result)
|
||||
|
||||
proc `$`*(d: MD5Digest): string =
|
||||
## Converts a `MD5Digest` value into its string representation.
|
||||
const digits = "0123456789abcdef"
|
||||
result = ""
|
||||
for i in 0..15:
|
||||
add(result, digits[(d[i].int shr 4) and 0xF])
|
||||
add(result, digits[d[i].int and 0xF])
|
||||
|
||||
proc getMD5*(s: string): string =
|
||||
## Computes an MD5 value of `s` and returns its string representation.
|
||||
##
|
||||
## See also:
|
||||
## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string
|
||||
runnableExamples:
|
||||
assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var
|
||||
c: MD5Context
|
||||
d: MD5Digest
|
||||
md5Init(c)
|
||||
md5Update(c, cstring(s), len(s))
|
||||
md5Final(c, d)
|
||||
result = $d
|
||||
|
||||
proc `==`*(D1, D2: MD5Digest): bool =
|
||||
## Checks if two `MD5Digest` values are identical.
|
||||
for i in 0..15:
|
||||
if D1[i] != D2[i]: return false
|
||||
return true
|
||||
|
||||
|
||||
proc md5Init*(c: var MD5Context) =
|
||||
## initializes a MD5Context
|
||||
## Initializes a `MD5Context`.
|
||||
##
|
||||
## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this
|
||||
## function explicitly.
|
||||
c.state[0] = 0x67452301'u32
|
||||
c.state[1] = 0xEFCDAB89'u32
|
||||
c.state[2] = 0x98BADCFE'u32
|
||||
@@ -172,7 +233,10 @@ proc md5Init*(c: var MD5Context) =
|
||||
zeroMem(addr(c.buffer), sizeof(MD5buffer))
|
||||
|
||||
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
|
||||
## updates the MD5Context with the `input` data of length `len`
|
||||
## Updates the `MD5Context` with the `input` data of length `len`.
|
||||
##
|
||||
## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this
|
||||
## function explicitly.
|
||||
var input = input
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
c.count[0] = c.count[0] + (uint32(len) shl 3)
|
||||
@@ -191,7 +255,10 @@ proc md5Update*(c: var MD5Context, input: cstring, len: int) =
|
||||
copyMem(addr(c.buffer[Index]), addr(input[0]), len)
|
||||
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
## finishes the MD5Context and stores the result in `digest`
|
||||
## Finishes the `MD5Context` and stores the result in `digest`.
|
||||
##
|
||||
## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this
|
||||
## function explicitly.
|
||||
var
|
||||
Bits: MD5CBits
|
||||
PadLen: int
|
||||
@@ -204,36 +271,6 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
decode(digest, c.state)
|
||||
zeroMem(addr(c), sizeof(MD5Context))
|
||||
|
||||
proc toMD5*(s: string): MD5Digest =
|
||||
## computes the MD5Digest value for a string `s`
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
md5Update(c, cstring(s), len(s))
|
||||
md5Final(c, result)
|
||||
|
||||
proc `$`*(d: MD5Digest): string =
|
||||
## converts a MD5Digest value into its string representation
|
||||
const digits = "0123456789abcdef"
|
||||
result = ""
|
||||
for i in 0..15:
|
||||
add(result, digits[(d[i].int shr 4) and 0xF])
|
||||
add(result, digits[d[i].int and 0xF])
|
||||
|
||||
proc getMD5*(s: string): string =
|
||||
## computes an MD5 value of `s` and returns its string representation
|
||||
var
|
||||
c: MD5Context
|
||||
d: MD5Digest
|
||||
md5Init(c)
|
||||
md5Update(c, cstring(s), len(s))
|
||||
md5Final(c, d)
|
||||
result = $d
|
||||
|
||||
proc `==`*(D1, D2: MD5Digest): bool =
|
||||
## checks if two MD5Digest values are identical
|
||||
for i in 0..15:
|
||||
if D1[i] != D2[i]: return false
|
||||
return true
|
||||
|
||||
when isMainModule:
|
||||
assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
## This module defines compile-time reflection procs for
|
||||
## working with types
|
||||
## working with types.
|
||||
|
||||
include "system/helpers" # for `isNamedTuple`
|
||||
|
||||
@@ -16,11 +16,13 @@ export system.`$`
|
||||
export isNamedTuple
|
||||
|
||||
proc name*(t: typedesc): string {.magic: "TypeTrait".}
|
||||
## Alias for system.`$`(t) since Nim v0.20.0.
|
||||
## Returns the name of the given type.
|
||||
##
|
||||
## Alias for system.`$`(t) since Nim v0.20.
|
||||
|
||||
proc arity*(t: typedesc): int {.magic: "TypeTrait".} =
|
||||
## Returns the arity of the given type. This is the number of "type" components or
|
||||
## the number of generic parameters a given type ``t`` has.
|
||||
## Returns the arity of the given type. This is the number of "type"
|
||||
## components or the number of generic parameters a given type ``t`` has.
|
||||
runnableExamples:
|
||||
assert arity(seq[string]) == 1
|
||||
assert arity(array[3, int]) == 2
|
||||
@@ -31,19 +33,35 @@ proc genericHead*(t: typedesc): typedesc {.magic: "TypeTrait".}
|
||||
## uninstantiated form.
|
||||
##
|
||||
## For example:
|
||||
## seq[int].genericHead will be just seq
|
||||
## seq[int].genericHead[float] will be seq[float]
|
||||
## * `seq[int].genericHead` will be just `seq`
|
||||
## * `seq[int].genericHead[float]` will be `seq[float]`
|
||||
##
|
||||
## A compile-time error will be produced if the supplied type
|
||||
## is not generic.
|
||||
##
|
||||
## See also:
|
||||
## * `stripGenericParams <#stripGenericParams,typedesc>`_
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## type
|
||||
## Functor[A] = concept f
|
||||
## type MatchedGenericType = genericHead(f.type)
|
||||
## # `f` will be a value of a type such as `Option[T]`
|
||||
## # `MatchedGenericType` will become the `Option` type
|
||||
|
||||
|
||||
proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".}
|
||||
## This trait is similar to `genericHead`, but instead of producing
|
||||
## error for non-generic types, it will just return them unmodified.
|
||||
## This trait is similar to `genericHead <#genericHead,typedesc>`_, but
|
||||
## instead of producing error for non-generic types, it will just return
|
||||
## them unmodified.
|
||||
|
||||
proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".}
|
||||
## This trait returns true iff the type ``t`` is safe to use for
|
||||
## `copyMem`:idx:. Other languages name a type like these `blob`:idx:.
|
||||
## `copyMem`:idx:.
|
||||
##
|
||||
## Other languages name a type like these `blob`:idx:.
|
||||
|
||||
|
||||
when isMainModule:
|
||||
|
||||
@@ -178,7 +178,7 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
|
||||
copyMem(dest, src, mt.size) # copy raw bits
|
||||
|
||||
proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
|
||||
## adds an `item` to the end of the queue `q`.
|
||||
## Adds an `item` to the end of the queue `q`.
|
||||
var cap = q.mask+1
|
||||
if q.count >= cap:
|
||||
# start with capacity for 2 entries in the queue:
|
||||
@@ -232,11 +232,14 @@ proc sendImpl(q: PRawChannel, typ: PNimType, msg: pointer, noBlock: bool): bool
|
||||
result = true
|
||||
|
||||
proc send*[TMsg](c: var Channel[TMsg], msg: TMsg) {.inline.} =
|
||||
## sends a message to a thread. `msg` is deeply copied.
|
||||
## Sends a message to a thread. `msg` is deeply copied.
|
||||
discard sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), false)
|
||||
|
||||
proc trySend*[TMsg](c: var Channel[TMsg], msg: TMsg): bool {.inline.} =
|
||||
## Tries to send a message to a thread. `msg` is deeply copied. Doesn't block.
|
||||
## Tries to send a message to a thread.
|
||||
##
|
||||
## `msg` is deeply copied. Doesn't block.
|
||||
##
|
||||
## Returns `false` if the message was not sent because number of pending items
|
||||
## in the channel exceeded `maxItems`.
|
||||
sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), true)
|
||||
@@ -255,8 +258,10 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
|
||||
signalSysCond(q.cond)
|
||||
|
||||
proc recv*[TMsg](c: var Channel[TMsg]): TMsg =
|
||||
## receives a message from the channel `c`. This blocks until
|
||||
## a message has arrived! You may use ``peek`` to avoid the blocking.
|
||||
## Receives a message from the channel `c`.
|
||||
##
|
||||
## This blocks until a message has arrived!
|
||||
## You may use `peek proc <#peek,Channel[TMsg]>`_ to avoid the blocking.
|
||||
var q = cast[PRawChannel](addr(c))
|
||||
acquireSys(q.lock)
|
||||
llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))
|
||||
@@ -265,8 +270,9 @@ proc recv*[TMsg](c: var Channel[TMsg]): TMsg =
|
||||
proc tryRecv*[TMsg](c: var Channel[TMsg]): tuple[dataAvailable: bool,
|
||||
msg: TMsg] =
|
||||
## Tries to receive a message from the channel `c`, but this can fail
|
||||
## for all sort of reasons, including contention. If it fails,
|
||||
## it returns ``(false, default(msg))`` otherwise it
|
||||
## for all sort of reasons, including contention.
|
||||
##
|
||||
## If it fails, it returns ``(false, default(msg))`` otherwise it
|
||||
## returns ``(true, msg)``.
|
||||
var q = cast[PRawChannel](addr(c))
|
||||
if q.mask != ChannelDeadMask:
|
||||
@@ -277,9 +283,12 @@ proc tryRecv*[TMsg](c: var Channel[TMsg]): tuple[dataAvailable: bool,
|
||||
releaseSys(q.lock)
|
||||
|
||||
proc peek*[TMsg](c: var Channel[TMsg]): int =
|
||||
## returns the current number of messages in the channel `c`. Returns -1
|
||||
## if the channel has been closed. **Note**: This is dangerous to use
|
||||
## as it encourages races. It's much better to use ``tryRecv`` instead.
|
||||
## Returns the current number of messages in the channel `c`.
|
||||
##
|
||||
## Returns -1 if the channel has been closed.
|
||||
##
|
||||
## **Note**: This is dangerous to use as it encourages races.
|
||||
## It's much better to use `tryRecv proc <#tryRecv,Channel[TMsg]>`_ instead.
|
||||
var q = cast[PRawChannel](addr(c))
|
||||
if q.mask != ChannelDeadMask:
|
||||
lockChannel(q):
|
||||
@@ -288,17 +297,20 @@ proc peek*[TMsg](c: var Channel[TMsg]): int =
|
||||
result = -1
|
||||
|
||||
proc open*[TMsg](c: var Channel[TMsg], maxItems: int = 0) =
|
||||
## opens a channel `c` for inter thread communication. The `send` operation
|
||||
## will block until number of unprocessed items is less than `maxItems`.
|
||||
## Opens a channel `c` for inter thread communication.
|
||||
##
|
||||
## The `send` operation will block until number of unprocessed items is
|
||||
## less than `maxItems`.
|
||||
##
|
||||
## For unlimited queue set `maxItems` to 0.
|
||||
initRawChannel(addr(c), maxItems)
|
||||
|
||||
proc close*[TMsg](c: var Channel[TMsg]) =
|
||||
## closes a channel `c` and frees its associated resources.
|
||||
## Closes a channel `c` and frees its associated resources.
|
||||
deinitRawChannel(addr(c))
|
||||
|
||||
proc ready*[TMsg](c: var Channel[TMsg]): bool =
|
||||
## returns true iff some thread is waiting on the channel `c` for
|
||||
## Returns true iff some thread is waiting on the channel `c` for
|
||||
## new messages.
|
||||
var q = cast[PRawChannel](addr(c))
|
||||
result = q.ready
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
# 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
|
||||
## 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
|
||||
@@ -381,6 +383,7 @@ var
|
||||
proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) =
|
||||
## Registers a *thread local* handler that is called at the thread's
|
||||
## destruction.
|
||||
##
|
||||
## A thread is destructed when the ``.thread`` proc returns
|
||||
## normally or when it raises an exception. Note that unhandled exceptions
|
||||
## in a thread nevertheless cause the whole process to die.
|
||||
@@ -481,22 +484,22 @@ else:
|
||||
{.pop.}
|
||||
|
||||
proc running*[TArg](t: Thread[TArg]): bool {.inline.} =
|
||||
## returns true if `t` is running.
|
||||
## Returns true if `t` is running.
|
||||
result = t.dataFn != nil
|
||||
|
||||
proc handle*[TArg](t: Thread[TArg]): SysThread {.inline.} =
|
||||
## returns the thread handle of `t`.
|
||||
## Returns the thread handle of `t`.
|
||||
result = t.sys
|
||||
|
||||
when hostOS == "windows":
|
||||
const MAXIMUM_WAIT_OBJECTS = 64
|
||||
|
||||
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
|
||||
## waits for the thread `t` to finish.
|
||||
## 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.
|
||||
## Waits for every thread in `t` to finish.
|
||||
var a: array[MAXIMUM_WAIT_OBJECTS, SysThread]
|
||||
var k = 0
|
||||
while k < len(t):
|
||||
@@ -508,25 +511,25 @@ when hostOS == "windows":
|
||||
|
||||
elif defined(genode):
|
||||
proc joinThread*[TArg](t: Thread[TArg]) {.importcpp.}
|
||||
## waits for the thread `t` to finish.
|
||||
## Waits for the thread `t` to finish.
|
||||
|
||||
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
|
||||
## waits for every thread in `t` to finish.
|
||||
## Waits for every thread in `t` to finish.
|
||||
for i in 0..t.high: joinThread(t[i])
|
||||
|
||||
else:
|
||||
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
|
||||
## waits for the thread `t` to finish.
|
||||
## 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.
|
||||
## 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
|
||||
## 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)
|
||||
@@ -543,8 +546,10 @@ 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
|
||||
## 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.
|
||||
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
|
||||
|
||||
@@ -558,14 +563,15 @@ when hostOS == "windows":
|
||||
raise newException(ResourceExhaustedError, "cannot create thread")
|
||||
|
||||
proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) =
|
||||
## pins a thread to a `CPU`:idx:. In other words sets a
|
||||
## thread's `affinity`:idx:. If you don't know what this means, you
|
||||
## shouldn't use this proc.
|
||||
## Pins a thread to a `CPU`:idx:.
|
||||
##
|
||||
## In other words sets a thread's `affinity`:idx:.
|
||||
## If you don't know what this means, you shouldn't use this proc.
|
||||
setThreadAffinityMask(t.sys, uint(1 shl cpu))
|
||||
|
||||
elif defined(genode):
|
||||
var affinityOffset: cuint = 1
|
||||
## CPU affinity offset for next thread, safe to roll-over
|
||||
## CPU affinity offset for next thread, safe to roll-over.
|
||||
|
||||
proc createThread*[TArg](t: var Thread[TArg],
|
||||
tp: proc (arg: TArg) {.thread, nimcall.},
|
||||
@@ -589,8 +595,10 @@ else:
|
||||
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
|
||||
## 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.
|
||||
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
|
||||
|
||||
@@ -604,9 +612,10 @@ else:
|
||||
raise newException(ResourceExhaustedError, "cannot create thread")
|
||||
|
||||
proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) =
|
||||
## pins a thread to a `CPU`:idx:. In other words sets a
|
||||
## thread's `affinity`:idx:. If you don't know what this means, you
|
||||
## shouldn't use this proc.
|
||||
## Pins a thread to a `CPU`:idx:.
|
||||
##
|
||||
## In other words sets a thread's `affinity`:idx:.
|
||||
## If you don't know what this means, you shouldn't use this proc.
|
||||
when not defined(macosx):
|
||||
var s {.noinit.}: CpuSet
|
||||
cpusetZero(s)
|
||||
@@ -618,7 +627,7 @@ proc createThread*(t: var Thread[void], tp: proc () {.thread, nimcall.}) =
|
||||
|
||||
when false:
|
||||
proc mainThreadId*[TArg](): ThreadId[TArg] =
|
||||
## returns the thread ID of the main thread.
|
||||
## Returns the thread ID of the main thread.
|
||||
result = cast[ThreadId[TArg]](addr(mainThread))
|
||||
|
||||
when useStackMaskHack:
|
||||
@@ -632,7 +641,7 @@ var threadId {.threadvar.}: int
|
||||
|
||||
when defined(windows):
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
if threadId == 0:
|
||||
threadId = int(getCurrentThreadId())
|
||||
result = threadId
|
||||
@@ -645,7 +654,7 @@ elif defined(linux):
|
||||
var NR_gettid {.importc: "__NR_gettid", header: "<sys/syscall.h>".}: clong
|
||||
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
if threadId == 0:
|
||||
threadId = int(syscall(NR_gettid))
|
||||
result = threadId
|
||||
@@ -654,7 +663,7 @@ elif defined(dragonfly):
|
||||
proc lwp_gettid(): int32 {.importc, header: "unistd.h".}
|
||||
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
if threadId == 0:
|
||||
threadId = int(lwp_gettid())
|
||||
result = threadId
|
||||
@@ -672,7 +681,7 @@ elif defined(netbsd):
|
||||
proc lwp_self(): int32 {.importc: "_lwp_self", header: "<lwp.h>".}
|
||||
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
if threadId == 0:
|
||||
threadId = int(lwp_self())
|
||||
result = threadId
|
||||
@@ -682,7 +691,7 @@ elif defined(freebsd):
|
||||
var SYS_thr_self {.importc:"SYS_thr_self", header:"<sys/syscall.h>"}: cint
|
||||
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
var tid = 0.cint
|
||||
if threadId == 0:
|
||||
discard syscall(SYS_thr_self, addr tid)
|
||||
@@ -694,7 +703,7 @@ elif defined(macosx):
|
||||
var SYS_thread_selfid {.importc:"SYS_thread_selfid", header:"<sys/syscall.h>".}: cint
|
||||
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
if threadId == 0:
|
||||
threadId = int(syscall(SYS_thread_selfid))
|
||||
result = threadId
|
||||
@@ -704,7 +713,7 @@ elif defined(solaris):
|
||||
proc thr_self(): thread_t {.importc, header: "<thread.h>".}
|
||||
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
if threadId == 0:
|
||||
threadId = int(thr_self())
|
||||
result = threadId
|
||||
@@ -714,7 +723,7 @@ elif defined(haiku):
|
||||
proc find_thread(name: cstring): thr_id {.importc, header: "<OS.h>".}
|
||||
|
||||
proc getThreadId*(): int =
|
||||
## get the ID of the currently running thread.
|
||||
## Gets the ID of the currently running thread.
|
||||
if threadId == 0:
|
||||
threadId = int(find_thread(nil))
|
||||
result = threadId
|
||||
|
||||
Reference in New Issue
Block a user