summary refs log tree commit diff stats
path: root/tests/gc/foreign_thr.nim
blob: 88ab9511332c21c10381dd834ac84be58ee7a5ab (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
discard """
  output: '''
Hello from thread
Hello from thread
Hello from thread
Hello from thread
'''
  cmd: "nim $target --hints:on --threads:on --tlsEmulation:off $options $file"
"""
# Copied from stdlib
import strutils

const
  StackGuardSize = 4096
  ThreadStackMask = 1024*256*sizeof(int)-1
  ThreadStackSize = ThreadStackMask+1 - StackGuardSize

type ThreadFunc = proc() {.thread.}

when defined(posix):
  import posix

  proc runInForeignThread(f: ThreadFunc) =
    proc wrapper(p: pointer): pointer {.noconv.} =
      let thr = cast[ThreadFunc](p)
      setupForeignThreadGc()
      thr()
      tearDownForeignThreadGc()
      setupForeignThreadGc()
      thr()
      tearDownForeignThreadGc()
      result = nil

    var attrs {.noinit.}: PthreadAttr
    doAssert pthread_attr_init(addr attrs) == 0
    doAssert pthread_attr_setstacksize(addr attrs, ThreadStackSize) == 0
    var tid: Pthread
    doAssert pthread_create(addr tid, addr attrs, wrapper, f) == 0
    doAssert pthread_join(tid, nil) == 0

elif defined(windows):
  import winlean
  type
    WinThreadProc = proc (x: pointer): int32 {.stdcall.}

  proc createThread(lpThreadAttributes: pointer, dwStackSize: DWORD,
                     lpStartAddress: WinThreadProc,
                     lpParameter: pointer,
                     dwCreationFlags: DWORD,
                     lpThreadId: var DWORD): Handle {.
    stdcall, dynlib: "kernel32", importc: "CreateThread".}

  proc wrapper(p: pointer): int32 {.stdcall.} =
    let thr = cast[ThreadFunc](p)
    setupForeignThreadGc()
    thr()
    tearDownForeignThreadGc()
    setupForeignThreadGc()
    thr()
    tearDownForeignThreadGc()
    result = 0'i32

  proc runInForeignThread(f: ThreadFunc) =
    var dummyThreadId: DWORD
    var h = createThread(nil, ThreadStackSize.int32, wrapper.WinThreadProc, cast[pointer](f), 0, dummyThreadId)
    doAssert h != 0.Handle
    doAssert waitForSingleObject(h, -1'i32) == 0.DWORD

else:
  {.fatal: "Unknown system".}

proc runInNativeThread(f: ThreadFunc) =
  proc wrapper(f: ThreadFunc) {.thread.} =
    # These operations must be NOP
    setupForeignThreadGc()
    tearDownForeignThreadGc()
    f()
    f()
  var thr: Thread[ThreadFunc]
  createThread(thr, wrapper, f)
  joinThread(thr)

proc f {.thread.} =
  var msg = "Hello " & "from thread"
  echo msg

runInForeignThread(f)
runInNativeThread(f)