Merge branch 'devel' into gogc

This commit is contained in:
Stefan Talpalaru 2015-06-15 08:44:02 +02:00
commit bdac85f2cf
212 changed files with 8304 additions and 7492 deletions

View file

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