home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
vpbgib2.zip
/
MUTEX.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-11-02
|
7KB
|
199 lines
{$A-,B-,D+,E-,F-,G-,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y+}
{&AlignCode-,AlignData-,AlignRec-,Asm-,Cdecl-,Delphi+,W-,Frame-,G3+}
{&LocInfo+,Optimise+,OrgName-,SmartLink+,Speed-,Z-,ZD-}
Unit Mutex;
Interface
uses
os2def, os2base;
type
// Fast MUTEX semaphore class
tMutexSem = class
public
Next : Pointer; // Next thread ID requesting ownership
Owner : TID; // Current semaphore owner; bit 31 = semaphore in use
Count : Longint; // For recursive semaphore requests
constructor create;
function request: boolean;
function release: boolean;
function check: boolean;
private
end;
Implementation
{---- Routines to handle safe termination ----}
const
MaxMonitor = 256;
var
Suspended: Array[0..MaxMonitor div 8] of Byte;
function IsInSuspendList( TID: Longint ): Boolean; assembler {&frame-} {&uses none};
asm
mov ecx,TID
cmp ecx,MaxMonitor
mov al,0
jge @@exit
lea eax,Suspended
bt [eax],ecx
setc al
@@exit:
end;
{---- tMutexSem definition ----}
constructor tMutexSem.create; assembler {&frame+} {&uses none};
asm mov ecx,Self
lock bts [ecx].Owner,31 {Lock semaphore updates}
jnc @@ok
mov al,0
ret 4
@@ok: xor eax,eax
mov [ecx].Next,eax
lock xchg [ecx].Owner,eax
mov al,1
end;
function tMutexSem.Request; assembler {&frame-} {&uses none};
asm mov eax,fs:[12] {Get ^Thread Information Block}
push dword ptr [eax] {Owner : Longint}
push eax {Next : Pointer}
mov ecx,Self+8
push dword ptr [ecx] {Class info ptr}
@@testSem:
lock bts [ecx].Owner,31
jnc @@semFree
push ecx
push 1 {There is no hurry since semaphore is busy}
call DosSleep {Go to sleep for a while...}
pop eax
pop ecx
jmp @@testSem
@@semFree: mov edx,[ecx].Owner {Get semaphore owner}
btr edx,31 {Reset `semaphor busy` bit}
cmp edx,[esp].Owner {Owner = current TID?}
jne @@notOur
inc [ecx].Count
lock btr [ecx].Owner,31 {Release semaphore}
add esp,12
mov al,1
ret 4
@@notOur: mov eax,esp
xchg eax,[ecx].Next
test edx,edx {Owner = 0?}
jz @@notBusy
mov [esp].Next,eax {Save ^nextTID}
mov edx,dword ptr [esp].Owner {Our TID}
cmp edx,MaxMonitor
jge @@Suspend {Only monitor Maxmonitor threads}
lea eax,Suspended
bts [eax],edx {Add to list of suspended threads}
@@Suspend:
lock btr [ecx].Owner,31 {Release semaphore}
push edx {Our TID}
call SuspendThread {Sleep until wakeup}
mov edx,dword ptr [esp].Owner {Our TID}
cmp edx,MaxMonitor
jge @@DontClear
lea eax,Suspended
btr [eax],edx {Remove from list of suspended threads}
@@DontClear:
add esp,12
mov al,1
ret 4
@@notBusy: xchg eax,[ecx].Next
inc edx
mov [ecx].Count,edx {Request count = 1}
pop edx {Skip classptr}
pop eax {Skip ^nextTID}
pop eax
lock xchg [ecx].Owner,eax {Set owner&unlock semaphore}
mov al,1
end;
function tMutexSem.Release; assembler {&frame-} {&uses none};
asm
@@testSem: mov ecx,Self
lock bts [ecx].Owner,31 {Lock semaphore updates}
jnc @@semFree
push 1
call DosSleep
pop eax
jmp @@testSem
@@semFree: mov eax,fs:[12]
mov eax,[eax]
bts eax,31 {Set bit 31 in EAX for comparison}
cmp eax,[ecx].Owner
je @@isOur
lock btr [ecx].Owner,31 {Release semaphore}
mov al,0
ret 4
@@isOur: dec [ecx].Count {Request count = 1?}
jz @@scanChain
lock btr [ecx].Owner,31 {Release semaphore}
mov al,1
ret 4
@@scanChain: mov edx,eax
mov eax,ecx
mov ecx,[ecx].Next {^nextTID}
test ecx,ecx
jnz @@scanChain
mov ecx,Self
cmp eax,ecx
je @@onlyOwner {Thread is only in chain}
mov [edx].Next,0 {Remove thread from chain}
mov [ecx].Count,1 {Set request count to 1}
mov edx,[eax].Owner
push edx
lock xchg [ecx].Owner,edx {Make thread semaphore owner}
pop edx
@@again:
push edx
push edx {ResumeThread(TID = EDX)}
call ResumeThread {Wake up thread}
pop edx
cmp eax,Error_Not_Frozen {Not yet sent to sleep?}
je @@again
mov al,1
ret 4
@@onlyOwner: xor eax,eax
lock xchg eax,[ecx].tMutexSem.Owner
mov al,1
end;
function tMutexSem.Check; assembler {&frame-} {&uses none};
asm mov eax,Self
mov eax,[eax].Owner
and eax,7FFFFFFFh
setz al
end;
var
Thread: LongInt;
initialization
// Initialise all threads to be active
fillchar( Suspended, Sizeof(Suspended), 0 );
finalization
// Release any threads that have been suspended by tMutexSems
for Thread := 0 to pred(MaxMonitor) do
if IsInSuspendList( Thread ) then
begin
DosResumeThread( Thread );
DosKillThread( Thread );
end;
end.