diff options
author | Araq <rumpf_a@web.de> | 2011-05-17 19:22:29 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-05-17 19:22:29 +0200 |
commit | aeb0506132bc706750840ba0a79b486745e34c4e (patch) | |
tree | a1e2aeaf5e0309ec9aa5ee2bb1345b837e7af4a5 /lib/system | |
parent | 6dd8c850513956e38f78c02e173df2c4d7b05cf3 (diff) | |
download | Nim-aeb0506132bc706750840ba0a79b486745e34c4e.tar.gz |
thread support: next iteration
Diffstat (limited to 'lib/system')
-rwxr-xr-x | lib/system/excpt.nim | 55 | ||||
-rwxr-xr-x | lib/system/gc.nim | 21 | ||||
-rwxr-xr-x | lib/system/systhread.nim | 57 |
3 files changed, 107 insertions, 26 deletions
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index e2d3bea08..dac5678e0 100755 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -81,8 +81,12 @@ when hasThreadSupport: proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {. importc: "pthread_setspecific", header: "<pthread.h>".} - proc specificDestroy(mem: pointer) {.noconv.} = dealloc(mem) - + proc specificDestroy(mem: pointer) {.noconv.} = + #aquireSys(heapLock) + #dealloc(mem) + #releaseSys(heapLock) + #c_free(mem) + proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} = discard pthread_key_create(addr(result), specificDestroy) proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {. @@ -104,31 +108,50 @@ when hasThreadSupport: tempFrames: array [0..127, PFrame] # cannot be allocated on the stack! data: float # compiler should add thread local variables here! PGlobals = ptr TGlobals - - var globalsSlot = ThreadVarAlloc() - proc CreateThreadLocalStorage*(): pointer {.inl.} = + + # it's more efficient to not use a global variable for the thread storage + # slot, but to rely on the implementation to assign slot 0 for us... ;-) + var checkSlot = ThreadVarAlloc() + const globalsSlot = TThreadVarSlot(0) + assert checkSlot.int == globalsSlot.int + + proc AtomicAlloc0(size: int): pointer = + #AquireSys(heapLock) + result = c_malloc(size) + zeroMem(result, size) + #ReleaseSys(heapLock) + + proc NewGlobals(): PGlobals = + result = cast[PGlobals](AtomicAlloc0(sizeof(TGlobals))) + new(result.gAssertionFailed) + result.buf = newStringOfCap(2000) + result.assertBuf = newStringOfCap(2000) + + proc AllocThreadLocalStorage*(): pointer {.inl.} = isMultiThreaded = true - result = alloc0(sizeof(TGlobals)) - ThreadVarSetValue(globalsSlot, result) + result = NewGlobals() + + proc SetThreadLocalStorage*(p: pointer) {.inl.} = + ThreadVarSetValue(globalsSlot, p) proc GetGlobals(): PGlobals {.compilerRtl, inl.} = result = cast[PGlobals](ThreadVarGetValue(globalsSlot)) # create for the main thread: - ThreadVarSetValue(globalsSlot, alloc0(sizeof(TGlobals))) + ThreadVarSetValue(globalsSlot, NewGlobals()) when hasThreadSupport: - template ThreadGlobals = + template ThreadGlobals = var globals = GetGlobals() template `||`(varname: expr): expr = globals.varname - ThreadGlobals() + #ThreadGlobals() else: template ThreadGlobals = nil # nothing template `||`(varname: expr): expr = varname var - framePtr {.compilerproc.}: PFrame # XXX only temporarily a compilerproc + framePtr: PFrame excHandler: PSafePoint = nil # list of exception handlers # a global variable for the root of all try blocks @@ -141,6 +164,11 @@ else: tempFrames: array [0..127, PFrame] # cannot be allocated on the stack! gAssertionFailed: ref EAssertionFailed + new(||gAssertionFailed) + ||buf = newStringOfCap(2000) + ||assertBuf = newStringOfCap(2000) + + proc pushFrame(s: PFrame) {.compilerRtl, inl.} = ThreadGlobals() s.prev = ||framePtr @@ -388,11 +416,6 @@ proc registerSignalHandler() = when not defined(noSignalHandler): registerSignalHandler() # call it in initialization section -# for easier debugging of the GC, this memory is only allocated after the -# signal handlers have been registered -new(||gAssertionFailed) -||buf = newStringOfCap(2000) -||assertBuf = newStringOfCap(2000) proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} = raise newException(EOutOfRange, "value " & $val & " out of range") diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 52de66d48..3a7270539 100755 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -81,14 +81,14 @@ var proc aquire(gch: var TGcHeap) {.inline.} = when hasThreadSupport: if isMultiThreaded: - aquire(gch.zctLock) - aquire(gch.cycleRootsLock) + aquireSys(gch.zctLock) + aquireSys(gch.cycleRootsLock) proc release(gch: var TGcHeap) {.inline.} = when hasThreadSupport: if isMultiThreaded: - release(gch.zctLock) - release(gch.cycleRootsLock) + releaseSys(gch.zctLock) + releaseSys(gch.cycleRootsLock) proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} = if (c.refcount and rcZct) == 0: @@ -207,18 +207,18 @@ proc prepareDealloc(cell: PCell) = proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! when hasThreadSupport: - if isMultiThreaded: Aquire(gch.cycleRootsLock) + if isMultiThreaded: AquireSys(gch.cycleRootsLock) incl(gch.cycleRoots, c) when hasThreadSupport: - if isMultiThreaded: Release(gch.cycleRootsLock) + if isMultiThreaded: ReleaseSys(gch.cycleRootsLock) proc rtlAddZCT(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! when hasThreadSupport: - if isMultiThreaded: Aquire(gch.zctLock) + if isMultiThreaded: AquireSys(gch.zctLock) addZCT(gch.zct, c) when hasThreadSupport: - if isMultiThreaded: Release(gch.zctLock) + if isMultiThreaded: ReleaseSys(gch.zctLock) proc decRef(c: PCell) {.inline.} = when stressGC: @@ -287,9 +287,10 @@ proc initGC() = Init(gch.cycleRoots) Init(gch.decStack) when hasThreadSupport: - InitLock(gch.cycleRootsLock) - InitLock(gch.zctLock) + InitSysLock(gch.cycleRootsLock) + InitSysLock(gch.zctLock) new(gOutOfMem) # reserve space for the EOutOfMemory exception here! + proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = var d = cast[TAddress](dest) diff --git a/lib/system/systhread.nim b/lib/system/systhread.nim index d9b340ce2..2b5057ff0 100755 --- a/lib/system/systhread.nim +++ b/lib/system/systhread.nim @@ -9,6 +9,12 @@ const maxThreads = 256 + SystemInclude = defined(hasThreadSupport) + +when not SystemInclude: + # ugly hack: this file is then included from core/threads, so we have + # thread support: + const hasThreadSupport = true when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport: proc sync_add_and_fetch(p: var int, val: int): int {. @@ -40,3 +46,54 @@ proc atomicDec(memLoc: var int, x: int): int = dec(memLoc, x) result = memLoc +when defined(Windows): + type + TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi + DebugInfo: pointer + LockCount: int32 + RecursionCount: int32 + OwningThread: int + LockSemaphore: int + Reserved: int32 + + proc InitSysLock(L: var TSysLock) {.stdcall, + dynlib: "kernel32", importc: "InitializeCriticalSection".} + ## Initializes the lock `L`. + + proc TryAquireSysAux(L: var TSysLock): int32 {.stdcall, + dynlib: "kernel32", importc: "TryEnterCriticalSection".} + ## Tries to aquire the lock `L`. + + proc TryAquireSys(L: var TSysLock): bool {.inline.} = + result = TryAquireSysAux(L) != 0'i32 + + proc AquireSys(L: var TSysLock) {.stdcall, + dynlib: "kernel32", importc: "EnterCriticalSection".} + ## Aquires the lock `L`. + + proc ReleaseSys(L: var TSysLock) {.stdcall, + dynlib: "kernel32", importc: "LeaveCriticalSection".} + ## Releases the lock `L`. + +else: + type + TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int + + proc InitSysLock(L: var TSysLock, attr: pointer = nil) {. + importc: "pthread_mutex_init", header: "<pthread.h>".} + + proc AquireSys(L: var TSysLock) {. + importc: "pthread_mutex_lock", header: "<pthread.h>".} + proc TryAquireSysAux(L: var TSysLock): cint {. + importc: "pthread_mutex_trylock", header: "<pthread.h>".} + + proc TryAquireSys(L: var TSysLock): bool {.inline.} = + result = TryAquireSysAux(L) == 0'i32 + + proc ReleaseSys(L: var TSysLock) {. + importc: "pthread_mutex_unlock", header: "<pthread.h>".} + +when SystemInclude: + var heapLock: TSysLock + InitSysLock(HeapLock) + |