Merge branch 'devel' into gogc
This commit is contained in:
commit
bdac85f2cf
212 changed files with 8304 additions and 7492 deletions
|
|
@ -24,8 +24,8 @@
|
|||
## import locks
|
||||
##
|
||||
## var
|
||||
## thr: array [0..4, TThread[tuple[a,b: int]]]
|
||||
## L: TLock
|
||||
## thr: array [0..4, Thread[tuple[a,b: int]]]
|
||||
## L: Lock
|
||||
##
|
||||
## proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
|
||||
## for i in interval.a..interval.b:
|
||||
|
|
@ -51,40 +51,41 @@ const
|
|||
|
||||
when defined(windows):
|
||||
type
|
||||
TSysThread = THandle
|
||||
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
|
||||
SysThread = Handle
|
||||
WinThreadProc = proc (x: pointer): int32 {.stdcall.}
|
||||
{.deprecated: [TSysThread: SysThread, TWinThreadProc: WinThreadProc].}
|
||||
|
||||
proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
|
||||
lpStartAddress: TWinThreadProc,
|
||||
lpStartAddress: WinThreadProc,
|
||||
lpParameter: pointer,
|
||||
dwCreationFlags: int32,
|
||||
lpThreadId: var int32): TSysThread {.
|
||||
lpThreadId: var int32): SysThread {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateThread".}
|
||||
|
||||
proc winSuspendThread(hThread: TSysThread): int32 {.
|
||||
proc winSuspendThread(hThread: SysThread): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
|
||||
|
||||
proc winResumeThread(hThread: TSysThread): int32 {.
|
||||
proc winResumeThread(hThread: SysThread): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
|
||||
|
||||
proc waitForMultipleObjects(nCount: int32,
|
||||
lpHandles: ptr TSysThread,
|
||||
lpHandles: ptr SysThread,
|
||||
bWaitAll: int32,
|
||||
dwMilliseconds: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
||||
|
||||
proc terminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
|
||||
proc terminateThread(hThread: SysThread, dwExitCode: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
|
||||
|
||||
type
|
||||
TThreadVarSlot = distinct int32
|
||||
ThreadVarSlot = distinct int32
|
||||
|
||||
when true:
|
||||
proc threadVarAlloc(): TThreadVarSlot {.
|
||||
proc threadVarAlloc(): ThreadVarSlot {.
|
||||
importc: "TlsAlloc", stdcall, header: "<windows.h>".}
|
||||
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
||||
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
|
||||
importc: "TlsSetValue", stdcall, header: "<windows.h>".}
|
||||
proc tlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
||||
proc tlsGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
|
||||
importc: "TlsGetValue", stdcall, header: "<windows.h>".}
|
||||
|
||||
proc getLastError(): uint32 {.
|
||||
|
|
@ -92,16 +93,16 @@ when defined(windows):
|
|||
proc setLastError(x: uint32) {.
|
||||
importc: "SetLastError", stdcall, header: "<windows.h>".}
|
||||
|
||||
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer =
|
||||
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer =
|
||||
let realLastError = getLastError()
|
||||
result = tlsGetValue(dwTlsIndex)
|
||||
setLastError(realLastError)
|
||||
else:
|
||||
proc threadVarAlloc(): TThreadVarSlot {.
|
||||
proc threadVarAlloc(): ThreadVarSlot {.
|
||||
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
||||
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
||||
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
|
||||
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
||||
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
||||
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
|
||||
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
||||
|
||||
else:
|
||||
|
|
@ -111,55 +112,58 @@ else:
|
|||
{.passC: "-pthread".}
|
||||
|
||||
type
|
||||
TSysThread {.importc: "pthread_t", header: "<sys/types.h>",
|
||||
SysThread {.importc: "pthread_t", header: "<sys/types.h>",
|
||||
final, pure.} = object
|
||||
Tpthread_attr {.importc: "pthread_attr_t",
|
||||
Pthread_attr {.importc: "pthread_attr_t",
|
||||
header: "<sys/types.h>", final, pure.} = object
|
||||
|
||||
Ttimespec {.importc: "struct timespec",
|
||||
Timespec {.importc: "struct timespec",
|
||||
header: "<time.h>", final, pure.} = object
|
||||
tv_sec: int
|
||||
tv_nsec: int
|
||||
{.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr,
|
||||
Ttimespec: Timespec].}
|
||||
|
||||
proc pthread_attr_init(a1: var TPthread_attr) {.
|
||||
proc pthread_attr_init(a1: var PthreadAttr) {.
|
||||
importc, header: "<pthread.h>".}
|
||||
proc pthread_attr_setstacksize(a1: var TPthread_attr, a2: int) {.
|
||||
proc pthread_attr_setstacksize(a1: var PthreadAttr, a2: int) {.
|
||||
importc, header: "<pthread.h>".}
|
||||
|
||||
proc pthread_create(a1: var TSysThread, a2: var TPthread_attr,
|
||||
proc pthread_create(a1: var SysThread, a2: var PthreadAttr,
|
||||
a3: proc (x: pointer): pointer {.noconv.},
|
||||
a4: pointer): cint {.importc: "pthread_create",
|
||||
header: "<pthread.h>".}
|
||||
proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
|
||||
proc pthread_join(a1: SysThread, a2: ptr pointer): cint {.
|
||||
importc, header: "<pthread.h>".}
|
||||
|
||||
proc pthread_cancel(a1: TSysThread): cint {.
|
||||
proc pthread_cancel(a1: SysThread): cint {.
|
||||
importc: "pthread_cancel", header: "<pthread.h>".}
|
||||
|
||||
type
|
||||
TThreadVarSlot {.importc: "pthread_key_t", pure, final,
|
||||
ThreadVarSlot {.importc: "pthread_key_t", pure, final,
|
||||
header: "<sys/types.h>".} = object
|
||||
{.deprecated: [TThreadVarSlot: ThreadVarSlot].}
|
||||
|
||||
proc pthread_getspecific(a1: TThreadVarSlot): pointer {.
|
||||
proc pthread_getspecific(a1: ThreadVarSlot): pointer {.
|
||||
importc: "pthread_getspecific", header: "<pthread.h>".}
|
||||
proc pthread_key_create(a1: ptr TThreadVarSlot,
|
||||
proc pthread_key_create(a1: ptr ThreadVarSlot,
|
||||
destruct: proc (x: pointer) {.noconv.}): int32 {.
|
||||
importc: "pthread_key_create", header: "<pthread.h>".}
|
||||
proc pthread_key_delete(a1: TThreadVarSlot): int32 {.
|
||||
proc pthread_key_delete(a1: ThreadVarSlot): int32 {.
|
||||
importc: "pthread_key_delete", header: "<pthread.h>".}
|
||||
|
||||
proc pthread_setspecific(a1: TThreadVarSlot, a2: pointer): int32 {.
|
||||
proc pthread_setspecific(a1: ThreadVarSlot, a2: pointer): int32 {.
|
||||
importc: "pthread_setspecific", header: "<pthread.h>".}
|
||||
|
||||
proc threadVarAlloc(): TThreadVarSlot {.inline.} =
|
||||
proc threadVarAlloc(): ThreadVarSlot {.inline.} =
|
||||
discard pthread_key_create(addr(result), nil)
|
||||
proc threadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
|
||||
proc threadVarSetValue(s: ThreadVarSlot, value: pointer) {.inline.} =
|
||||
discard pthread_setspecific(s, value)
|
||||
proc threadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
|
||||
proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} =
|
||||
result = pthread_getspecific(s)
|
||||
|
||||
when useStackMaskHack:
|
||||
proc pthread_attr_setstack(attr: var TPthread_attr, stackaddr: pointer,
|
||||
proc pthread_attr_setstack(attr: var PthreadAttr, stackaddr: pointer,
|
||||
size: int): cint {.
|
||||
importc: "pthread_attr_setstack", header: "<pthread.h>".}
|
||||
|
||||
|
|
@ -175,13 +179,13 @@ when emulatedThreadVars:
|
|||
# allocations are needed. Currently less than 7K are used on a 64bit machine.
|
||||
# We use ``float`` for proper alignment:
|
||||
type
|
||||
TThreadLocalStorage = array [0..1_000, float]
|
||||
ThreadLocalStorage = array [0..1_000, float]
|
||||
|
||||
PGcThread = ptr TGcThread
|
||||
TGcThread {.pure, inheritable.} = object
|
||||
sys: TSysThread
|
||||
PGcThread = ptr GcThread
|
||||
GcThread {.pure, inheritable.} = object
|
||||
sys: SysThread
|
||||
when emulatedThreadVars and not useStackMaskHack:
|
||||
tls: TThreadLocalStorage
|
||||
tls: ThreadLocalStorage
|
||||
else:
|
||||
nil
|
||||
when hasSharedHeap:
|
||||
|
|
@ -190,15 +194,16 @@ type
|
|||
stackSize: int
|
||||
else:
|
||||
nil
|
||||
{.deprecated: [TThreadLocalStorage: ThreadLocalStorage, TGcThread: GcThread].}
|
||||
|
||||
# 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: TThreadVarSlot
|
||||
var globalsSlot: ThreadVarSlot
|
||||
|
||||
when not defined(useNimRtl):
|
||||
when not useStackMaskHack:
|
||||
var mainThread: TGcThread
|
||||
var mainThread: GcThread
|
||||
|
||||
proc initThreadVarsEmulation() {.compilerProc, inline.} =
|
||||
when not defined(useNimRtl):
|
||||
|
|
@ -206,7 +211,7 @@ proc initThreadVarsEmulation() {.compilerProc, inline.} =
|
|||
when declared(mainThread):
|
||||
threadVarSetValue(globalsSlot, addr(mainThread))
|
||||
|
||||
#const globalsSlot = TThreadVarSlot(0)
|
||||
#const globalsSlot = ThreadVarSlot(0)
|
||||
#sysAssert checkSlot.int == globalsSlot.int
|
||||
|
||||
when emulatedThreadVars:
|
||||
|
|
@ -228,7 +233,7 @@ when not defined(useNimRtl):
|
|||
initGC()
|
||||
|
||||
when emulatedThreadVars:
|
||||
if nimThreadVarsSize() > sizeof(TThreadLocalStorage):
|
||||
if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
|
||||
echo "too large thread local storage size requested"
|
||||
quit 1
|
||||
|
||||
|
|
@ -269,26 +274,27 @@ when not defined(useNimRtl):
|
|||
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
|
||||
|
||||
type
|
||||
TThread* {.pure, final.}[TArg] =
|
||||
object of TGcThread ## Nim thread. A thread is a heavy object (~14K)
|
||||
Thread* {.pure, final.}[TArg] =
|
||||
object of GcThread ## Nim thread. A thread is a heavy object (~14K)
|
||||
## that **must not** be part of a message! Use
|
||||
## a ``TThreadId`` for that.
|
||||
## a ``ThreadId`` for that.
|
||||
when TArg is void:
|
||||
dataFn: proc () {.nimcall, gcsafe.}
|
||||
else:
|
||||
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
|
||||
data: TArg
|
||||
TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
|
||||
ThreadId*[TArg] = ptr Thread[TArg] ## the current implementation uses
|
||||
## a pointer as a thread ID.
|
||||
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
|
||||
|
||||
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
|
||||
proc deallocOsPages()
|
||||
|
||||
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
|
||||
var t = cast[ptr TThread[TArg]](closure)
|
||||
var t = cast[ptr Thread[TArg]](closure)
|
||||
when useStackMaskHack:
|
||||
var tls: TThreadLocalStorage
|
||||
var tls: ThreadLocalStorage
|
||||
when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap:
|
||||
# init the GC for this thread:
|
||||
setStackBottom(addr(t))
|
||||
|
|
@ -319,35 +325,35 @@ else:
|
|||
threadProcWrapperBody(closure)
|
||||
{.pop.}
|
||||
|
||||
proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
|
||||
proc running*[TArg](t: Thread[TArg]): bool {.inline.} =
|
||||
## returns true if `t` is running.
|
||||
result = t.dataFn != nil
|
||||
|
||||
when hostOS == "windows":
|
||||
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
|
||||
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
|
||||
## waits for the thread `t` to finish.
|
||||
discard waitForSingleObject(t.sys, -1'i32)
|
||||
|
||||
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
|
||||
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
|
||||
## waits for every thread in `t` to finish.
|
||||
var a: array[0..255, TSysThread]
|
||||
var a: array[0..255, SysThread]
|
||||
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,
|
||||
cast[ptr TSysThread](addr(a)), 1, -1)
|
||||
cast[ptr SysThread](addr(a)), 1, -1)
|
||||
|
||||
else:
|
||||
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
|
||||
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
|
||||
## waits for the thread `t` to finish.
|
||||
discard pthread_join(t.sys, nil)
|
||||
|
||||
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
|
||||
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
|
||||
## 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 TThread[TArg]) =
|
||||
proc destroyThread*[TArg](t: var Thread[TArg]) =
|
||||
## 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":
|
||||
|
|
@ -358,7 +364,7 @@ when false:
|
|||
t.dataFn = nil
|
||||
|
||||
when hostOS == "windows":
|
||||
proc createThread*[TArg](t: var TThread[TArg],
|
||||
proc createThread*[TArg](t: var Thread[TArg],
|
||||
tp: proc (arg: TArg) {.thread.},
|
||||
param: TArg) =
|
||||
## creates a new thread `t` and starts its execution. Entry point is the
|
||||
|
|
@ -373,7 +379,7 @@ when hostOS == "windows":
|
|||
if t.sys <= 0:
|
||||
raise newException(ResourceExhaustedError, "cannot create thread")
|
||||
else:
|
||||
proc createThread*[TArg](t: var TThread[TArg],
|
||||
proc createThread*[TArg](t: var Thread[TArg],
|
||||
tp: proc (arg: TArg) {.thread.},
|
||||
param: TArg) =
|
||||
## creates a new thread `t` and starts its execution. Entry point is the
|
||||
|
|
@ -382,29 +388,29 @@ else:
|
|||
when TArg isnot void: t.data = param
|
||||
t.dataFn = tp
|
||||
when hasSharedHeap: t.stackSize = ThreadStackSize
|
||||
var a {.noinit.}: Tpthread_attr
|
||||
var a {.noinit.}: PthreadAttr
|
||||
pthread_attr_init(a)
|
||||
pthread_attr_setstacksize(a, ThreadStackSize)
|
||||
if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0:
|
||||
raise newException(ResourceExhaustedError, "cannot create thread")
|
||||
|
||||
proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} =
|
||||
proc threadId*[TArg](t: var Thread[TArg]): ThreadId[TArg] {.inline.} =
|
||||
## returns the thread ID of `t`.
|
||||
result = addr(t)
|
||||
|
||||
proc myThreadId*[TArg](): TThreadId[TArg] =
|
||||
proc myThreadId*[TArg](): ThreadId[TArg] =
|
||||
## returns the thread ID of the thread that calls this proc. This is unsafe
|
||||
## because the type ``TArg`` is not checked for consistency!
|
||||
result = cast[TThreadId[TArg]](threadVarGetValue(globalsSlot))
|
||||
result = cast[ThreadId[TArg]](threadVarGetValue(globalsSlot))
|
||||
|
||||
when false:
|
||||
proc mainThreadId*[TArg](): TThreadId[TArg] =
|
||||
proc mainThreadId*[TArg](): ThreadId[TArg] =
|
||||
## returns the thread ID of the main thread.
|
||||
result = cast[TThreadId[TArg]](addr(mainThread))
|
||||
result = cast[ThreadId[TArg]](addr(mainThread))
|
||||
|
||||
when useStackMaskHack:
|
||||
proc runMain(tp: proc () {.thread.}) {.compilerproc.} =
|
||||
var mainThread: TThread[pointer]
|
||||
var mainThread: Thread[pointer]
|
||||
createThread(mainThread, tp)
|
||||
joinThread(mainThread)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue