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