summaryrefslogtreecommitdiff
path: root/rtl/inc/thread.inc
blob: c4826960db55a2df823a96a476f100806bf50994 (plain)
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
{
    This file is part of the Free Pascal Run time library.
    Copyright (c) 2000 by the Free Pascal development team

    OS independent thread functions/overloads

    See the File COPYING.FPC, included in this distribution,
    for details about the copyright.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 **********************************************************************}


Var
  CurrentTM : TThreadManager;
{$ifndef THREADVAR_RELOCATED_ALREADY_DEFINED}
  fpc_threadvar_relocate_proc : TRelocateThreadVarHandler; public name 'FPC_THREADVAR_RELOCATE';
{$endif THREADVAR_RELOCATED_ALREADY_DEFINED}

{$ifndef HAS_GETCPUCOUNT}
    function GetCPUCount: LongWord;
      begin
        Result := 1;
      end;
{$endif}


{*****************************************************************************
                           Threadvar initialization
*****************************************************************************}

    procedure InitThread(stklen:SizeUInt);
      begin
{$ifndef FPUNONE}
        SysResetFPU;
        SysInitFPU;
{$endif}
{$ifndef HAS_MEMORYMANAGER}
{$ifndef FPC_NO_DEFAULT_HEAP}
        { initialize this thread's heap }
        InitHeapThread;
{$endif ndef FPC_NO_DEFAULT_HEAP}
{$else HAS_MEMORYMANAGER}
        if MemoryManager.InitThread <> nil then
          MemoryManager.InitThread();
{$endif HAS_MEMORYMANAGER}
{$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
        if assigned(widestringmanager.ThreadInitProc) then
          widestringmanager.ThreadInitProc;
{$endif FPC_HAS_FEATURE_WIDESTRINGS}
{$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
        { ExceptAddrStack and ExceptObjectStack are threadvars       }
        { so every thread has its on exception handling capabilities }
        SysInitExceptions;
{$endif FPC_HAS_FEATURE_EXCEPTIONS}
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
{$ifndef EMBEDDED}
        { Open all stdio fds again }
        SysInitStdio;
        InOutRes:=0;
        // ErrNo:=0;
{$endif EMBEDDED}
{$endif FPC_HAS_FEATURE_CONSOLEIO}
{$ifdef FPC_HAS_FEATURE_STACKCHECK}
        { Stack checking }
        StackLength:= CheckInitialStkLen(stkLen);
        StackBottom:=Sptr - StackLength;
{$endif FPC_HAS_FEATURE_STACKCHECK}
        ThreadID := CurrentTM.GetCurrentThreadID();
      end;

    procedure DoneThread;
      begin
{$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
        if assigned(widestringmanager.ThreadFiniProc) then
          widestringmanager.ThreadFiniProc;
{$endif FPC_HAS_FEATURE_WIDESTRINGS}
{$ifndef HAS_MEMORYMANAGER}
{$ifndef FPC_NO_DEFAULT_HEAP}
        FinalizeHeap;
{$endif ndef FPC_NO_DEFAULT_HEAP}
{$endif HAS_MEMORYMANAGER}
        if MemoryManager.DoneThread <> nil then
          MemoryManager.DoneThread();
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
        { Open all stdio fds again }
        SysFlushStdio;
{$endif FPC_HAS_FEATURE_CONSOLEIO}
        { Support platforms where threadvar memory is managed outside of the RTL:
          reset ThreadID and allow ReleaseThreadVars to be unassigned }
        ThreadID := TThreadID(0);
        if assigned(CurrentTM.ReleaseThreadVars) then
          CurrentTM.ReleaseThreadVars;
      end;


    procedure InitThread;
      begin
        { we should find a reasonable value here }
        InitThread($1000000);
      end;

{*****************************************************************************
                            Overloaded functions
*****************************************************************************}

    function BeginThread(ThreadFunction : tthreadfunc) : TThreadID;
      var
        dummy : TThreadID;
      begin
        BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,nil,0,dummy);
      end;


    function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : TThreadID;
      var
        dummy : TThreadID;
      begin
        BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,dummy);
      end;


    function BeginThread(ThreadFunction : tthreadfunc;p : pointer;var ThreadId : TThreadID) : TThreadID;
      begin
        BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,ThreadId);
      end;

    function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
                     var ThreadId : TThreadID; const stacksize: SizeUInt) : TThreadID;
      begin
        BeginThread:=BeginThread(nil,stacksize,ThreadFunction,p,0,ThreadId);
      end;

    procedure EndThread;
      begin
        EndThread(0);
      end;

function BeginThread(sa : Pointer;stacksize : SizeUInt; ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword;  var ThreadId : TThreadID) : TThreadID;

begin
  Result:=CurrentTM.BeginThread(sa,stacksize,threadfunction,P,creationflags,ThreadID);
end;

procedure FlushThread;

begin
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  SysFlushStdio;
{$endif FPC_HAS_FEATURE_CONSOLEIO}
end;

procedure EndThread(ExitCode : DWord);

begin
  CurrentTM.EndThread(ExitCode);
end;

function  SuspendThread (threadHandle : TThreadID) : dword;

begin
  Result:=CurrentTM.SuspendThread(ThreadHandle);
end;

function ResumeThread  (threadHandle : TThreadID) : dword;

begin
  Result:=CurrentTM.ResumeThread(ThreadHandle);
end;

function CloseThread  (threadHandle : TThreadID):dword;

begin
  result:=CurrentTM.CloseThread(ThreadHandle);
end;

procedure ThreadSwitch;

begin
  CurrentTM.ThreadSwitch;
end;

function  KillThread (threadHandle : TThreadID) : dword;

begin
  Result:=CurrentTM.KillThread(ThreadHandle);
end;

function  WaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;

begin
  Result:=CurrentTM.WaitForThreadTerminate(ThreadHandle,TimeOutMS);
end;

function  ThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean;
begin
  Result:=CurrentTM.ThreadSetPriority(ThreadHandle,Prio);
end;

function  ThreadGetPriority (threadHandle : TThreadID): longint;

begin
  Result:=CurrentTM.ThreadGetPriority(ThreadHandle);
end;

function  GetCurrentThreadId : TThreadID;

begin
  Result:=CurrentTM.GetCurrentThreadID();
end;

procedure SetThreadDebugName(threadHandle: TThreadID; const ThreadName: AnsiString);
begin
  CurrentTM.SetThreadDebugNameA(threadHandle, ThreadName);
end;

{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
procedure SetThreadDebugName(threadHandle: TThreadID; const ThreadName: UnicodeString);
begin
  CurrentTM.SetThreadDebugNameU(threadHandle, ThreadName);
end;
{$endif FPC_HAS_FEATURE_UNICODESTRINGS}

procedure InitCriticalSection(out cs : TRTLCriticalSection);

begin
  CurrentTM.InitCriticalSection(cs);
end;

procedure DoneCriticalSection(var cs : TRTLCriticalSection);

begin
  CurrentTM.DoneCriticalSection(cs);
end;

procedure EnterCriticalSection(var cs : TRTLCriticalSection);

begin
  CurrentTM.EnterCriticalSection(cs);
end;

function TryEnterCriticalSection(var cs : TRTLCriticalSection):longint;

begin
  result:=CurrentTM.TryEnterCriticalSection(cs);
end;

procedure LeaveCriticalSection(var cs : TRTLCriticalSection);

begin
  CurrentTM.LeaveCriticalSection(cs);
end;

Function GetThreadManager(Out TM : TThreadManager) : Boolean;

begin
  TM:=CurrentTM;
  Result:=True;
end;

Function SetThreadManager(Const NewTM : TThreadManager; Out OldTM : TThreadManager) : Boolean;

begin
  GetThreadManager(OldTM);
  Result:=SetThreadManager(NewTM);
end;

Function SetThreadManager(Const NewTM : TThreadManager) : Boolean;

begin
  Result:=True;
  If Assigned(CurrentTM.DoneManager) then
    Result:=CurrentTM.DoneManager();
  If Result then
    begin
    CurrentTM:=NewTM;
    If Assigned(CurrentTM.InitManager) then
      Result:=CurrentTM.InitManager();
    end;
end;

function  BasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;

begin
  result:=currenttm.BasicEventCreate(EventAttributes,AManualReset,InitialState, Name);
end;

procedure BasicEventDestroy(state:peventstate);

begin
  currenttm.BasicEventDestroy(state);
end;

procedure BasicEventResetEvent(state:peventstate);

begin
  currenttm.BasicEventResetEvent(state);
end;

procedure BasicEventSetEvent(state:peventstate);

begin
  currenttm.BasicEventSetEvent(state);
end;

function  BasicEventWaitFor(Timeout : Cardinal;state:peventstate) : longint;

begin
 result:=currenttm.BasicEventWaitFor(Timeout,state);
end;

function  RTLEventCreate :PRTLEvent;

begin
  result:=currenttm.RTLEventCreate();
end;


procedure RTLeventDestroy(state:pRTLEvent);

begin
  currenttm.RTLEventDestroy(state);
end;

procedure RTLeventSetEvent(state:pRTLEvent);

begin
  currenttm.RTLEventSetEvent(state);
end;

procedure RTLeventResetEvent(state:pRTLEvent);

begin
  currenttm.RTLEventResetEvent(state);
end;

procedure RTLeventWaitFor(state:pRTLEvent);

begin
  currenttm.RTLEventWaitFor(state);
end;

procedure RTLeventWaitFor(state:pRTLEvent;timeout : longint);

begin
  currenttm.RTLEventWaitForTimeout(state,timeout);
end;

{ ---------------------------------------------------------------------
    lazy thread initialization support
  ---------------------------------------------------------------------}

type
  PLazyInitThreadingProcInfo = ^TLazyInitThreadingProcInfo;
  TLazyInitThreadingProcInfo = Record
    Next     : PLazyInitThreadingProcInfo;
    Proc     : TProcedure;
  End;
const
  LazyInitThreadingProcList: PLazyInitThreadingProcInfo = nil;

procedure FinalizeLazyInitThreading;
var
  p: PLazyInitThreadingProcInfo;
begin
  while assigned(LazyInitThreadingProcList) do
    begin
    p:=LazyInitThreadingProcList^.Next;
    Dispose(LazyInitThreadingProcList);
    LazyInitThreadingProcList:=p;
    end;
end;

procedure RegisterLazyInitThreadingProc(const proc: TProcedure);
var
  p: PLazyInitThreadingProcInfo;
begin
  if IsMultiThread then
    begin
    { multithreading is already enabled - execute directly }
    proc();
    end
  else
    begin
    if not assigned(LazyInitThreadingProcList) then
      AddExitProc(@FinalizeLazyInitThreading);
    new(p);
    p^.Next:=LazyInitThreadingProcList;
    p^.Proc:=proc;
    LazyInitThreadingProcList:=p;
    end;
end;

procedure LazyInitThreading;
var
  p: PLazyInitThreadingProcInfo;
begin
  p:=LazyInitThreadingProcList;
  while assigned(p) do
    begin
    p^.Proc();
    p:=p^.Next;
    end;
end;

{ ---------------------------------------------------------------------
    ThreadManager which gives run-time error. Use if no thread support.
  ---------------------------------------------------------------------}

{$ifndef DISABLE_NO_THREAD_MANAGER}

{ resourcestrings are not supported by the system unit,
  they are in the objpas unit and not available for fpc/tp modes }
const
  SNoThreads = 'This binary has no thread support compiled in.';
  SRecompileWithThreads = 'Recompile the application with a thread-driver in the program uses clause before other units using thread.';

Procedure NoThreadError;

begin
{$ifndef EMBEDDED}
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  If IsConsole then
    begin
    Writeln(StdErr,SNoThreads);
    Writeln(StdErr,SRecompileWithThreads);
    end;
{$endif FPC_HAS_FEATURE_CONSOLEIO}
{$endif EMBEDDED}
  RunError(232)
end;

function NoBeginThread(sa : Pointer;stacksize : PtrUInt;
                     ThreadFunction : tthreadfunc;p : pointer;
                     creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
begin
  NoThreadError;
  result:=tthreadid(-1);
end;

procedure NoEndThread(ExitCode : DWord);
begin
  NoThreadError;
end;

function  NoThreadHandler (threadHandle : TThreadID) : dword;
begin
  NoThreadError;
  result:=dword(-1);
end;

function  NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;  {0=no timeout}
begin
  NoThreadError;
  result:=dword(-1);
end;

function  NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
begin
  NoThreadError;
  result:=false;
end;

function  NoThreadGetPriority (threadHandle : TThreadID): longint;
begin
  NoThreadError;
  result:=-1;
end;

function  NoGetCurrentThreadId : TThreadID;
begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
  result:=TThreadID(1);
end;

procedure NoSetThreadDebugNameA(threadHandle: TThreadID; const ThreadName: AnsiString);
begin
  NoThreadError;
end;

{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
procedure NoSetThreadDebugNameU(threadHandle: TThreadID; const ThreadName: UnicodeString);
begin
  NoThreadError;
end;
{$endif FPC_HAS_FEATURE_UNICODESTRINGS}

procedure NoCriticalSection(var CS);

begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
end;

function NoTryEnterCriticalSection(var CS):longint;

begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
  Result:=-1;
end;

procedure NoInitThreadvar(var offset : {$ifdef cpu16}word{$else}dword{$endif};size : dword);

begin
  NoThreadError;
end;

function NoRelocateThreadvar(offset : {$ifdef cpu16}word{$else}dword{$endif}) : pointer;

begin
  NoThreadError;
  result:=nil;
end;


function  NoBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;

begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
  result:=nil;
end;

procedure NoBasicEvent(state:peventstate);

begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
end;

function  NoBasicEventWaitFor(Timeout : Cardinal;state:peventstate) : longint;

begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
  result:=-1;
end;

function  NoRTLEventCreate :PRTLEvent;

begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
  result:=nil;
end;

procedure NoRTLEvent(state:pRTLEvent);

begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true
end;

procedure NoRTLEventWaitForTimeout(state:pRTLEvent;timeout : longint);
begin
  if IsMultiThread then
    NoThreadError
  else
    ThreadingAlreadyUsed:=true;
end;


const
  NoThreadManager : TThreadManager = (
         InitManager            : Nil;
         DoneManager            : Nil;
{$ifdef EMBEDDED}
         { while this is pretty hacky, it reduces the size of typical embedded programs
           and works fine on arm and avr }
         BeginThread            : @NoBeginThread;
         EndThread              : TEndThreadHandler(@NoThreadError);
         SuspendThread          : TThreadHandler(@NoThreadError);
         ResumeThread           : TThreadHandler(@NoThreadError);
         KillThread             : TThreadHandler(@NoThreadError);
         CloseThread            : TThreadHandler(@NoThreadError);
         ThreadSwitch           : TThreadSwitchHandler(@NoThreadError);
         WaitForThreadTerminate : TWaitForThreadTerminateHandler(@NoThreadError);
         ThreadSetPriority      : TThreadSetPriorityHandler(@NoThreadError);
         ThreadGetPriority      : TThreadGetPriorityHandler(@NoThreadError);
         GetCurrentThreadId     : @NoGetCurrentThreadId;
         SetThreadDebugNameA    : TThreadSetThreadDebugNameHandlerA(@NoThreadError);
         {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
         SetThreadDebugNameU    : TThreadSetThreadDebugNameHandlerU(@NoThreadError);
         {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
         InitCriticalSection    : TCriticalSectionHandler(@NoThreadError);
         DoneCriticalSection    : TCriticalSectionHandler(@NoThreadError);
         EnterCriticalSection   : TCriticalSectionHandler(@NoThreadError);
         TryEnterCriticalSection: TCriticalSectionHandlerTryEnter(@NoThreadError);
         LeaveCriticalSection   : TCriticalSectionHandler(@NoThreadError);
         InitThreadVar          : TInitThreadVarHandler(@NoThreadError);
         RelocateThreadVar      : TRelocateThreadVarHandler(@NoThreadError);
         AllocateThreadVars     : @NoThreadError;
         ReleaseThreadVars      : @NoThreadError;
         BasicEventCreate       : TBasicEventCreateHandler(@NoThreadError);
         BasicEventdestroy      : TBasicEventHandler(@NoThreadError);
         BasicEventResetEvent   : TBasicEventHandler(@NoThreadError);
         BasicEventSetEvent     : TBasicEventHandler(@NoThreadError);
         BasicEventWaitFor      : TBasicEventWaitForHandler(@NoThreadError);
         RTLEventCreate         : TRTLCreateEventHandler(@NoThreadError);
         RTLEventdestroy        : TRTLEventHandler(@NoThreadError);
         RTLEventSetEvent       : TRTLEventHandler(@NoThreadError);
         RTLEventResetEvent     : TRTLEventHandler(@NoThreadError);
         RTLEventWaitFor        : TRTLEventHandler(@NoThreadError);
         RTLEventwaitfortimeout : TRTLEventHandlerTimeout(@NoThreadError);
{$else EMBEDDED}
         BeginThread            : @NoBeginThread;
         EndThread              : @NoEndThread;
         SuspendThread          : @NoThreadHandler;
         ResumeThread           : @NoThreadHandler;
         KillThread             : @NoThreadHandler;
         CloseThread            : @NoThreadHandler;
         ThreadSwitch           : @NoThreadError;
         WaitForThreadTerminate : @NoWaitForThreadTerminate;
         ThreadSetPriority      : @NoThreadSetPriority;
         ThreadGetPriority      : @NoThreadGetPriority;
         GetCurrentThreadId     : @NoGetCurrentThreadId;
         SetThreadDebugNameA    : @NoSetThreadDebugNameA;
         {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
         SetThreadDebugNameU    : @NoSetThreadDebugNameU;
         {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
         InitCriticalSection    : @NoCriticalSection;
         DoneCriticalSection    : @NoCriticalSection;
         EnterCriticalSection   : @NoCriticalSection;
         TryEnterCriticalSection: @NoTryEnterCriticalSection;
         LeaveCriticalSection   : @NoCriticalSection;
         InitThreadVar          : @NoInitThreadVar;
         RelocateThreadVar      : @NoRelocateThreadVar;
         AllocateThreadVars     : @NoThreadError;
         ReleaseThreadVars      : @NoThreadError;
         BasicEventCreate       : @NoBasicEventCreate;
         BasicEventDestroy      : @NoBasicEvent;
         BasicEventResetEvent   : @NoBasicEvent;
         BasicEventSetEvent     : @NoBasicEvent;
         BasicEventWaitFor      : @NoBasiceventWaitFor;
         RTLEventCreate         : @NoRTLEventCreate;
         RTLEventDestroy        : @NoRTLevent;
         RTLEventSetEvent       : @NoRTLevent;
         RTLEventResetEvent     : @NoRTLEvent;
         RTLEventWaitFor        : @NoRTLEvent;
         RTLEventWaitforTimeout : @NoRTLEventWaitForTimeout;
{$endif EMBEDDED}
      );

Procedure SetNoThreadManager;

begin
  SetThreadManager(NoThreadManager);
end;

Procedure InitSystemThreads; public name '_FPC_InitSystemThreads';
begin
  { This should be changed to a real value during
    thread driver initialization if appropriate. }
  ThreadID := TThreadID(1);
  SetNoThreadManager;
end;

{$endif DISABLE_NO_THREAD_MANAGER}