foreign_thr.nim 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. discard """
  2. output: '''
  3. Hello from thread
  4. Hello from thread
  5. Hello from thread
  6. Hello from thread
  7. '''
  8. cmd: "nim $target --hints:on --threads:on --tlsEmulation:off $options $file"
  9. retries: 2
  10. """
  11. # Copied from stdlib
  12. import strutils
  13. const
  14. StackGuardSize = 4096
  15. ThreadStackMask = 1024*256*sizeof(int)-1
  16. ThreadStackSize = ThreadStackMask+1 - StackGuardSize
  17. type ThreadFunc = proc() {.thread.}
  18. when defined(posix):
  19. import posix
  20. proc runInForeignThread(f: ThreadFunc) =
  21. proc wrapper(p: pointer): pointer {.noconv.} =
  22. let thr = cast[ThreadFunc](p)
  23. setupForeignThreadGc()
  24. thr()
  25. tearDownForeignThreadGc()
  26. setupForeignThreadGc()
  27. thr()
  28. tearDownForeignThreadGc()
  29. result = nil
  30. var attrs {.noinit.}: PthreadAttr
  31. doAssert pthread_attr_init(addr attrs) == 0
  32. doAssert pthread_attr_setstacksize(addr attrs, ThreadStackSize) == 0
  33. var tid: Pthread
  34. doAssert pthread_create(addr tid, addr attrs, wrapper, f) == 0
  35. doAssert pthread_join(tid, nil) == 0
  36. elif defined(windows):
  37. import winlean
  38. type
  39. WinThreadProc = proc (x: pointer): int32 {.stdcall.}
  40. proc createThread(lpThreadAttributes: pointer, dwStackSize: DWORD,
  41. lpStartAddress: WinThreadProc,
  42. lpParameter: pointer,
  43. dwCreationFlags: DWORD,
  44. lpThreadId: var DWORD): Handle {.
  45. stdcall, dynlib: "kernel32", importc: "CreateThread".}
  46. proc wrapper(p: pointer): int32 {.stdcall.} =
  47. let thr = cast[ThreadFunc](p)
  48. setupForeignThreadGc()
  49. thr()
  50. tearDownForeignThreadGc()
  51. setupForeignThreadGc()
  52. thr()
  53. tearDownForeignThreadGc()
  54. result = 0'i32
  55. proc runInForeignThread(f: ThreadFunc) =
  56. var dummyThreadId: DWORD
  57. var h = createThread(nil, ThreadStackSize.int32, wrapper.WinThreadProc, cast[pointer](f), 0, dummyThreadId)
  58. doAssert h != 0.Handle
  59. doAssert waitForSingleObject(h, -1'i32) == 0.DWORD
  60. else:
  61. {.fatal: "Unknown system".}
  62. proc runInNativeThread(f: ThreadFunc) =
  63. proc wrapper(f: ThreadFunc) {.thread.} =
  64. # These operations must be NOP
  65. setupForeignThreadGc()
  66. tearDownForeignThreadGc()
  67. f()
  68. f()
  69. var thr: Thread[ThreadFunc]
  70. createThread(thr, wrapper, f)
  71. joinThread(thr)
  72. proc f {.thread.} =
  73. var msg = "Hello " & "from thread"
  74. echo msg
  75. runInForeignThread(f)
  76. runInNativeThread(f)