diff options
Diffstat (limited to 'lib')
-rwxr-xr-x[-rw-r--r--] | lib/core/typeinfo.nim | 16 | ||||
-rwxr-xr-x | lib/impure/re.nim | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/prelude.nim | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/pure/collections/intsets.nim | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/pure/collections/queues.nim | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/pure/collections/sets.nim | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/pure/collections/tables.nim | 8 | ||||
-rwxr-xr-x | lib/pure/osproc.nim | 10 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/pure/redis.nim | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/pure/romans.nim | 0 | ||||
-rwxr-xr-x | lib/pure/smtp.nim | 1 | ||||
-rwxr-xr-x | lib/system.nim | 2 | ||||
-rwxr-xr-x | lib/system/alloc.nim | 9 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/system/atomics.nim | 3 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/system/inboxes.nim | 36 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/system/syslocks.nim | 2 | ||||
-rwxr-xr-x | lib/system/threads.nim | 161 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/wrappers/sphinx.nim | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/wrappers/zmq.nim | 27 |
19 files changed, 181 insertions, 106 deletions
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 3434cd9d4..32042695d 100644..100755 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -45,8 +45,8 @@ type TAny* = object {.pure.} ## can represent any nimrod value; NOTE: the wrapped ## value can be modified with its wrapper! This means ## that ``TAny`` keeps a non-traced pointer to its - ## wrapped value and MUST not live longer than its - ## wrapped value. + ## wrapped value and **must not** live longer than + ## its wrapped value. value: pointer rawType: PNimType @@ -97,7 +97,7 @@ proc newAny(value: pointer, rawType: PNimType): TAny = proc toAny*[T](x: var T): TAny {.inline.} = ## constructs a ``TAny`` object from `x`. This captures `x`'s address, so ## `x` can be modified with its ``TAny`` wrapper! The client needs to ensure - ## that the wrapper DOES NOT live longer than `x`! + ## that the wrapper **does not** live longer than `x`! result.value = addr(x) result.rawType = cast[PNimType](getTypeInfo(x)) @@ -106,7 +106,7 @@ proc kind*(x: TAny): TAnyKind {.inline.} = result = TAnyKind(ord(x.rawType.kind)) proc baseTypeKind*(x: TAny): TAnyKind {.inline.} = - ## get the base type's kind; akNone is returned if `x` has no base type. + ## get the base type's kind; ``akNone`` is returned if `x` has no base type. if x.rawType.base != nil: result = TAnyKind(ord(x.rawType.base.kind)) @@ -586,13 +586,13 @@ when isMainModule: block: # gimme a new scope dammit - var myarr: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + var myarr: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]] var m = toAny(myArr) for i in 0 .. m.len-1: for j in 0 .. m[i].len-1: echo getString(m[i][j]) - + diff --git a/lib/impure/re.nim b/lib/impure/re.nim index eaa712f01..635fab0db 100755 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -287,7 +287,7 @@ proc replacef*(s: string, sub: TRegEx, by: string): string = ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## ## .. code-block:: nimrod - ## "var1=key; var2=key2".replace(re"(\w+)'='(\w+)", "$1<-$2$2") + ## "var1=key; var2=key2".replacef(re"(\w+)'='(\w+)", "$1<-$2$2") ## ## Results in: ## diff --git a/lib/prelude.nim b/lib/prelude.nim index cdd241581..cdd241581 100644..100755 --- a/lib/prelude.nim +++ b/lib/prelude.nim diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index bbe6a674b..3fd81acf6 100644..100755 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -9,8 +9,8 @@ ## The ``intsets`` module implements an efficient int set implemented as a ## sparse bit set. -## **Note**: Since Nimrod does not allow the assignment operator to be -## overloaded, ``=`` for int sets performs some rather meaningless shallow +## **Note**: Since Nimrod currently does not allow the assignment operator to +## be overloaded, ``=`` for int sets performs some rather meaningless shallow ## copy. import diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim index 2130d9949..2130d9949 100644..100755 --- a/lib/pure/collections/queues.nim +++ b/lib/pure/collections/queues.nim diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index a577964c9..00056ff14 100644..100755 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -9,9 +9,9 @@ ## The ``sets`` module implements an efficient hash set and ordered hash set. ## -## Note: The data types declared here have *value semantics*: This means that -## ``=`` performs a copy of the hash table. If you are overly concerned with -## efficiency and know what you do (!), you can define the symbol +## **Note**: The data types declared here have *value semantics*: This means +## that ``=`` performs a copy of the hash table. If you are overly concerned +## with efficiency and know what you do (!), you can define the symbol ## ``shallowADT`` to compile a version that uses shallow copies instead. import diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index d353db3fb..6fe77b26f 100644..100755 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -10,9 +10,9 @@ ## The ``tables`` module implements an efficient hash table that is ## a mapping from keys to values. ## -## Note: The data types declared here have *value semantics*: This means that -## ``=`` performs a copy of the hash table. If you are overly concerned with -## efficiency and know what you do (!), you can define the symbol +## **Note:** The data types declared here have *value semantics*: This means +## that ``=`` performs a copy of the hash table. If you are overly concerned +## with efficiency and know what you do (!), you can define the symbol ## ``shallowADT`` to compile a version that uses shallow copies instead. import @@ -27,7 +27,7 @@ type TSlotEnum = enum seEmpty, seFilled, seDeleted TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] - TTable* {.final, myShallow.}[A, B] = object + TTable* {.final, myShallow.}[A, B] = object ## generic hash table data: TKeyValuePairSeq[A, B] counter: int diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 2b7047143..281615881 100755 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -366,10 +366,12 @@ when defined(Windows) and not defined(useNimRtl): result.id = procInfo.dwProcessID proc close(p: PProcess) = - discard CloseHandle(p.inputHandle) - discard CloseHandle(p.outputHandle) - discard CloseHandle(p.errorHandle) - discard CloseHandle(p.FProcessHandle) + when false: + # somehow this does not work on Windows: + discard CloseHandle(p.inputHandle) + discard CloseHandle(p.outputHandle) + discard CloseHandle(p.errorHandle) + discard CloseHandle(p.FProcessHandle) proc suspend(p: PProcess) = discard SuspendThread(p.FProcessHandle) diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim index 434378b04..434378b04 100644..100755 --- a/lib/pure/redis.nim +++ b/lib/pure/redis.nim diff --git a/lib/pure/romans.nim b/lib/pure/romans.nim index dee3226d8..dee3226d8 100644..100755 --- a/lib/pure/romans.nim +++ b/lib/pure/romans.nim diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 21afdf953..bddcdfb04 100755 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -168,6 +168,7 @@ proc createMessage*(mSubject, mBody: string, mTo, result.msgOtherHeaders = newStringTable() proc `$`*(msg: TMessage): string = + ## stringify for ``TMessage``. result = "" if msg.msgTo.len() > 0: result = "TO: " & msg.msgTo.join(", ") & "\c\L" diff --git a/lib/system.nim b/lib/system.nim index 6f20a9b4d..b6a119ddd 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1456,7 +1456,7 @@ else: `x`[0][len] = 0 """ -proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo".} +proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo", noSideEffect.} ## special built-in that takes a variable number of arguments. Each argument ## is converted to a string via ``$``, so it works for user-defined ## types that have an overloaded ``$`` operator. diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 8a54e0ddd..efa372bcd 100755 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -65,9 +65,12 @@ elif defined(windows): PAGE_READWRITE) if result == nil: raiseOutOfMem() - proc osDeallocPages(p: pointer, size: int) {.inline.} = - # according to Microsoft, 0 is the only correct value here: - when reallyOsDealloc: VirtualFree(p, 0, MEM_RELEASE) + proc osDeallocPages(p: pointer, size: int) {.inline.} = + # according to Microsoft, 0 is the only correct value for MEM_RELEASE: + # This means that the OS has some different view over how big the block is + # that we want to free! So, we cannot reliably release the memory back to + # Windows :-(. We have to live with MEM_DECOMMIT instead. + when reallyOsDealloc: VirtualFree(p, size, MEM_DECOMMIT) else: {.error: "Port memory manager to your platform".} diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index 64f8e03e0..371168094 100644..100755 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -9,7 +9,8 @@ ## Atomic operations for Nimrod. -when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport: +when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport and + not defined(windows): proc sync_add_and_fetch(p: var int, val: int): int {. importc: "__sync_add_and_fetch", nodecl.} proc sync_sub_and_fetch(p: var int, val: int): int {. diff --git a/lib/system/inboxes.nim b/lib/system/inboxes.nim index 1f5d56c16..7b522c7ae 100644..100755 --- a/lib/system/inboxes.nim +++ b/lib/system/inboxes.nim @@ -7,8 +7,12 @@ # distribution, for details about the copyright. # -## Message passing for threads. The current implementation is slow and does -## not work with cyclic data structures. But hey, it's better than nothing. +## Message passing for threads. **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. +## +## **Note:** The current implementation of message passing is slow and does +## not work with cyclic data structures. type pbytes = ptr array[0.. 0xffff, byte] @@ -18,6 +22,7 @@ type lock: TSysLock cond: TSysCond elemType: PNimType + ready: bool region: TMemRegion PInbox = ptr TInbox TLoadStoreMode = enum mStore, mLoad @@ -178,9 +183,7 @@ template lockInbox(q: expr, action: stmt) = action releaseSys(q.lock) -proc send*[TMsg](receiver: var TThread[TMsg], msg: TMsg) = - ## sends a message to a thread. `msg` is deeply copied. - var q = cast[PInbox](getInBoxMem(receiver)) +template sendImpl(q: expr) = if q.mask == ThreadDeadMask: raise newException(EDeadThread, "cannot send message; thread died") acquireSys(q.lock) @@ -192,12 +195,24 @@ proc send*[TMsg](receiver: var TThread[TMsg], msg: TMsg) = releaseSys(q.lock) SignalSysCond(q.cond) +proc send*[TMsg](receiver: var TThread[TMsg], msg: TMsg) = + ## sends a message to a thread. `msg` is deeply copied. + var q = cast[PInbox](getInBoxMem(receiver)) + sendImpl(q) + +proc send*[TMsg](receiver: TThreadId[TMsg], msg: TMsg) = + ## sends a message to a thread. `msg` is deeply copied. + var q = cast[PInbox](getInBoxMem(receiver[])) + sendImpl(q) + proc llRecv(res: pointer, typ: PNimType) = # to save space, the generic is as small as possible var q = cast[PInbox](getInBoxMem()) acquireSys(q.lock) + q.ready = true while q.count <= 0: WaitSysCond(q.cond, q.lock) + q.ready = false if typ != q.elemType: releaseSys(q.lock) raise newException(EInvalidValue, "cannot receive message of wrong type") @@ -215,4 +230,15 @@ proc peek*(): int = lockInbox(q): result = q.count +proc peek*[TMsg](t: var TThread[TMsg]): int = + ## returns the current number of messages in the inbox of thread `t`. + var q = cast[PInbox](getInBoxMem(t)) + if q.mask != ThreadDeadMask: + lockInbox(q): + result = q.count + +proc ready*[TMsg](t: var TThread[TMsg]): bool = + ## returns true iff the thread `t` is waiting on ``recv`` for new messages. + var q = cast[PInbox](getInBoxMem(t)) + result = q.ready diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index c91e83dcd..17327bb59 100644..100755 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -47,7 +47,7 @@ when defined(Windows): proc CreateEvent(lpEventAttributes: pointer, bManualReset, bInitialState: int32, lpName: cstring): TSysCond {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "CreateEvent".} + dynlib: "kernel32", importc: "CreateEventA".} proc CloseHandle(hObject: THandle) {.stdcall, noSideEffect, dynlib: "kernel32", importc: "CloseHandle".} diff --git a/lib/system/threads.nim b/lib/system/threads.nim index bd361760d..0e6c8ce82 100755 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -8,7 +8,7 @@ # ## Thread support for Nimrod. **Note**: This is part of the system module. -## Do not import it directly. To active thread support you need to compile +## Do not import it directly. To activate thread support you need to compile ## with the ``--threads:on`` command line switch. ## ## Nimrod's memory model for threads is quite different from other common @@ -39,8 +39,8 @@ const maxRegisters = 256 # don't think there is an arch with more registers - maxLocksPerThread* = 10 ## max number of locks a thread can hold - ## at the same time + maxLocksPerThread = 10 ## max number of locks a thread can hold + ## at the same time useStackMaskHack = false ## use the stack mask hack for better performance StackGuardSize = 4096 ThreadStackMask = 1024*256*sizeof(int)-1 @@ -167,14 +167,17 @@ type PGcThread = ptr TGcThread TGcThread {.pure.} = object sys: TSysThread - next, prev: PGcThread - stackBottom, stackTop: pointer - stackSize: int inbox: TThreadLocalStorage when emulatedThreadVars and not useStackMaskHack: tls: TThreadLocalStorage else: nil + when hasSharedHeap: + next, prev: PGcThread + stackBottom, stackTop: pointer + stackSize: int + else: + nil # 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 0 @@ -201,44 +204,45 @@ when not defined(useNimRtl): ThreadVarSetValue(globalsSlot, addr(mainThread)) initStackBottom() initGC() - - var heapLock: TSysLock - InitSysLock(HeapLock) when emulatedThreadVars: if NimThreadVarsSize() > sizeof(TThreadLocalStorage): echo "too large thread local storage size requested" quit 1 - - 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 = 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) + when hasSharedHeap: + var heapLock: TSysLock + InitSysLock(HeapLock) + + 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 = t + threadList = t + ReleaseSys(HeapLock) - # on UNIX, the GC uses ``SIGFREEZE`` to tell every thread to stop so that - # the GC can examine the stacks? - proc stopTheWord() = nil + 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() = nil # We jump through some hops here to ensure that Nimrod thread procs can have # the Nimrod calling convention. This is needed because thread procs are @@ -248,10 +252,15 @@ when not defined(useNimRtl): # GC'ed closures in Nimrod. type - TThread* {.pure, final.}[TParam] = object of TGcThread ## Nimrod thread. + TThread* {.pure, final.}[TMsg] = + object of TGcThread ## Nimrod thread. A thread is a heavy object (~14K) + ## that should not be part of a message! Use + ## a ``TThreadId`` for that. emptyFn: proc () - dataFn: proc (p: TParam) - data: TParam + dataFn: proc (p: TMsg) + data: TMsg + TThreadId*[TMsg] = ptr TThread[TMsg] ## the current implementation uses + ## a pointer as a thread ID. proc initInbox(p: pointer) proc freeInbox(p: pointer) @@ -260,47 +269,47 @@ when not defined(boehmgc) and not hasSharedHeap: template ThreadProcWrapperBody(closure: expr) = ThreadVarSetValue(globalsSlot, closure) - var t = cast[ptr TThread[TParam]](closure) + var t = cast[ptr TThread[TMsg]](closure) when useStackMaskHack: var tls: TThreadLocalStorage when not defined(boehmgc) and not hasSharedHeap: # init the GC for this thread: setStackBottom(addr(t)) initGC() - t.stackBottom = addr(t) - registerThread(t) - try: - when false: - var a = addr(tls) - var b = MaskStackPointer(1293920-372736-303104-36864) - c_fprintf(c_stdout, "TLS: %p\nmasked: %p\ndiff: %ld\n", - a, b, cast[int](a) - cast[int](b)) - if t.emptyFn == nil: t.dataFn(t.data) - else: t.emptyFn() - finally: - # XXX shut-down is not executed when the thread is forced down! - freeInbox(addr(t.inbox)) - unregisterThread(t) - when defined(deallocOsPages): deallocOsPages() + when hasSharedHeap: + t.stackBottom = addr(t) + registerThread(t) + if t.emptyFn == nil: t.dataFn(t.data) + else: t.emptyFn() + #finally: + # XXX shut-down is not executed when the thread is forced down! + freeInbox(addr(t.inbox)) + when hasSharedHeap: unregisterThread(t) + when defined(deallocOsPages): deallocOsPages() + # 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! {.push stack_trace:off.} when defined(windows): - proc threadProcWrapper[TParam](closure: pointer): int32 {.stdcall.} = + proc threadProcWrapper[TMsg](closure: pointer): int32 {.stdcall.} = ThreadProcWrapperBody(closure) # implicitely return 0 else: - proc threadProcWrapper[TParam](closure: pointer) {.noconv.} = + proc threadProcWrapper[TMsg](closure: pointer) {.noconv.} = ThreadProcWrapperBody(closure) {.pop.} -proc joinThread*[TParam](t: TThread[TParam]) {.inline.} = +proc joinThread*[TMsg](t: TThread[TMsg]) {.inline.} = ## waits for the thread `t` to finish. when hostOS == "windows": discard WaitForSingleObject(t.sys, -1'i32) else: discard pthread_join(t.sys, nil) -proc joinThreads*[TParam](t: openArray[TThread[TParam]]) = +proc joinThreads*[TMsg](t: openArray[TThread[TMsg]]) = ## waits for every thread in `t` to finish. when hostOS == "windows": var a: array[0..255, TSysThread] @@ -312,7 +321,7 @@ proc joinThreads*[TParam](t: openArray[TThread[TParam]]) = when false: # XXX a thread should really release its heap here somehow: - proc destroyThread*[TParam](t: var TThread[TParam]) = + proc destroyThread*[TMsg](t: var TThread[TMsg]) = ## 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": @@ -321,18 +330,18 @@ when false: discard pthread_cancel(t.sys) unregisterThread(addr(t)) -proc createThread*[TParam](t: var TThread[TParam], - tp: proc (param: TParam) {.thread.}, - param: TParam) = +proc createThread*[TMsg](t: var TThread[TMsg], + tp: proc (msg: TMsg) {.thread.}, + param: TMsg) = ## creates a new thread `t` and starts its execution. Entry point is the ## proc `tp`. `param` is passed to `tp`. t.data = param t.dataFn = tp - t.stackSize = ThreadStackSize + when hasSharedHeap: t.stackSize = ThreadStackSize initInbox(addr(t.inbox)) when hostOS == "windows": var dummyThreadId: int32 - t.sys = CreateThread(nil, ThreadStackSize, threadProcWrapper[TParam], + t.sys = CreateThread(nil, ThreadStackSize, threadProcWrapper[TMsg], addr(t), 0'i32, dummyThreadId) if t.sys <= 0: raise newException(EResourceExhausted, "cannot create thread") @@ -340,18 +349,18 @@ proc createThread*[TParam](t: var TThread[TParam], var a: Tpthread_attr pthread_attr_init(a) pthread_attr_setstacksize(a, ThreadStackSize) - if pthread_create(t.sys, a, threadProcWrapper[TParam], addr(t)) != 0: + if pthread_create(t.sys, a, threadProcWrapper[TMsg], addr(t)) != 0: raise newException(EResourceExhausted, "cannot create thread") -proc createThread*[TParam](t: var TThread[TParam], tp: proc () {.thread.}) = +proc createThread*[TMsg](t: var TThread[TMsg], tp: proc () {.thread.}) = ## creates a new thread `t` and starts its execution. Entry point is the ## proc `tp`. t.emptyFn = tp - t.stackSize = ThreadStackSize + when hasSharedHeap: t.stackSize = ThreadStackSize initInbox(addr(t.inbox)) when hostOS == "windows": var dummyThreadId: int32 - t.sys = CreateThread(nil, ThreadStackSize, threadProcWrapper[TParam], + t.sys = CreateThread(nil, ThreadStackSize, threadProcWrapper[TMsg], addr(t), 0'i32, dummyThreadId) if t.sys <= 0: raise newException(EResourceExhausted, "cannot create thread") @@ -359,9 +368,17 @@ proc createThread*[TParam](t: var TThread[TParam], tp: proc () {.thread.}) = var a: Tpthread_attr pthread_attr_init(a) pthread_attr_setstacksize(a, ThreadStackSize) - if pthread_create(t.sys, a, threadProcWrapper[TParam], addr(t)) != 0: + if pthread_create(t.sys, a, threadProcWrapper[TMsg], addr(t)) != 0: raise newException(EResourceExhausted, "cannot create thread") +proc threadId*[TMsg](t: var TThread[TMsg]): TThreadId[TMsg] {.inline.} = + ## returns the thread ID of `t`. + result = addr(t) + +proc myThreadId*[TMsg](): TThreadId[TMsg] = + ## returns the thread ID of the thread that calls this proc. + result = cast[TThreadId[TMsg]](ThreadVarGetValue(globalsSlot)) + when useStackMaskHack: proc runMain(tp: proc () {.thread.}) {.compilerproc.} = var mainThread: TThread[pointer] @@ -371,7 +388,7 @@ when useStackMaskHack: # --------------------------- lock handling ---------------------------------- type - TLock* = TSysLock ## Nimrod lock + TLock* = TSysLock ## Nimrod lock; not re-entrant! const noDeadlocks = false # compileOption("deadlockPrevention") diff --git a/lib/wrappers/sphinx.nim b/lib/wrappers/sphinx.nim index a4fce0205..a4fce0205 100644..100755 --- a/lib/wrappers/sphinx.nim +++ b/lib/wrappers/sphinx.nim diff --git a/lib/wrappers/zmq.nim b/lib/wrappers/zmq.nim index 8ebda26f9..4e658028e 100644..100755 --- a/lib/wrappers/zmq.nim +++ b/lib/wrappers/zmq.nim @@ -27,7 +27,32 @@ ## Nimrod 0mq wrapper. This file contains the low level C wrappers as well as ## some higher level constructs. The higher level constructs are easily ## recognizable because they are the only ones that have documentation. - +## +## Example of a client: +## +## .. code-block:: nimrod +## import zmq +## +## var connection = zmq.open("tcp://localhost:5555", server=false) +## echo("Connecting...") +## for i in 0..10: +## echo("Sending hello...", i) +## send(connection, "Hello") +## var reply = receive(connection) +## echo("Received ...", reply) +## close(connection) +## +## Example of a server: +## +## .. code-block:: nimrod +## +## import zmq +## var connection = zmq.open("tcp://*:5555", server=true) +## while True: +## var request = receive(connection) +## echo("Received: ", request) +## send(connection, "World") +## close(connection) {.deadCodeElim: on.} when defined(windows): |