1{
2    This file is part of the Free Pascal Run time library.
3    Copyright (c) 2000 by the Free Pascal development team
4
5    OS independent thread functions/overloads
6
7    See the File COPYING.FPC, included in this distribution,
8    for details about the copyright.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 **********************************************************************}
15
16
17Var
18  CurrentTM : TThreadManager;
19{$ifndef THREADVAR_RELOCATED_ALREADY_DEFINED}
20  fpc_threadvar_relocate_proc : TRelocateThreadVarHandler; public name 'FPC_THREADVAR_RELOCATE';
21{$endif THREADVAR_RELOCATED_ALREADY_DEFINED}
22
23{$ifndef HAS_GETCPUCOUNT}
24    function GetCPUCount: LongWord;
25      begin
26        Result := 1;
27      end;
28{$endif}
29
30
31{*****************************************************************************
32                           Threadvar initialization
33*****************************************************************************}
34
35    procedure InitThread(stklen:SizeUInt);
36      begin
37{$ifndef FPUNONE}
38        SysResetFPU;
39        SysInitFPU;
40{$endif}
41{$ifndef HAS_MEMORYMANAGER}
42{$ifndef FPC_NO_DEFAULT_HEAP}
43        { initialize this thread's heap }
44        InitHeapThread;
45{$endif ndef FPC_NO_DEFAULT_HEAP}
46{$else HAS_MEMORYMANAGER}
47        if MemoryManager.InitThread <> nil then
48          MemoryManager.InitThread();
49{$endif HAS_MEMORYMANAGER}
50{$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
51        if assigned(widestringmanager.ThreadInitProc) then
52          widestringmanager.ThreadInitProc;
53{$endif FPC_HAS_FEATURE_WIDESTRINGS}
54{$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
55        { ExceptAddrStack and ExceptObjectStack are threadvars       }
56        { so every thread has its on exception handling capabilities }
57        SysInitExceptions;
58{$endif FPC_HAS_FEATURE_EXCEPTIONS}
59{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
60{$ifndef EMBEDDED}
61        { Open all stdio fds again }
62        SysInitStdio;
63        InOutRes:=0;
64        // ErrNo:=0;
65{$endif EMBEDDED}
66{$endif FPC_HAS_FEATURE_CONSOLEIO}
67{$ifdef FPC_HAS_FEATURE_STACKCHECK}
68        { Stack checking }
69        StackLength:= CheckInitialStkLen(stkLen);
70        StackBottom:=Sptr - StackLength;
71{$endif FPC_HAS_FEATURE_STACKCHECK}
72        ThreadID := CurrentTM.GetCurrentThreadID();
73      end;
74
75    procedure DoneThread;
76      begin
77{$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
78        if assigned(widestringmanager.ThreadFiniProc) then
79          widestringmanager.ThreadFiniProc;
80{$endif FPC_HAS_FEATURE_WIDESTRINGS}
81{$ifndef HAS_MEMORYMANAGER}
82{$ifndef FPC_NO_DEFAULT_HEAP}
83        FinalizeHeap;
84{$endif ndef FPC_NO_DEFAULT_HEAP}
85{$endif HAS_MEMORYMANAGER}
86        if MemoryManager.DoneThread <> nil then
87          MemoryManager.DoneThread();
88{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
89        { Open all stdio fds again }
90        SysFlushStdio;
91{$endif FPC_HAS_FEATURE_CONSOLEIO}
92        { Support platforms where threadvar memory is managed outside of the RTL:
93          reset ThreadID and allow ReleaseThreadVars to be unassigned }
94        ThreadID := TThreadID(0);
95        if assigned(CurrentTM.ReleaseThreadVars) then
96          CurrentTM.ReleaseThreadVars;
97      end;
98
99{*****************************************************************************
100                            Overloaded functions
101*****************************************************************************}
102
103    function BeginThread(ThreadFunction : tthreadfunc) : TThreadID;
104      var
105        dummy : TThreadID;
106      begin
107        BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,nil,0,dummy);
108      end;
109
110
111    function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : TThreadID;
112      var
113        dummy : TThreadID;
114      begin
115        BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,dummy);
116      end;
117
118
119    function BeginThread(ThreadFunction : tthreadfunc;p : pointer;var ThreadId : TThreadID) : TThreadID;
120      begin
121        BeginThread:=BeginThread(nil,DefaultStackSize,ThreadFunction,p,0,ThreadId);
122      end;
123
124    function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
125                     var ThreadId : TThreadID; const stacksize: SizeUInt) : TThreadID;
126      begin
127        BeginThread:=BeginThread(nil,stacksize,ThreadFunction,p,0,ThreadId);
128      end;
129
130    procedure EndThread;
131      begin
132        EndThread(0);
133      end;
134
135function BeginThread(sa : Pointer;stacksize : SizeUInt; ThreadFunction : tthreadfunc;p : pointer;creationFlags : dword;  var ThreadId : TThreadID) : TThreadID;
136
137begin
138  Result:=CurrentTM.BeginThread(sa,stacksize,threadfunction,P,creationflags,ThreadID);
139end;
140
141procedure FlushThread;
142
143begin
144{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
145  SysFlushStdio;
146{$endif FPC_HAS_FEATURE_CONSOLEIO}
147end;
148
149procedure EndThread(ExitCode : DWord);
150
151begin
152  CurrentTM.EndThread(ExitCode);
153end;
154
155function  SuspendThread (threadHandle : TThreadID) : dword;
156
157begin
158  Result:=CurrentTM.SuspendThread(ThreadHandle);
159end;
160
161function ResumeThread  (threadHandle : TThreadID) : dword;
162
163begin
164  Result:=CurrentTM.ResumeThread(ThreadHandle);
165end;
166
167function CloseThread  (threadHandle : TThreadID):dword;
168
169begin
170  result:=CurrentTM.CloseThread(ThreadHandle);
171end;
172
173procedure ThreadSwitch;
174
175begin
176  CurrentTM.ThreadSwitch;
177end;
178
179function  KillThread (threadHandle : TThreadID) : dword;
180
181begin
182  Result:=CurrentTM.KillThread(ThreadHandle);
183end;
184
185function  WaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;
186
187begin
188  Result:=CurrentTM.WaitForThreadTerminate(ThreadHandle,TimeOutMS);
189end;
190
191function  ThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean;
192begin
193  Result:=CurrentTM.ThreadSetPriority(ThreadHandle,Prio);
194end;
195
196function  ThreadGetPriority (threadHandle : TThreadID): longint;
197
198begin
199  Result:=CurrentTM.ThreadGetPriority(ThreadHandle);
200end;
201
202function  GetCurrentThreadId : TThreadID;
203
204begin
205  Result:=CurrentTM.GetCurrentThreadID();
206end;
207
208procedure SetThreadDebugName(threadHandle: TThreadID; const ThreadName: AnsiString);
209begin
210  CurrentTM.SetThreadDebugNameA(threadHandle, ThreadName);
211end;
212
213{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
214procedure SetThreadDebugName(threadHandle: TThreadID; const ThreadName: UnicodeString);
215begin
216  CurrentTM.SetThreadDebugNameU(threadHandle, ThreadName);
217end;
218{$endif FPC_HAS_FEATURE_UNICODESTRINGS}
219
220procedure InitCriticalSection(var cs : TRTLCriticalSection);
221
222begin
223  CurrentTM.InitCriticalSection(cs);
224end;
225
226procedure DoneCriticalSection(var cs : TRTLCriticalSection);
227
228begin
229  CurrentTM.DoneCriticalSection(cs);
230end;
231
232procedure EnterCriticalSection(var cs : TRTLCriticalSection);
233
234begin
235  CurrentTM.EnterCriticalSection(cs);
236end;
237
238function TryEnterCriticalSection(var cs : TRTLCriticalSection):longint;
239
240begin
241  result:=CurrentTM.TryEnterCriticalSection(cs);
242end;
243
244procedure LeaveCriticalSection(var cs : TRTLCriticalSection);
245
246begin
247  CurrentTM.LeaveCriticalSection(cs);
248end;
249
250Function GetThreadManager(Var TM : TThreadManager) : Boolean;
251
252begin
253  TM:=CurrentTM;
254  Result:=True;
255end;
256
257Function SetThreadManager(Const NewTM : TThreadManager; Var OldTM : TThreadManager) : Boolean;
258
259begin
260  GetThreadManager(OldTM);
261  Result:=SetThreadManager(NewTM);
262end;
263
264Function SetThreadManager(Const NewTM : TThreadManager) : Boolean;
265
266begin
267  Result:=True;
268  If Assigned(CurrentTM.DoneManager) then
269    Result:=CurrentTM.DoneManager();
270  If Result then
271    begin
272    CurrentTM:=NewTM;
273    If Assigned(CurrentTM.InitManager) then
274      Result:=CurrentTM.InitManager();
275    end;
276end;
277
278function  BasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
279
280begin
281  result:=currenttm.BasicEventCreate(EventAttributes,AManualReset,InitialState, Name);
282end;
283
284procedure BasicEventDestroy(state:peventstate);
285
286begin
287  currenttm.BasicEventDestroy(state);
288end;
289
290procedure BasicEventResetEvent(state:peventstate);
291
292begin
293  currenttm.BasicEventResetEvent(state);
294end;
295
296procedure BasicEventSetEvent(state:peventstate);
297
298begin
299  currenttm.BasicEventSetEvent(state);
300end;
301
302function  BasicEventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
303
304begin
305 result:=currenttm.BasicEventWaitFor(Timeout,state);
306end;
307
308function  RTLEventCreate :PRTLEvent;
309
310begin
311  result:=currenttm.RTLEventCreate();
312end;
313
314
315procedure RTLeventDestroy(state:pRTLEvent);
316
317begin
318  currenttm.RTLEventDestroy(state);
319end;
320
321procedure RTLeventSetEvent(state:pRTLEvent);
322
323begin
324  currenttm.RTLEventSetEvent(state);
325end;
326
327procedure RTLeventResetEvent(state:pRTLEvent);
328
329begin
330  currenttm.RTLEventResetEvent(state);
331end;
332
333procedure RTLeventWaitFor(state:pRTLEvent);
334
335begin
336  currenttm.RTLEventWaitFor(state);
337end;
338
339procedure RTLeventWaitFor(state:pRTLEvent;timeout : longint);
340
341begin
342  currenttm.RTLEventWaitForTimeout(state,timeout);
343end;
344
345{ ---------------------------------------------------------------------
346    ThreadManager which gives run-time error. Use if no thread support.
347  ---------------------------------------------------------------------}
348
349{$ifndef DISABLE_NO_THREAD_MANAGER}
350
351{ resourcestrings are not supported by the system unit,
352  they are in the objpas unit and not available for fpc/tp modes }
353const
354  SNoThreads = 'This binary has no thread support compiled in.';
355  SRecompileWithThreads = 'Recompile the application with a thread-driver in the program uses clause before other units using thread.';
356
357Procedure NoThreadError;
358
359begin
360{$ifndef EMBEDDED}
361{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
362  If IsConsole then
363    begin
364    Writeln(StdErr,SNoThreads);
365    Writeln(StdErr,SRecompileWithThreads);
366    end;
367{$endif FPC_HAS_FEATURE_CONSOLEIO}
368{$endif EMBEDDED}
369  RunError(232)
370end;
371
372function NoBeginThread(sa : Pointer;stacksize : PtrUInt;
373                     ThreadFunction : tthreadfunc;p : pointer;
374                     creationFlags : dword; var ThreadId : TThreadID) : TThreadID;
375begin
376  NoThreadError;
377  result:=tthreadid(-1);
378end;
379
380procedure NoEndThread(ExitCode : DWord);
381begin
382  NoThreadError;
383end;
384
385function  NoThreadHandler (threadHandle : TThreadID) : dword;
386begin
387  NoThreadError;
388  result:=dword(-1);
389end;
390
391function  NoWaitForThreadTerminate (threadHandle : TThreadID; TimeoutMs : longint) : dword;  {0=no timeout}
392begin
393  NoThreadError;
394  result:=dword(-1);
395end;
396
397function  NoThreadSetPriority (threadHandle : TThreadID; Prio: longint): boolean; {-15..+15, 0=normal}
398begin
399  NoThreadError;
400  result:=false;
401end;
402
403function  NoThreadGetPriority (threadHandle : TThreadID): longint;
404begin
405  NoThreadError;
406  result:=-1;
407end;
408
409function  NoGetCurrentThreadId : TThreadID;
410begin
411  if IsMultiThread then
412    NoThreadError
413  else
414    ThreadingAlreadyUsed:=true;
415  result:=TThreadID(1);
416end;
417
418procedure NoSetThreadDebugNameA(threadHandle: TThreadID; const ThreadName: AnsiString);
419begin
420  NoThreadError;
421end;
422
423{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
424procedure NoSetThreadDebugNameU(threadHandle: TThreadID; const ThreadName: UnicodeString);
425begin
426  NoThreadError;
427end;
428{$endif FPC_HAS_FEATURE_UNICODESTRINGS}
429
430procedure NoCriticalSection(var CS);
431
432begin
433  if IsMultiThread then
434    NoThreadError
435  else
436    ThreadingAlreadyUsed:=true;
437end;
438
439function NoTryEnterCriticalSection(var CS):longint;
440
441begin
442  if IsMultiThread then
443    NoThreadError
444  else
445    ThreadingAlreadyUsed:=true;
446  Result:=-1;
447end;
448
449procedure NoInitThreadvar(var offset : {$ifdef cpu16}word{$else}dword{$endif};size : dword);
450
451begin
452  NoThreadError;
453end;
454
455function NoRelocateThreadvar(offset : {$ifdef cpu16}word{$else}dword{$endif}) : pointer;
456
457begin
458  NoThreadError;
459  result:=nil;
460end;
461
462
463function  NoBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
464
465begin
466  if IsMultiThread then
467    NoThreadError
468  else
469    ThreadingAlreadyUsed:=true;
470  result:=nil;
471end;
472
473procedure NoBasicEvent(state:peventstate);
474
475begin
476  if IsMultiThread then
477    NoThreadError
478  else
479    ThreadingAlreadyUsed:=true;
480end;
481
482function  NoBasicEventWaitFor(Timeout : Cardinal;state:peventstate) : longint;
483
484begin
485  if IsMultiThread then
486    NoThreadError
487  else
488    ThreadingAlreadyUsed:=true;
489  result:=-1;
490end;
491
492function  NoRTLEventCreate :PRTLEvent;
493
494begin
495  if IsMultiThread then
496    NoThreadError
497  else
498    ThreadingAlreadyUsed:=true;
499  result:=nil;
500end;
501
502procedure NoRTLEvent(state:pRTLEvent);
503
504begin
505  if IsMultiThread then
506    NoThreadError
507  else
508    ThreadingAlreadyUsed:=true
509end;
510
511procedure NoRTLEventWaitForTimeout(state:pRTLEvent;timeout : longint);
512begin
513  if IsMultiThread then
514    NoThreadError
515  else
516    ThreadingAlreadyUsed:=true;
517end;
518
519
520const
521  NoThreadManager : TThreadManager = (
522         InitManager            : Nil;
523         DoneManager            : Nil;
524{$ifdef EMBEDDED}
525         { while this is pretty hacky, it reduces the size of typical embedded programs
526           and works fine on arm and avr }
527         BeginThread            : @NoBeginThread;
528         EndThread              : TEndThreadHandler(@NoThreadError);
529         SuspendThread          : TThreadHandler(@NoThreadError);
530         ResumeThread           : TThreadHandler(@NoThreadError);
531         KillThread             : TThreadHandler(@NoThreadError);
532         CloseThread            : TThreadHandler(@NoThreadError);
533         ThreadSwitch           : TThreadSwitchHandler(@NoThreadError);
534         WaitForThreadTerminate : TWaitForThreadTerminateHandler(@NoThreadError);
535         ThreadSetPriority      : TThreadSetPriorityHandler(@NoThreadError);
536         ThreadGetPriority      : TThreadGetPriorityHandler(@NoThreadError);
537         GetCurrentThreadId     : @NoGetCurrentThreadId;
538         SetThreadDebugNameA    : TThreadSetThreadDebugNameHandlerA(@NoThreadError);
539         {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
540         SetThreadDebugNameU    : TThreadSetThreadDebugNameHandlerU(@NoThreadError);
541         {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
542         InitCriticalSection    : TCriticalSectionHandler(@NoThreadError);
543         DoneCriticalSection    : TCriticalSectionHandler(@NoThreadError);
544         EnterCriticalSection   : TCriticalSectionHandler(@NoThreadError);
545         TryEnterCriticalSection: TCriticalSectionHandlerTryEnter(@NoThreadError);
546         LeaveCriticalSection   : TCriticalSectionHandler(@NoThreadError);
547         InitThreadVar          : TInitThreadVarHandler(@NoThreadError);
548         RelocateThreadVar      : TRelocateThreadVarHandler(@NoThreadError);
549         AllocateThreadVars     : @NoThreadError;
550         ReleaseThreadVars      : @NoThreadError;
551         BasicEventCreate       : TBasicEventCreateHandler(@NoThreadError);
552         BasicEventdestroy      : TBasicEventHandler(@NoThreadError);
553         BasicEventResetEvent   : TBasicEventHandler(@NoThreadError);
554         BasicEventSetEvent     : TBasicEventHandler(@NoThreadError);
555         BasicEventWaitFor      : TBasicEventWaitForHandler(@NoThreadError);
556         RTLEventCreate         : TRTLCreateEventHandler(@NoThreadError);
557         RTLEventdestroy        : TRTLEventHandler(@NoThreadError);
558         RTLEventSetEvent       : TRTLEventHandler(@NoThreadError);
559         RTLEventResetEvent     : TRTLEventHandler(@NoThreadError);
560         RTLEventWaitFor        : TRTLEventHandler(@NoThreadError);
561         RTLEventwaitfortimeout : TRTLEventHandlerTimeout(@NoThreadError);
562{$else EMBEDDED}
563         BeginThread            : @NoBeginThread;
564         EndThread              : @NoEndThread;
565         SuspendThread          : @NoThreadHandler;
566         ResumeThread           : @NoThreadHandler;
567         KillThread             : @NoThreadHandler;
568         CloseThread            : @NoThreadHandler;
569         ThreadSwitch           : @NoThreadError;
570         WaitForThreadTerminate : @NoWaitForThreadTerminate;
571         ThreadSetPriority      : @NoThreadSetPriority;
572         ThreadGetPriority      : @NoThreadGetPriority;
573         GetCurrentThreadId     : @NoGetCurrentThreadId;
574         SetThreadDebugNameA    : @NoSetThreadDebugNameA;
575         {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
576         SetThreadDebugNameU    : @NoSetThreadDebugNameU;
577         {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
578         InitCriticalSection    : @NoCriticalSection;
579         DoneCriticalSection    : @NoCriticalSection;
580         EnterCriticalSection   : @NoCriticalSection;
581         TryEnterCriticalSection: @NoTryEnterCriticalSection;
582         LeaveCriticalSection   : @NoCriticalSection;
583         InitThreadVar          : @NoInitThreadVar;
584         RelocateThreadVar      : @NoRelocateThreadVar;
585         AllocateThreadVars     : @NoThreadError;
586         ReleaseThreadVars      : @NoThreadError;
587         BasicEventCreate       : @NoBasicEventCreate;
588         BasicEventDestroy      : @NoBasicEvent;
589         BasicEventResetEvent   : @NoBasicEvent;
590         BasicEventSetEvent     : @NoBasicEvent;
591         BasicEventWaitFor      : @NoBasiceventWaitFor;
592         RTLEventCreate         : @NoRTLEventCreate;
593         RTLEventDestroy        : @NoRTLevent;
594         RTLEventSetEvent       : @NoRTLevent;
595         RTLEventResetEvent     : @NoRTLEvent;
596         RTLEventWaitFor        : @NoRTLEvent;
597         RTLEventWaitforTimeout : @NoRTLEventWaitForTimeout;
598{$endif EMBEDDED}
599      );
600
601Procedure SetNoThreadManager;
602
603begin
604  SetThreadManager(NoThreadManager);
605end;
606
607Procedure InitSystemThreads; public name '_FPC_InitSystemThreads';
608begin
609  { This should be changed to a real value during
610    thread driver initialization if appropriate. }
611  ThreadID := TThreadID(1);
612  SetNoThreadManager;
613end;
614
615{$endif DISABLE_NO_THREAD_MANAGER}
616