123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- {
- $Id$
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2000 by the Free Pascal development team.
- Multithreading implementation for OS/2
- 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.
- **********************************************************************}
- {$IFDEF MT}
- const
- ThreadVarBlockSize: dword = 0;
- pag_Read = 1;
- pag_Write = 2;
- pag_Execute = 4;
- pag_Guard = 8;
- pag_Commit = $10;
- obj_Tile = $40;
- sem_Indefinite_Wait = -1;
- dtSuspended = 1;
- dtStack_Commited = 2;
- type
- TThreadInfo = record
- F: TThreadFunc;
- P: pointer;
- end;
- PThreadInfo = ^TThreadInfo;
- var
- (* Pointer to an allocated dword space within the local thread *)
- (* memory area. Pointer to the real memory block allocated for *)
- (* thread vars in this block is then stored in this dword. *)
- DataIndex: PPointer;
- { import the necessary stuff from the OS }
- function DosAllocThreadLocalMemory (Count: cardinal; var P: pointer): cardinal;
- cdecl; external 'DOSCALLS' index 454;
- function DosFreeThreadLocalMemory (P: pointer): cardinal; cdecl;
- external 'DOSCALLS' index 455;
- function DosCreateThread (var TID: cardinal; Address: pointer;
- (* TThreadFunc *)
- aParam: pointer; Flags: cardinal; StackSize: cardinal): cardinal; cdecl;
- external 'DOSCALLS' index 311;
- procedure DosExit (Action, Result: cardinal); cdecl;
- external 'DOSCALLS' index 234;
- function DosCreateMutExSem (Name: PChar; var Handle: longint; Attr: cardinal;
- State: boolean): cardinal; cdecl; external 'DOSCALLS' index 331;
- function DosCloseMutExSem (Handle: longint): cardinal; cdecl;
- external 'DOSCALLS' index 333;
- function DosQueryMutExSem (Handle: longint; var PID, TID, Count: cardinal):
- cardinal; cdecl; external 'DOSCALLS' index 336;
- function DosRequestMutExSem (Handle: longint; Timeout: cardinal): cardinal;
- cdecl; external 'DOSCALLS' index 334;
- function DosReleaseMutExSem (Handle: longint): cardinal; cdecl;
- external 'DOSCALLS' index 335;
- function DosAllocMem (var P: pointer; Size, Flag: cardinal): cardinal; cdecl;
- external 'DOSCALLS' index 299;
- function DosFreeMem (P: pointer): cardinal; cdecl;
- external 'DOSCALLS' index 304;
- function DosEnterCritSec:cardinal; cdecl; external 'DOSCALLS' index 232;
- function DosExitCritSec:cardinal; cdecl; external 'DOSCALLS' index 233;
- procedure Init_ThreadVar (var TVOffset: dword; Size: dword);
- [public, alias: 'FPC_INIT_THREADVAR'];
- begin
- TVOffset := ThreadVarBlockSize;
- Inc (ThreadVarBlockSize, Size);
- end;
- type ltvInitEntry =
- record
- varaddr : pdword;
- size : longint;
- end;
- pltvInitEntry = ^ltvInitEntry;
- procedure init_unit_threadvars (tableEntry : pltvInitEntry);
- begin
- while tableEntry^.varaddr <> nil do
- begin
- init_threadvar (tableEntry^.varaddr^, tableEntry^.size);
- inc (pchar (tableEntry), sizeof (tableEntry^));
- end;
- end;
- type TltvInitTablesTable =
- record
- count : dword;
- tables: array [1..32767] of pltvInitEntry;
- end;
- var
- ThreadvarTablesTable : TltvInitTablesTable; external name 'FPC_LOCALTHREADVARTABLES';
- procedure init_all_unit_threadvars; [public,alias: 'FPC_INITIALIZELOCALTHREADVARS'];
- var i : integer;
- begin
- {$ifdef DEBUG_MT}
- WriteLn ('init_all_unit_threadvars (%d) units',ThreadvarTablesTable.count);
- {$endif}
- for i := 1 to ThreadvarTablesTable.count do
- init_unit_threadvars (ThreadvarTablesTable.tables[i]);
- end;
- function Relocate_ThreadVar (TVOffset: dword): pointer;
- [public,alias: 'FPC_RELOCATE_THREADVAR'];
- begin
- Relocate_ThreadVar := DataIndex^ + TVOffset;
- end;
- procedure AllocateThreadVars;
- begin
- { we've to allocate the memory from the OS }
- { because the FPC heap management uses }
- { exceptions which use threadvars but }
- { these aren't allocated yet ... }
- { allocate room on the heap for the thread vars }
- if DosAllocMem (DataIndex^, ThreadVarBlockSize, pag_Read or pag_Write
- or pag_Commit) <> 0 then HandleError (8);
- end;
- procedure ReleaseThreadVars;
- begin
- { release thread vars }
- DosFreeMem (DataIndex^)
- end;
- procedure InitThread;
- begin
- InitFPU;
- { we don't need to set the data to 0 because we did this with }
- { the fillchar above, but it looks nicer }
- { ExceptAddrStack and ExceptObjectStack are threadvars }
- { so every thread has its on exception handling capabilities }
- InitExceptions;
- InOutRes := 0;
- { ErrNo := 0;}
- end;
- procedure DoneThread;
- var
- PTIB: PThreadInfoBlock;
- PPIB: PProcessInfoBlock;
- ThreadID: cardinal;
- begin
- ReleaseThreadVars;
- DosGetInfoBlocks (@PTIB, @PPIB);
- ThreadID := PTIB^.TIB2^.TID;
- end;
- function ThreadMain (Param: pointer): dword; cdecl;
- var
- TI: TThreadInfo;
- begin
- {$ifdef DEBUG_MT}
- WriteLn ('New thread started, initialising ...');
- {$endif DEBUG_MT}
- AllocateThreadVars;
- InitThread;
- TI := PThreadInfo (Param)^;
- Dispose (PThreadInfo (Param));
- {$ifdef DEBUG_MT}
- WriteLn ('Jumping to thread function');
- {$endif DEBUG_MT}
- ThreadMain := TI.F (TI.P);
- end;
- function BeginThread (SA: pointer; StackSize: dword;
- ThreadFunction: TThreadFunc; P: pointer; CreationFlags: dword;
- var ThreadID: dword): dword;
- var
- TI: PThreadInfo;
- begin
- {$ifdef DEBUG_MT}
- WriteLn ('Creating new thread');
- {$endif DEBUG_MT}
- IsMultiThread := true;
- { the only way to pass data to the newly created thread }
- { in a MT safe way, is to use the heap }
- New (TI);
- TI^.F := ThreadFunction;
- TI^.P := P;
- {$ifdef DEBUG_MT}
- WriteLn ('Starting new thread');
- {$endif DEBUG_MT}
- BeginThread := DosCreateThread (ThreadID, @ThreadMain, TI, CreationFlags,
- StackSize);
- end;
- function BeginThread (ThreadFunction: TThreadFunc): dword;
- var
- Dummy: dword;
- begin
- (* The stack size of 0 causes 4 kB to be allocated for stack. *)
- BeginThread := BeginThread (nil, 0, ThreadFunction, nil, dtStack_Commited,
- Dummy);
- end;
- function BeginThread (ThreadFunction: TThreadFunc; P: pointer): dword;
- var
- Dummy: dword;
- begin
- (* The stack size of 0 causes 4 kB to be allocated for stack. *)
- BeginThread := BeginThread (nil, 0, ThreadFunction, P, 0, Dummy);
- end;
- function BeginThread (ThreadFunction: TThreadFunc; P: pointer;
- var ThreadID: dword): dword;
- begin
- (* The stack size of 0 causes 4 kB to be allocated for stack. *)
- BeginThread := BeginThread (nil, 0, ThreadFunction, P, 0, ThreadID);
- end;
- procedure EndThread (ExitCode: dword);
- begin
- DoneThread;
- DosExit (0, ExitCode);
- end;
- procedure EndThread;
- begin
- EndThread (0);
- end;
- procedure InitCriticalSection (var CS: TRTLCriticalSection);
- begin
- if DosCreateMutExSem (nil, CS.LockSemaphore2, 0, true) <> 0 then
- HandleError (8);
- DosEnterCritSec;
- CS.LockCount := 0;
- CS.OwningThread := $FFFF;
- DosExitCritSec;
- DosReleaseMutexSem (CS.LockSemaphore2);
- end;
- procedure DoneCriticalSection (var CS: TRTLCriticalSection);
- begin
- DosCloseMutExSem (CS.LockSemaphore2);
- end;
- procedure EnterCriticalSection (var CS: TRTLCriticalSection);
- var
- P, T, Cnt: cardinal;
- PTIB: PThreadInfoBlock;
- PPIB: PProcessInfoBlock;
- begin
- DosGetInfoBlocks (@PTIB, @PPIB);
- DosEnterCritSec;
- with CS do if (LockCount = 0) and
- (DosQueryMutExSem (LockSemaphore2, P, T, Cnt) = 0) and (Cnt = 0) and
- (T = PTIB^.TIB2^.TID) then
- begin
- LockCount := 1;
- OwningThread2 := PTIB^.TIB2^.TID;
- DosExitCritSec;
- DosRequestMutExSem (LockSemaphore2, sem_Indefinite_Wait);
- end else if PTIB^.TIB2^.TID = OwningThread2 then
- begin
- Inc (LockCount);
- if LockCount = 0 then Dec (LockCount);
- DosExitCritSec;
- end else
- begin
- DosExitCritSec;
- DosRequestMutExSem (LockSemaphore2, sem_Indefinite_Wait);
- DosEnterCritSec;
- LockCount := 1;
- OwningThread2 := PTIB^.TIB2^.TID;
- DosExitCritSec;
- end;
- end;
- procedure LeaveCriticalSection (var CS: TRTLCriticalSection);
- var
- PTIB: PThreadInfoBlock;
- PPIB: PProcessInfoBlock;
- Err: boolean;
- begin
- Err := false;
- DosGetInfoBlocks (@PTIB, @PPIB);
- DosEnterCritSec;
- with CS do if OwningThread2 <> PTIB^.TIB2^.TID then
- begin
- DosExitCritSec;
- Err := true;
- end else if LockCount = 1 then
- begin
- if DosReleaseMutExSem (LockSemaphore2) <> 0 then Err := true;
- Dec (LockCount);
- DosExitCritSec;
- end else
- begin
- Dec (LockCount);
- DosExitCritSec;
- end;
- if Err then HandleError (5);
- end;
- {$ENDIF MT}
- {
- $Log$
- Revision 1.14 2003-10-13 21:17:31 hajny
- * longint to cardinal corrections
- Revision 1.13 2003/10/08 09:21:33 yuri
- * EMX code removed. Most probably, MT broken. (EMX notification removed)
- Revision 1.12 2003/10/08 05:22:47 yuri
- * Some emx code removed
- Revision 1.11 2003/10/07 21:26:35 hajny
- * stdcall fixes and asm routines cleanup
- Revision 1.10 2003/02/20 17:09:49 hajny
- * fixes for OS/2 v2.1 incompatibility
- Revision 1.9 2002/09/07 16:01:25 peter
- * old logs removed and tabs fixed
- Revision 1.8 2002/07/07 18:04:39 hajny
- * correction by Yuri Prokushev
- Revision 1.7 2002/03/28 16:34:29 armin
- + initialize threadvars defined local in units
- }
|