123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- {
- $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 Win32
- 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.
- **********************************************************************}
- const
- threadvarblocksize : dword = 0;
- type
- tthreadinfo = record
- f : tthreadfunc;
- p : pointer;
- end;
- pthreadinfo = ^tthreadinfo;
- var
- dataindex : dword;
- { import the necessary stuff from windows }
- function TlsAlloc : DWord;external 'kernel32' name 'TlsAlloc';
- function TlsGetValue(dwTlsIndex : DWord) : pointer;
- external 'kernel32' name 'TlsGetValue';
- function TlsSetValue(dwTlsIndex : DWord;lpTlsValue : pointer) : LongBool;
- external 'kernel32' name 'TlsSetValue';
- function TlsFree(dwTlsIndex : DWord) : LongBool;
- external 'kernel32' name 'TlsFree';
- function CreateThread(lpThreadAttributes : pointer;
- dwStackSize : DWord; lpStartAddress : pointer;lpParameter : pointer;
- dwCreationFlags : DWord;var lpThreadId : DWord) : THandle;
- external 'kernel32' name 'CreateThread';
- procedure ExitThread(dwExitCode : DWord);
- external 'kernel32' name 'ExitThread';
- procedure init_threadvar(var offset : dword;size : dword);[public,alias: 'FPC_INIT_THREADVAR'];
- begin
- offset:=threadvarblocksize;
- inc(threadvarblocksize,size);
- end;
- function relocate_threadvar(offset : dword) : pointer;[public,alias: 'FPC_RELOCATE_THREADVAR'];
- begin
- relocate_threadvar:=TlsGetValue(dataindex)+offset;
- end;
- procedure AllocateThreadVars;
- var
- threadvars : pointer;
- begin
- { we've to allocate the memory from windows }
- { 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 }
- threadvars:=pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,
- threadvarblocksize));
- TlsSetValue(dataindex,threadvars);
- 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
- threadvars : pointer;
- begin
- { release thread vars }
- threadvars:=TlsGetValue(dataindex);
- GlobalFree(threadvars);
- end;
- function ThreadMain(param : pointer) : dword;stdcall;
- 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}
- IsMultithreaded:=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:=CreateThread(sa,stacksize,@ThreadMain,ti,
- creationflags,threadid);
- end;
- function BeginThread(ThreadFunction : tthreadfunc) : DWord;
- var
- dummy : dword;
- begin
- BeginThread:=BeginThread(nil,0,ThreadFunction,nil,0,dummy);
- end;
- function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : DWord;
- var
- dummy : dword;
- begin
- BeginThread:=BeginThread(nil,0,ThreadFunction,p,0,dummy);
- end;
- function BeginThread(ThreadFunction : tthreadfunc;p : pointer;
- var ThreadId : DWord) : DWord;
- begin
- BeginThread:=BeginThread(nil,0,ThreadFunction,p,0,ThreadId);
- end;
- procedure EndThread(ExitCode : DWord);
- begin
- DoneThread;
- ExitThread(ExitCode);
- end;
- procedure EndThread;
- begin
- EndThread(0);
- end;
- { we implement these procedures for win32 by importing them }
- { directly from windows }
- procedure InitCriticalsection(var cs : tcriticalsection);
- begin
- end;
- procedure DoneCriticalsection(var cs : tcriticalsection);
- begin
- end;
- procedure EnterCriticalsection(var cs : tcriticalsection);
- begin
- end;
- procedure LeaveCriticalsection(var cs : tcriticalsection);
- begin
- end;
- {
- procedure InitCriticalSection(var cs : tcriticalsection);
- external 'kernel32' name 'InitializeCriticalSection';
- procedure DoneCriticalSection(var cs : tcriticalsection);
- external 'kernel32' name 'DeleteCriticalSection';
- procedure EnterCriticalSection(var cs : tcriticalsection);
- external 'kernel32' name 'EnterCriticalSection';
- procedure LeaveCriticalSection(var cs : tcriticalsection);
- external 'kernel32' name 'LeaveCriticalSection';
- }
- {
- $Log$
- Revision 1.1 2001-01-01 19:06:36 florian
- + initial release
- }
|