systhrd.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. {%MainUnit system.pp}
  2. {
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2022 by Nikolay Nikolov,
  5. member of the Free Pascal development team.
  6. WASI threading support implementation
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. {$ifndef FPC_WASM_THREADS}
  14. {$fatal This file shouldn't be included if thread support is disabled!}
  15. {$endif FPC_WASM_THREADS}
  16. {$DEFINE DEBUGWASMTHREADS}
  17. Const
  18. MaxThreadSignal = 1000; // maximum threads to signal
  19. Type
  20. TThreadState = (tsNone,tsInit,tsRunning,tsCanceling,tsExit);
  21. TOSTime = __wasi_timestamp_t;
  22. // Forwards used in mutex
  23. Function GetClockTime: TOSTime; forward;
  24. Function IsWaitAllowed : Boolean; forward;
  25. Function GetSelfThread : TThreadID; forward;
  26. Function GetThreadState(aThread : TThreadID) : TThreadState; forward;
  27. {$i wasmmem.inc}
  28. {$i wasmmutex.inc}
  29. Type
  30. PWasmRTLEvent = ^TWasmRTLEvent;
  31. TWasmRTLEvent = record
  32. Signal : Longint;
  33. mutex: TWasmMutex;
  34. Destroying : Boolean;
  35. end;
  36. PWasmThread = ^TWasmThread;
  37. TWasmThread = Record
  38. ID : LongInt; // Allocated by host javascript code
  39. State : TThreadState;
  40. DoneEvent : PWasmRTLEvent;
  41. Running : TWasmMutex;
  42. ExitCode : Cardinal;
  43. ThreadName : Array of byte; // UTF8 name
  44. end;
  45. Var
  46. MainThread : TWasmThread;
  47. WasiThreadManager : TThreadManager;
  48. GlobalIsWorkerThread : Longint; section 'WebAssembly.Global';
  49. GlobalIsMainThread : Longint; section 'WebAssembly.Global';
  50. GlobalIsThreadBlockable : Longint; section 'WebAssembly.Global';
  51. GlobalCurrentThread : PWasmThread; section 'WebAssembly.Global';
  52. // Forward functions
  53. Function IsWaitAllowed : Boolean;
  54. begin
  55. IsWaitAllowed:=GlobalIsThreadBlockable<>0;
  56. end;
  57. Function GetClockTime: TOSTime;
  58. var
  59. NanoSecsPast: TOSTime;
  60. begin
  61. if __wasi_clock_time_get(__WASI_CLOCKID_REALTIME,1000000,@NanoSecsPast)=__WASI_ERRNO_SUCCESS then
  62. GetClockTime:=NanoSecsPast
  63. else
  64. GetClockTime:=0;
  65. end;
  66. Function GetSelfThread : TThreadID;
  67. begin
  68. GetSelfThread:=GlobalCurrentThread;
  69. end;
  70. Function GetThreadState(aThread : TThreadID) : TThreadState;
  71. begin
  72. GetThreadState:=PWasmThread(aThread)^.State
  73. end;
  74. function WasiInitManager: Boolean;
  75. begin
  76. DebugWriteln('Initializing manager');
  77. if TLSInfoBlock=Nil then
  78. TLSInfoBlock:=AllocateOSInfoBlock;
  79. if TLSInfoBlock = Nil then
  80. DebugWriteln('Initializing manager done: failed');
  81. WasiInitManager:=True;
  82. end;
  83. function WasiDoneManager: Boolean;
  84. begin
  85. WasiDoneManager:=True;
  86. end;
  87. { ----------------------------------------------------------------------
  88. Critical section (mutex)
  89. ----------------------------------------------------------------------}
  90. procedure WasiInitCriticalSection(var cs);
  91. begin
  92. InitMutex(TWasmMutex(CS));
  93. end;
  94. procedure WasiDoneCriticalSection(var cs);
  95. begin
  96. DoneMutex(TWasmMutex(CS));
  97. end;
  98. procedure WasiEnterCriticalSection(var cs);
  99. begin
  100. LockMutex(TWasmMutex(CS));
  101. end;
  102. function WasiCriticalSectionTryEnter(var cs):longint;
  103. begin
  104. WasiCriticalSectionTryEnter:=Ord(TryLockMutex(TWasmMutex(CS)))
  105. end;
  106. procedure WasiLeaveCriticalSection(var cs);
  107. begin
  108. UnLockMutex(TWasmMutex(CS));
  109. end;
  110. { ----------------------------------------------------------------------
  111. RTL event
  112. ----------------------------------------------------------------------}
  113. function WasiRTLCreateEvent:PRTLEvent;
  114. Var
  115. P : PWasmRTLEvent;
  116. begin
  117. New(P);
  118. P^.Signal:=0;
  119. P^.Destroying:=False;
  120. InitMutex(P^.Mutex);
  121. end;
  122. procedure WasiRTLEventSetEvent(AEvent:PRTLEvent);
  123. Var
  124. P : PWasmRTLEvent absolute aEvent;
  125. a : longint;
  126. begin
  127. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventSetEvent : locking mutex');{$ENDIF}
  128. LockMutex(P^.Mutex);
  129. P^.Signal:=1;
  130. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventSetEvent : unlocking mutex');{$ENDIF}
  131. UnLockMutex(P^.Mutex);
  132. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventSetEvent : send signal');{$ENDIF}
  133. a:=fpc_wasm32_memory_atomic_notify(@(P^.Signal),MaxThreadSignal);
  134. end;
  135. procedure WasiRTLEventDestroy(AEvent:PRTLEvent);
  136. Var
  137. P : PWasmRTLEvent absolute aEvent;
  138. begin
  139. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventDestroy : locking mutex');{$ENDIF}
  140. LockMutex(P^.Mutex);
  141. P^.Destroying:=True;
  142. UnlockMutex(P^.Mutex);
  143. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventDestroy : setting event to notify others');{$ENDIF}
  144. WasiRTLEventSetEvent(aEvent);
  145. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventDestroy : set event to notify others');{$ENDIF}
  146. FreeMem(P);
  147. end;
  148. procedure WasiRTLEventResetEvent(AEvent:PRTLEvent);
  149. Var
  150. P : PWasmRTLEvent absolute aEvent;
  151. begin
  152. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventResetEvent : locking mutex');{$ENDIF}
  153. LockMutex(P^.Mutex);
  154. P^.Signal:=0;
  155. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventResetEvent : unlocking mutex');{$ENDIF}
  156. UnLockMutex(P^.Mutex);
  157. end;
  158. procedure WasiRTLEventWaitFor_WaitAllowed(AEvent:PWasmRTLEvent; aTimeoutMs : Longint);
  159. Var
  160. a : Longint;
  161. begin
  162. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventWaitFor_WaitAllowed : waiting');{$ENDIF}
  163. a:=fpc_wasm32_memory_atomic_wait32(@(aEvent^.Signal),1,aTimeoutMs*1000);
  164. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventWaitFor_WaitAllowed : done');{$ENDIF}
  165. end;
  166. procedure WasiRTLEventWaitFor_WaitNotAllowed(AEvent:PWasmRTLEvent; aTimeoutMs : Longint);
  167. Var
  168. EndTime : Int64;
  169. IsTimeOut : Boolean;
  170. IsDone : Boolean;
  171. isMain : Boolean;
  172. begin
  173. IsMain:=GlobalIsMainThread<>0;
  174. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventWaitFor_WaitNotAllowed : waiting (is main: '+intToStr(Ord(IsMain))+')');{$ENDIF}
  175. EndTime:=GetClockTime+aTimeoutMs*1000;
  176. Repeat
  177. IsTimeOut:=(aTimeOutMS<>0) and (GetClockTime>EndTime);
  178. IsDone:=(aEvent^.Signal=1) or (aEvent^.Destroying) or (Not IsMain and (GetThreadState(GetSelfThread)<>tsRunning));
  179. Until isTimeOut or IsDone;
  180. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRTLEventWaitFor_WaitNotAllowed : done waiting');{$ENDIF}
  181. end;
  182. procedure WasiRTLEventWaitFor(AEvent:PRTLEvent);
  183. Var
  184. P : PWasmRTLEvent absolute aEvent;
  185. begin
  186. if IsWaitAllowed then
  187. WasiRTLEventWaitFor_WaitAllowed(P,0)
  188. else
  189. WasiRTLEventWaitFor_WaitNotAllowed(P,0);
  190. end;
  191. procedure WasiRTLEventWaitForTimeout(AEvent:PRTLEvent;timeout : longint);
  192. Var
  193. P : PWasmRTLEvent absolute aEvent;
  194. begin
  195. if IsWaitAllowed then
  196. WasiRTLEventWaitFor_WaitAllowed(P,TimeOut)
  197. else
  198. WasiRTLEventWaitFor_WaitNotAllowed(P,TimeOut);
  199. end;
  200. { ----------------------------------------------------------------------
  201. Thread
  202. ----------------------------------------------------------------------}
  203. procedure FPCWasmThreadSetStackPointer(Address: Pointer); [public, alias: 'FPC_WASM_THREAD_SET_STACK_POINTER'];
  204. begin
  205. fpc_wasm32_set_base_pointer(Address);
  206. end;
  207. // Javascript definition: TThreadInitInstanceFunction = Function(IsWorkerThread : Longint; IsMainThread : Integer; CanBlock : Integer) : Integer;
  208. Function FPCWasmThreadInit(IsWorkerThread : Longint; IsMainThread : Longint; CanBlock : Longint) : Longint; [public, alias: 'FPC_WASM_THREAD_INIT'];
  209. begin
  210. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FPCWasmThreadInit('+IntToStr(IsWorkerThread)+','+IntToStr(IsMainThread)+','+IntToStr(CanBlock)+')');{$ENDIF}
  211. GlobalIsWorkerThread:=IsWorkerThread;
  212. GlobalIsMainThread:=IsMainThread;
  213. GlobalIsThreadBlockable:=CanBlock;
  214. Result:=0;
  215. end;
  216. procedure WasiAllocateThreadVars; forward;
  217. // Javascript definition: TThreadEntryFunction = Function(ThreadId : Longint; RunFunction : Longint; Args : LongInt) : Longint;
  218. Function FPCWasmThreadEntry(ThreadID : PWasmThread; RunFunction : Pointer; Args : Pointer) : Longint; [public, alias: 'FPC_WASM_THREAD_ENTRY'];
  219. begin
  220. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FPCWasmThreadEntry('+IntToStr(PtrUint(ThreadID))+','+IntToStr(PtrUint(RunFunction))+','+IntToStr(PtrUint(Args))+')');{$ENDIF}
  221. GlobalCurrentThread:=ThreadID;
  222. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FPCWasmThreadEntry: allocating threadvars (thread function: '+intToStr(PtrUint(RunFunction))+')');{$ENDIF}
  223. WasiAllocateThreadVars;
  224. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FPCWasmThreadEntry: calling initthread (thread function: '+intToStr(PtrUint(RunFunction))+')');{$ENDIF}
  225. InitThread;
  226. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FPCWasmThreadEntry: calling thread function '+intToStr(PtrUint(RunFunction)));{$ENDIF}
  227. Result:=tthreadfunc(RunFunction)(args);
  228. end;
  229. exports FPCWasmThreadSetStackPointer, FPCWasmThreadInit, FPCWasmThreadEntry;
  230. Function thread_spawn(thread_id : PInteger; attrs: Pointer; thread_start_func : Pointer; args : Pointer) : LongInt; external 'FPCThreading' name 'thread_spawn';
  231. function WasiBeginThread(sa : Pointer;stacksize : PtrUInt; ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
  232. Var
  233. T : PWasmThread;
  234. begin
  235. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread(sa: '+IntToStr(PtrUint(Sa))+',ss: '+IntToStr(PtrUint(StackSize))+',TF: '+IntToStr(PtrUint(ThreadFunction))+',Arg: '+IntToStr(PtrUint(P))+',fl: '+IntToStr(PtrUint(CreationFlags))+',ID: '+IntToStr(PtrUint(ThreadID))+')');{$ENDIF}
  236. T:=GetMem(SizeOf(TWasmThread));
  237. ThreadID:=T;
  238. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread thread ID : '+IntToStr(PtrUint(ThreadID)));{$ENDIF}
  239. InitMutex(T^.Running,mkNormal);
  240. T^.DoneEvent:=WasiRTLCreateEvent;
  241. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread: Locked mutex');{$ENDIF}
  242. if thread_spawn(@(T^.ID),Nil,ThreadFunction,P)=0 then
  243. begin
  244. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread: spawn thread OK, setting result');{$ENDIF}
  245. WasiBeginThread:=T;
  246. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread: spawn thread OK, done setting result');{$ENDIF}
  247. end
  248. else
  249. begin
  250. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread: spawn thread failed');{$ENDIF}
  251. FreeMem(T);
  252. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread: spawn thread failed, freeing thread struct');{$ENDIF}
  253. WasiBeginThread:=TThreadID(0);
  254. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiBeginThread: spawn thread failed, returning 0');{$ENDIF}
  255. end
  256. end;
  257. procedure WasiEndThread(ExitCode : DWord);
  258. Var
  259. T : PWasmThread;
  260. begin
  261. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('EndThread('+IntToStr(ExitCode)+')');{$ENDIF}
  262. T:=PWasmThread(GetSelfThread);
  263. T^.ExitCode:=ExitCode;
  264. // Signal that we're done
  265. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('EndThread: Signaling end of thread');{$ENDIF}
  266. WasiRTLEventSetEvent(T^.DoneEvent);
  267. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('EndThread: Unlocking mutex');{$ENDIF}
  268. // Now unlock running mutex
  269. UnlockMutex(T^.Running);
  270. end;
  271. function WasiSuspendThread(threadHandle : TThreadID) : dword;
  272. begin
  273. WasiSuspendThread:=DWord(-1);
  274. end;
  275. function WasiResumeThread(threadHandle : TThreadID) : dword;
  276. begin
  277. WasiResumeThread:=DWord(-1);
  278. end;
  279. function WasiKillThread(threadHandle : TThreadID) : dword;
  280. begin
  281. WasiKillThread:=DWord(-1);
  282. end;
  283. function WasiCloseThread(threadHandle : TThreadID) : dword;
  284. begin
  285. Result:=0;
  286. end;
  287. procedure WasiThreadSwitch;
  288. begin
  289. // Normally a yield, but this does not (yet) exist in webassembly.
  290. {todo:implement}
  291. end;
  292. function WasiWaitForThreadTerminate(threadHandle : TThreadID; TimeoutMs : longint) : dword;
  293. Var
  294. Res : Integer;
  295. TH : PWasmThread absolute ThreadHandle;
  296. begin
  297. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WaitForThreadTerminate('+IntToStr(PtrUINT(TH))+','+IntToStr(TimeoutMs)+')');{$ENDIF}
  298. WasiRTLEventWaitFor(TH^.DoneEvent);
  299. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WaitForThreadTerminate('+IntToStr(PtrUINT(TH))+') : Event set, waiting for lock');{$ENDIF}
  300. Case LockMuTexTimeout(PWasmThread(ThreadHandle)^.Running,TimeoutMS) of
  301. lmrOK : Res:=0;
  302. lmrError : Res:=-2;
  303. else
  304. Res:=-1;
  305. end;
  306. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WaitForThreadTerminate('+IntToStr(PtrUINT(TH))+') : Got Lock');{$ENDIF}
  307. UnLockMuTex(PWasmThread(ThreadHandle)^.Running);
  308. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WaitForThreadTerminate('+IntToStr(PtrUINT(TH))+') : Lock released');{$ENDIF}
  309. WasiWaitForThreadTerminate:=DWord(Res);
  310. end;
  311. function WasiThreadSetPriority(threadHandle : TThreadID; Prio: longint): boolean;
  312. begin
  313. Result:=False;
  314. end;
  315. function WasiThreadGetPriority(threadHandle : TThreadID): longint;
  316. begin
  317. Result:=0;
  318. end;
  319. function WasiGetCurrentThreadId : TThreadID;
  320. begin
  321. Result:=GetSelfThread;
  322. end;
  323. procedure WasiThreadSetThreadDebugNameA(threadHandle: TThreadID; const ThreadName: AnsiString);
  324. Var
  325. P : PWasmThread absolute ThreadHandle;
  326. Len : Integer;
  327. begin
  328. Len:=Length(ThreadName);
  329. SetLength(P^.ThreadName,Len);
  330. if Len>0 then
  331. Move(ThreadName[1],P^.ThreadName[0],Len);
  332. end;
  333. {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
  334. procedure WasiThreadSetThreadDebugNameU(threadHandle: TThreadID; const ThreadName: UnicodeString);
  335. Var
  336. P : PWasmThread absolute ThreadHandle;
  337. LThreadName : RawBytestring;
  338. Len : Integer;
  339. begin
  340. Len:=Length(LThreadName);
  341. LThreadName:=Utf8Encode(ThreadName);
  342. SetLength(P^.ThreadName,Len*SizeOf(UnicodeChar));
  343. if Len>0 then
  344. Move(LThreadName[1],P^.ThreadName[0],Len*SizeOf(UnicodeChar));
  345. end;
  346. {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
  347. { ----------------------------------------------------------------------
  348. Threadvars
  349. ----------------------------------------------------------------------}
  350. Var
  351. threadvarblocksize : PtrUint;
  352. procedure WasiInitThreadVar(var offset : dword;size : dword);
  353. begin
  354. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiInitThreadVar('+IntToStr(offset)+','+IntToStr(size)+')');{$ENDIF}
  355. threadvarblocksize:=align(threadvarblocksize, fpc_wasm32_tls_align);
  356. offset:=threadvarblocksize;
  357. inc(threadvarblocksize,size);
  358. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Done WasiInitThreadVar. Total size: '+IntToStr(threadvarblocksize));{$ENDIF}
  359. end;
  360. procedure WasiAllocateThreadVars;
  361. var
  362. tlsMemBlock : pointer;
  363. tlsBlockSize : Integer;
  364. P : POSMemBlock;
  365. begin
  366. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiAllocateThreadVars');{$ENDIF}
  367. tlsBlockSize:=fpc_wasm32_tls_size;
  368. if threadvarblocksize<>tlsBlocksize then
  369. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Warning : block sizes differ: (linker) '+IntToStr(tlsBlocksize)+'<>'+IntToStr(threadvarblocksize)+' (calculated) !');{$ENDIF}
  370. P:=GetFreeOSBlock;
  371. FillChar((P^.Data)^.TLSMemory,tlsBlockSize,0);
  372. fpc_wasm32_init_tls(@((P^.Data)^.TLSMemory));
  373. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('Done WasiAllocateThreadVars');{$ENDIF}
  374. end;
  375. Function GetTLSMemory : Pointer;
  376. begin
  377. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetTLSMemory Enter');{$ENDIF}
  378. GetTLSMemory:=fpc_wasm32_tls_base();
  379. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetTLSMemory exit: '+InttoStr(PtrUint(fpc_wasm32_tls_base())));{$ENDIF}
  380. end;
  381. procedure WasiReleaseThreadVars;
  382. Var
  383. PTLS : PTLSMem;
  384. begin
  385. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiReleaseThreadVars');{$ENDIF}
  386. PTLS:=GetTLSMemory-Sizeof(Pointer);
  387. ReleaseOSBlock(PTLS^.OSMemBlock);
  388. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiReleaseThreadVars done');{$ENDIF}
  389. end;
  390. procedure HookThread;
  391. { Set up externally created thread }
  392. begin
  393. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('HookThread');{$ENDIF}
  394. WasiAllocateThreadVars;
  395. InitThread(1000000000);
  396. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('HookThread done');{$ENDIF}
  397. end;
  398. function WasiRelocateThreadVar(offset : dword) : pointer;
  399. var
  400. P : Pointer;
  401. begin
  402. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRelocateThreadVar ('+IntToStr(offset)+')');{$ENDIF}
  403. P:=GetTLSMemory;
  404. if (P=Nil) then
  405. begin
  406. HookThread;
  407. P:=GetTLSMemory;
  408. end;
  409. WasiRelocateThreadvar:=P+Offset;
  410. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('WasiRelocateThreadVar done. Result: '+IntToStr(PtrUint(P+Offset)));{$ENDIF}
  411. end;
  412. { ----------------------------------------------------------------------
  413. Basic event
  414. ----------------------------------------------------------------------}
  415. function WasiBasicEventCreate(EventAttributes :Pointer; AManualReset,InitialState : Boolean;const Name:ansistring):pEventState;
  416. begin
  417. {todo:implement}
  418. end;
  419. procedure WasiBasicEventDestroy(state:peventstate);
  420. begin
  421. {todo:implement}
  422. end;
  423. procedure WasiBasicEventResetEvent(state:peventstate);
  424. begin
  425. {todo:implement}
  426. end;
  427. procedure WasiBasicEventSetEvent(state:peventstate);
  428. begin
  429. {todo:implement}
  430. end;
  431. function WasiBasicEventWaitFor(timeout:cardinal;state:peventstate;FUseComWait : Boolean=False):longint;
  432. begin
  433. {todo:implement}
  434. end;
  435. procedure InitSystemThreads;public name '_FPC_InitSystemThreads';
  436. begin
  437. with WasiThreadManager do
  438. begin
  439. InitManager := @WasiInitManager;
  440. DoneManager := @WasiDoneManager;
  441. BeginThread := @WasiBeginThread;
  442. EndThread := @WasiEndThread;
  443. SuspendThread := @WasiSuspendThread;
  444. ResumeThread := @WasiResumeThread;
  445. KillThread := @WasiKillThread;
  446. CloseThread := @WasiCloseThread;
  447. ThreadSwitch := @WasiThreadSwitch;
  448. WaitForThreadTerminate := @WasiWaitForThreadTerminate;
  449. ThreadSetPriority := @WasiThreadSetPriority;
  450. ThreadGetPriority := @WasiThreadGetPriority;
  451. GetCurrentThreadId := @WasiGetCurrentThreadId;
  452. SetThreadDebugNameA := @WasiThreadSetThreadDebugNameA;
  453. {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
  454. SetThreadDebugNameU := @WasiThreadSetThreadDebugNameU;
  455. {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
  456. InitCriticalSection := @WasiInitCriticalSection;
  457. DoneCriticalSection := @WasiDoneCriticalSection;
  458. EnterCriticalSection := @WasiEnterCriticalSection;
  459. TryEnterCriticalSection:= @WasiCriticalSectionTryEnter;
  460. LeaveCriticalSection := @WasiLeaveCriticalSection;
  461. InitThreadVar := @WasiInitThreadVar;
  462. RelocateThreadVar := @WasiRelocateThreadVar;
  463. AllocateThreadVars := @WasiAllocateThreadVars;
  464. ReleaseThreadVars := @WasiReleaseThreadVars;
  465. BasicEventCreate := @WasiBasicEventCreate;
  466. BasicEventDestroy := @WasiBasicEventDestroy;
  467. BasicEventResetEvent := @WasiBasicEventResetEvent;
  468. BasicEventSetEvent := @WasiBasicEventSetEvent;
  469. BasiceventWaitFOr := @WasiBasicEventWaitFor;
  470. RTLEventCreate := @WasiRTLCreateEvent;
  471. RTLEventDestroy := @WasiRTLEventDestroy;
  472. RTLEventSetEvent := @WasiRTLEventSetEvent;
  473. RTLEventResetEvent := @WasiRTLEventResetEvent;
  474. RTLEventWaitFor := @WasiRTLEventWaitFor;
  475. RTLEventWaitForTimeout := @WasiRTLEventWaitForTimeout;
  476. end;
  477. SetThreadManager(WasiThreadManager);
  478. end;