case consistency improvements
This commit is contained in:
parent
437cfa73ab
commit
346443d1b5
18 changed files with 139 additions and 137 deletions
|
|
@ -36,7 +36,7 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
|
|||
## This proc implements an atomic load operation. It returns the contents at p.
|
||||
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
|
||||
|
||||
proc atomicLoad*[T: TAtomType](p: ptr T, ret: ptr T, mem: AtomMemModel) {.
|
||||
proc atomicLoad*[T: TAtomType](p, ret: ptr T, mem: AtomMemModel) {.
|
||||
importc: "__atomic_load", nodecl.}
|
||||
## This is the generic version of an atomic load. It returns the contents at p in ret.
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
|
|||
## This proc implements an atomic store operation. It writes val at p.
|
||||
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
|
||||
|
||||
proc atomicStore*[T: TAtomType](p: ptr T, val: ptr T, mem: AtomMemModel) {.
|
||||
proc atomicStore*[T: TAtomType](p, val: ptr T, mem: AtomMemModel) {.
|
||||
importc: "__atomic_store", nodecl.}
|
||||
## This is the generic version of an atomic store. It stores the value of val at p
|
||||
|
||||
|
|
@ -55,12 +55,12 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
|
|||
## and returns the previous contents at p.
|
||||
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
|
||||
|
||||
proc atomicExchange*[T: TAtomType](p: ptr T, val: ptr T, ret: ptr T, mem: AtomMemModel) {.
|
||||
proc atomicExchange*[T: TAtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
|
||||
importc: "__atomic_exchange", nodecl.}
|
||||
## This is the generic version of an atomic exchange. It stores the contents at val at p.
|
||||
## The original value at p is copied into ret.
|
||||
|
||||
proc atomicCompareExchangeN*[T: TAtomType](p: ptr T, expected: ptr T, desired: T,
|
||||
proc atomicCompareExchangeN*[T: TAtomType](p, expected: ptr T, desired: T,
|
||||
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
|
||||
importc: "__atomic_compare_exchange_n ", nodecl.}
|
||||
## This proc implements an atomic compare and exchange operation. This compares the
|
||||
|
|
@ -76,7 +76,7 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
|
|||
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
|
||||
## than that specified by success_memmodel.
|
||||
|
||||
proc atomicCompareExchange*[T: TAtomType](p: ptr T, expected: ptr T, desired: ptr T,
|
||||
proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
|
||||
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
|
||||
importc: "__atomic_compare_exchange_n ", nodecl.}
|
||||
## This proc implements the generic version of atomic_compare_exchange.
|
||||
|
|
@ -108,7 +108,7 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
|
|||
importc: "__atomic_fetch_and", nodecl.}
|
||||
proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||
importc: "__atomic_fetch_xor", nodecl.}
|
||||
proc atomicFetchAand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||
proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||
importc: "__atomic_fetch_nand", nodecl.}
|
||||
|
||||
proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.
|
||||
|
|
@ -176,7 +176,7 @@ else:
|
|||
|
||||
#elif not hasThreadSupport:
|
||||
# proc compareAndSwap*[T](mem: ptr T,
|
||||
# expected: T, newValue: T): bool {.inline.} =
|
||||
# expected: T, newValue: T): bool {.inline.} =
|
||||
# ## Returns true if successfully set value at mem to newValue when value
|
||||
# ## at mem == expected
|
||||
# var oldval = mem[]
|
||||
|
|
@ -202,4 +202,4 @@ proc atomicDec*(memLoc: var int, x: int = 1): int =
|
|||
result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
|
||||
else:
|
||||
dec(memLoc, x)
|
||||
result = memLoc
|
||||
result = memLoc
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ proc deinitRawChannel(p: pointer) =
|
|||
deinitSys(c.lock)
|
||||
deinitSysCond(c.cond)
|
||||
|
||||
proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
||||
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
|
||||
mode: TLoadStoreMode)
|
||||
proc storeAux(dest, src: Pointer, n: ptr TNimNode, t: PRawChannel,
|
||||
proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
|
||||
mode: TLoadStoreMode) =
|
||||
var
|
||||
d = cast[TAddress](dest)
|
||||
|
|
@ -67,7 +67,7 @@ proc storeAux(dest, src: Pointer, n: ptr TNimNode, t: PRawChannel,
|
|||
if m != nil: storeAux(dest, src, m, t, mode)
|
||||
of nkNone: sysAssert(false, "storeAux")
|
||||
|
||||
proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
||||
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
|
||||
mode: TLoadStoreMode) =
|
||||
var
|
||||
d = cast[TAddress](dest)
|
||||
|
|
@ -82,7 +82,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
|||
x[] = nil
|
||||
else:
|
||||
var ss = cast[NimString](s2)
|
||||
var ns = cast[NimString](Alloc(t.region, ss.len+1 + GenericSeqSize))
|
||||
var ns = cast[NimString](alloc(t.region, ss.len+1 + GenericSeqSize))
|
||||
copyMem(ns, ss, ss.len+1 + GenericSeqSize)
|
||||
x[] = ns
|
||||
else:
|
||||
|
|
@ -92,7 +92,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
|||
unsureAsgnRef(x, s2)
|
||||
else:
|
||||
unsureAsgnRef(x, copyString(cast[NimString](s2)))
|
||||
Dealloc(t.region, s2)
|
||||
dealloc(t.region, s2)
|
||||
of tySequence:
|
||||
var s2 = cast[ppointer](src)[]
|
||||
var seq = cast[PGenericSeq](s2)
|
||||
|
|
@ -105,7 +105,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
|||
else:
|
||||
sysAssert(dest != nil, "dest == nil")
|
||||
if mode == mStore:
|
||||
x[] = Alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)
|
||||
x[] = alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)
|
||||
else:
|
||||
unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
|
||||
var dst = cast[taddress](cast[ppointer](dest)[])
|
||||
|
|
@ -118,7 +118,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
|||
var dstseq = cast[PGenericSeq](dst)
|
||||
dstseq.len = seq.len
|
||||
dstseq.reserved = seq.len
|
||||
if mode != mStore: Dealloc(t.region, s2)
|
||||
if mode != mStore: dealloc(t.region, s2)
|
||||
of tyObject:
|
||||
# copy type field:
|
||||
var pint = cast[ptr PNimType](dest)
|
||||
|
|
@ -143,7 +143,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
|||
unsureAsgnRef(x, nil)
|
||||
else:
|
||||
if mode == mStore:
|
||||
x[] = Alloc(t.region, mt.base.size)
|
||||
x[] = alloc(t.region, mt.base.size)
|
||||
else:
|
||||
# XXX we should use the dynamic type here too, but that is not stored
|
||||
# in the inbox at all --> use source[]'s object type? but how? we need
|
||||
|
|
@ -151,7 +151,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
|
|||
var obj = newObj(mt, mt.base.size)
|
||||
unsureAsgnRef(x, obj)
|
||||
storeAux(x[], s, mt.base, t, mode)
|
||||
if mode != mStore: Dealloc(t.region, s)
|
||||
if mode != mStore: dealloc(t.region, s)
|
||||
else:
|
||||
copyMem(dest, src, mt.size) # copy raw bits
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
|
|||
if q.count >= cap:
|
||||
# start with capacity for 2 entries in the queue:
|
||||
if cap == 0: cap = 1
|
||||
var n = cast[pbytes](Alloc0(q.region, cap*2*typ.size))
|
||||
var n = cast[pbytes](alloc0(q.region, cap*2*typ.size))
|
||||
var z = 0
|
||||
var i = q.rd
|
||||
var c = q.count
|
||||
|
|
@ -170,7 +170,7 @@ proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
|
|||
copyMem(addr(n[z*typ.size]), addr(q.data[i*typ.size]), typ.size)
|
||||
i = (i + 1) and q.mask
|
||||
inc z
|
||||
if q.data != nil: Dealloc(q.region, q.data)
|
||||
if q.data != nil: dealloc(q.region, q.data)
|
||||
q.data = n
|
||||
q.mask = cap*2 - 1
|
||||
q.wr = q.count
|
||||
|
|
@ -200,7 +200,7 @@ template sendImpl(q: expr) {.immediate.} =
|
|||
rawSend(q, addr(m), typ)
|
||||
q.elemType = typ
|
||||
releaseSys(q.lock)
|
||||
SignalSysCond(q.cond)
|
||||
signalSysCond(q.cond)
|
||||
|
||||
proc send*[TMsg](c: var TChannel[TMsg], msg: TMsg) =
|
||||
## sends a message to a thread. `msg` is deeply copied.
|
||||
|
|
@ -212,7 +212,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
|
|||
acquireSys(q.lock)
|
||||
q.ready = true
|
||||
while q.count <= 0:
|
||||
WaitSysCond(q.cond, q.lock)
|
||||
waitSysCond(q.cond, q.lock)
|
||||
q.ready = false
|
||||
if typ != q.elemType:
|
||||
releaseSys(q.lock)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ when defined(Windows):
|
|||
discard waitForSingleObject(cond, -1'i32)
|
||||
acquireSys(lock)
|
||||
|
||||
proc waitSysCondWindows(cond: var TSysCond) =
|
||||
discard waitForSingleObject(cond, -1'i32)
|
||||
|
||||
else:
|
||||
type
|
||||
TSysLock {.importc: "pthread_mutex_t", pure, final,
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@
|
|||
##
|
||||
## proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
|
||||
## for i in interval.a..interval.b:
|
||||
## Acquire(L) # lock stdout
|
||||
## acquire(L) # lock stdout
|
||||
## echo i
|
||||
## Release(L)
|
||||
## release(L)
|
||||
##
|
||||
## InitLock(L)
|
||||
## initLock(L)
|
||||
##
|
||||
## for i in 0..high(thr):
|
||||
## createThread(thr[i], threadFunc, (i*10, i*10+5))
|
||||
|
|
@ -54,9 +54,9 @@ when defined(windows):
|
|||
TSysThread = THandle
|
||||
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
|
||||
|
||||
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
|
||||
proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
|
||||
lpStartAddress: TWinThreadProc,
|
||||
lpParameter: Pointer,
|
||||
lpParameter: pointer,
|
||||
dwCreationFlags: int32,
|
||||
lpThreadId: var int32): TSysThread {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateThread".}
|
||||
|
|
@ -67,23 +67,23 @@ when defined(windows):
|
|||
proc winResumeThread(hThread: TSysThread): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
|
||||
|
||||
proc WaitForMultipleObjects(nCount: int32,
|
||||
proc waitForMultipleObjects(nCount: int32,
|
||||
lpHandles: ptr TSysThread,
|
||||
bWaitAll: int32,
|
||||
dwMilliseconds: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
||||
|
||||
proc TerminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
|
||||
proc terminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
|
||||
|
||||
type
|
||||
TThreadVarSlot = distinct int32
|
||||
|
||||
proc ThreadVarAlloc(): TThreadVarSlot {.
|
||||
proc threadVarAlloc(): TThreadVarSlot {.
|
||||
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
||||
proc ThreadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
||||
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
||||
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
||||
proc ThreadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
||||
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
||||
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
||||
|
||||
else:
|
||||
|
|
@ -116,14 +116,14 @@ else:
|
|||
proc pthread_cancel(a1: TSysThread): cint {.
|
||||
importc: "pthread_cancel", header: "<pthread.h>".}
|
||||
|
||||
proc AcquireSysTimeoutAux(L: var TSysLock, timeout: var Ttimespec): cint {.
|
||||
proc acquireSysTimeoutAux(L: var TSysLock, timeout: var Ttimespec): cint {.
|
||||
importc: "pthread_mutex_timedlock", header: "<time.h>".}
|
||||
|
||||
proc AcquireSysTimeout(L: var TSysLock, msTimeout: int) {.inline.} =
|
||||
proc acquireSysTimeout(L: var TSysLock, msTimeout: int) {.inline.} =
|
||||
var a: Ttimespec
|
||||
a.tv_sec = msTimeout div 1000
|
||||
a.tv_nsec = (msTimeout mod 1000) * 1000
|
||||
var res = AcquireSysTimeoutAux(L, a)
|
||||
var res = acquireSysTimeoutAux(L, a)
|
||||
if res != 0'i32: raise newException(EResourceExhausted, $strerror(res))
|
||||
|
||||
type
|
||||
|
|
@ -141,11 +141,11 @@ else:
|
|||
proc pthread_setspecific(a1: TThreadVarSlot, a2: pointer): int32 {.
|
||||
importc: "pthread_setspecific", header: "<pthread.h>".}
|
||||
|
||||
proc ThreadVarAlloc(): TThreadVarSlot {.inline.} =
|
||||
proc threadVarAlloc(): TThreadVarSlot {.inline.} =
|
||||
discard pthread_key_create(addr(result), nil)
|
||||
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
|
||||
proc threadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
|
||||
discard pthread_setspecific(s, value)
|
||||
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
|
||||
proc threadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
|
||||
result = pthread_getspecific(s)
|
||||
|
||||
when useStackMaskHack:
|
||||
|
|
@ -159,7 +159,7 @@ const
|
|||
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".}
|
||||
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.
|
||||
|
|
@ -184,7 +184,7 @@ type
|
|||
# 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 = ThreadVarAlloc()
|
||||
var globalsSlot = threadVarAlloc()
|
||||
#const globalsSlot = TThreadVarSlot(0)
|
||||
#sysAssert checkSlot.int == globalsSlot.int
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ when emulatedThreadVars:
|
|||
result = addr(cast[PGcThread](ThreadVarGetValue(globalsSlot)).tls)
|
||||
|
||||
when useStackMaskHack:
|
||||
proc MaskStackPointer(offset: int): pointer {.compilerRtl, inl.} =
|
||||
proc maskStackPointer(offset: int): pointer {.compilerRtl, inl.} =
|
||||
var x {.volatile.}: pointer
|
||||
x = addr(x)
|
||||
result = cast[pointer]((cast[int](x) and not ThreadStackMask) +%
|
||||
|
|
@ -205,7 +205,7 @@ when not defined(useNimRtl):
|
|||
|
||||
when not useStackMaskHack:
|
||||
var mainThread: TGcThread
|
||||
ThreadVarSetValue(globalsSlot, addr(mainThread))
|
||||
threadVarSetValue(globalsSlot, addr(mainThread))
|
||||
when not defined(createNimRtl): initStackBottom()
|
||||
initGC()
|
||||
|
||||
|
|
@ -220,18 +220,18 @@ when not defined(useNimRtl):
|
|||
|
||||
proc registerThread(t: PGcThread) =
|
||||
# we need to use the GC global lock here!
|
||||
AcquireSys(HeapLock)
|
||||
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)
|
||||
releaseSys(HeapLock)
|
||||
|
||||
proc unregisterThread(t: PGcThread) =
|
||||
# we need to use the GC global lock here!
|
||||
AcquireSys(HeapLock)
|
||||
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
|
||||
|
|
@ -239,7 +239,7 @@ when not defined(useNimRtl):
|
|||
# code executes `destroyThread`:
|
||||
t.next = nil
|
||||
t.prev = nil
|
||||
ReleaseSys(HeapLock)
|
||||
releaseSys(HeapLock)
|
||||
|
||||
# on UNIX, the GC uses ``SIGFREEZE`` to tell every thread to stop so that
|
||||
# the GC can examine the stacks?
|
||||
|
|
@ -266,7 +266,7 @@ type
|
|||
when not defined(boehmgc) and not hasSharedHeap:
|
||||
proc deallocOsPages()
|
||||
|
||||
template ThreadProcWrapperBody(closure: expr) {.immediate.} =
|
||||
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||
when defined(globalsSlot): ThreadVarSetValue(globalsSlot, closure)
|
||||
var t = cast[ptr TThread[TArg]](closure)
|
||||
when useStackMaskHack:
|
||||
|
|
@ -294,11 +294,11 @@ template ThreadProcWrapperBody(closure: expr) {.immediate.} =
|
|||
{.push stack_trace:off.}
|
||||
when defined(windows):
|
||||
proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} =
|
||||
ThreadProcWrapperBody(closure)
|
||||
threadProcWrapperBody(closure)
|
||||
# implicitly return 0
|
||||
else:
|
||||
proc threadProcWrapper[TArg](closure: pointer) {.noconv.} =
|
||||
ThreadProcWrapperBody(closure)
|
||||
threadProcWrapperBody(closure)
|
||||
{.pop.}
|
||||
|
||||
proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
|
||||
|
|
@ -308,7 +308,7 @@ proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
|
|||
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
|
||||
## waits for the thread `t` to finish.
|
||||
when hostOS == "windows":
|
||||
discard WaitForSingleObject(t.sys, -1'i32)
|
||||
discard waitForSingleObject(t.sys, -1'i32)
|
||||
else:
|
||||
discard pthread_join(t.sys, nil)
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
|
|||
var a: array[0..255, TSysThread]
|
||||
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,
|
||||
discard waitForMultipleObjects(t.len.int32,
|
||||
cast[ptr TSysThread](addr(a)), 1, -1)
|
||||
else:
|
||||
for i in 0..t.high: joinThread(t[i])
|
||||
|
|
@ -346,7 +346,7 @@ proc createThread*[TArg](t: var TThread[TArg],
|
|||
when hasSharedHeap: t.stackSize = ThreadStackSize
|
||||
when hostOS == "windows":
|
||||
var dummyThreadId: int32
|
||||
t.sys = CreateThread(nil, ThreadStackSize, threadProcWrapper[TArg],
|
||||
t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg],
|
||||
addr(t), 0'i32, dummyThreadId)
|
||||
if t.sys <= 0:
|
||||
raise newException(EResourceExhausted, "cannot create thread")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue