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:
Miran
2019-03-01 12:57:55 +01:00
committed by GitHub
parent e9d3c5de19
commit ca7980f301
6 changed files with 325 additions and 177 deletions

View File

@@ -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

View File

@@ -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