File: threadtypes.nim

package info (click to toggle)
nim 2.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,911,644 kB
  • sloc: sh: 24,603; ansic: 1,761; python: 1,492; makefile: 1,013; sql: 298; asm: 141; xml: 13
file content (176 lines) | stat: -rw-r--r-- 6,317 bytes parent folder | download
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
include system/inclrtl

const hasSharedHeap* = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own

when defined(windows):
  type
    Handle* = int
    SysThread* = Handle
    WinThreadProc* = proc (x: pointer): int32 {.stdcall.}

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

  proc winSuspendThread*(hThread: SysThread): int32 {.
    stdcall, dynlib: "kernel32", importc: "SuspendThread".}

  proc winResumeThread*(hThread: SysThread): int32 {.
    stdcall, dynlib: "kernel32", importc: "ResumeThread".}

  proc waitForSingleObject*(hHandle: SysThread, dwMilliseconds: int32): int32 {.
    stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}

  proc waitForMultipleObjects*(nCount: int32,
                              lpHandles: ptr SysThread,
                              bWaitAll: int32,
                              dwMilliseconds: int32): int32 {.
    stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}

  proc terminateThread*(hThread: SysThread, dwExitCode: int32): int32 {.
    stdcall, dynlib: "kernel32", importc: "TerminateThread".}

  proc setThreadAffinityMask*(hThread: SysThread, dwThreadAffinityMask: uint) {.
    importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".}

elif defined(genode):
  const
    GenodeHeader* = "genode_cpp/threads.h"
  type
    SysThread* {.importcpp: "Nim::SysThread",
                 header: GenodeHeader, final, pure.} = object
    GenodeThreadProc* = proc (x: pointer) {.noconv.}

  proc initThread*(s: var SysThread,
                  env: GenodeEnv,
                  stackSize: culonglong,
                  entry: GenodeThreadProc,
                  arg: pointer,
                  affinity: cuint) {.
    importcpp: "#.initThread(@)".}


else:
  when not (defined(macosx) or defined(haiku)):
    {.passl: "-pthread".}

  when not defined(haiku):
    {.passc: "-pthread".}

  const
    schedh = "#define _GNU_SOURCE\n#include <sched.h>"
    pthreadh* = "#define _GNU_SOURCE\n#include <pthread.h>"

  when not declared(Time):
    when defined(linux):
      type Time = clong
    else:
      type Time = int

  when (defined(linux) or defined(nintendoswitch)) and defined(amd64):
    type
      SysThread* {.importc: "pthread_t",
                  header: "<sys/types.h>" .} = distinct culong
      Pthread_attr* {.importc: "pthread_attr_t",
                    header: "<sys/types.h>".} = object
        abi: array[56 div sizeof(clong), clong]
  elif defined(openbsd) and defined(amd64):
    type
      SysThread* {.importc: "pthread_t", header: "<pthread.h>".} = object
      Pthread_attr* {.importc: "pthread_attr_t",
                       header: "<pthread.h>".} = object
  else:
    type
      SysThread* {.importc: "pthread_t", header: "<sys/types.h>".} = int
      Pthread_attr* {.importc: "pthread_attr_t",
                       header: "<sys/types.h>".} = object
  type
    Timespec* {.importc: "struct timespec", header: "<time.h>".} = object
      tv_sec*: Time
      tv_nsec*: clong

  proc pthread_attr_init*(a1: var Pthread_attr): cint {.
    importc, header: pthreadh.}
  proc pthread_attr_setstack*(a1: ptr Pthread_attr, a2: pointer, a3: int): cint {.
    importc, header: pthreadh.}
  proc pthread_attr_setstacksize*(a1: var Pthread_attr, a2: int): cint {.
    importc, header: pthreadh.}
  proc pthread_attr_destroy*(a1: var Pthread_attr): cint {.
    importc, header: pthreadh.}

  proc pthread_create*(a1: var SysThread, a2: var Pthread_attr,
            a3: proc (x: pointer): pointer {.noconv.},
            a4: pointer): cint {.importc: "pthread_create",
            header: pthreadh.}
  proc pthread_join*(a1: SysThread, a2: ptr pointer): cint {.
    importc, header: pthreadh.}

  proc pthread_cancel*(a1: SysThread): cint {.
    importc: "pthread_cancel", header: pthreadh.}

  type CpuSet* {.importc: "cpu_set_t", header: schedh.} = object
     when defined(linux) and defined(amd64):
       abi: array[1024 div (8 * sizeof(culong)), culong]

  proc cpusetZero*(s: var CpuSet) {.importc: "CPU_ZERO", header: schedh.}
  proc cpusetIncl*(cpu: cint; s: var CpuSet) {.
    importc: "CPU_SET", header: schedh.}

  when defined(android):
    # libc of android doesn't implement pthread_setaffinity_np,
    # it exposes pthread_gettid_np though, so we can use that in combination
    # with sched_setaffinity to set the thread affinity.
    type Pid* {.importc: "pid_t", header: "<sys/types.h>".} = int32 # From posix_other.nim

    proc setAffinityTID*(tid: Pid; setsize: csize_t; s: var CpuSet) {.
      importc: "sched_setaffinity", header: schedh.}

    proc pthread_gettid_np*(thread: SysThread): Pid {.
      importc: "pthread_gettid_np", header: pthreadh.}

    proc setAffinity*(thread: SysThread; setsize: csize_t; s: var CpuSet) =
      setAffinityTID(pthread_gettid_np(thread), setsize, s)
  else:
    proc setAffinity*(thread: SysThread; setsize: csize_t; s: var CpuSet) {.
      importc: "pthread_setaffinity_np", header: pthreadh.}


const
  emulatedThreadVars* = compileOption("tlsEmulation")
# we preallocate a fixed size for thread local storage, so that no heap
# allocations are needed. Currently less than 16K are used on a 64bit machine.
# We use `float` for proper alignment:
const nimTlsSize {.intdefine.} = 16000
type
  ThreadLocalStorage* = array[0..(nimTlsSize div sizeof(float)), float]
  PGcThread* = ptr GcThread
  GcThread* {.pure, inheritable.} = object
    when emulatedThreadVars:
      tls*: ThreadLocalStorage
    else:
      nil
    when hasSharedHeap:
      next*, prev*: PGcThread
      stackBottom*, stackTop*: pointer
      stackSize*: int
    else:
      nil

const hasAllocStack* = defined(zephyr) # maybe freertos too?

type
  Thread*[TArg] = object
    core*: PGcThread
    sys*: SysThread
    when TArg is void:
      dataFn*: proc () {.nimcall, gcsafe.}
    else:
      dataFn*: proc (m: TArg) {.nimcall, gcsafe.}
      data*: TArg
    when hasAllocStack:
      rawStack*: pointer

proc `=copy`*[TArg](x: var Thread[TArg], y: Thread[TArg]) {.error.}