home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vpbgib2.zip / MUTEX.PAS < prev    next >
Pascal/Delphi Source File  |  1996-11-02  |  7KB  |  199 lines

  1. {$A-,B-,D+,E-,F-,G-,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y+}
  2. {&AlignCode-,AlignData-,AlignRec-,Asm-,Cdecl-,Delphi+,W-,Frame-,G3+}
  3. {&LocInfo+,Optimise+,OrgName-,SmartLink+,Speed-,Z-,ZD-}
  4. Unit Mutex;
  5.  
  6. Interface
  7.  
  8. uses
  9.   os2def, os2base;
  10.  
  11. type
  12.   // Fast MUTEX semaphore class
  13.   tMutexSem = class
  14.   public
  15.     Next  : Pointer;  // Next thread ID requesting ownership
  16.     Owner : TID;      // Current semaphore owner; bit 31 = semaphore in use
  17.     Count : Longint;  // For recursive semaphore requests
  18.  
  19.     constructor create;
  20.     function request: boolean;
  21.     function release: boolean;
  22.     function check: boolean;
  23.   private
  24.  
  25.   end;
  26.  
  27. Implementation
  28.  
  29. {---- Routines to handle safe termination ----}
  30.  
  31. const
  32.   MaxMonitor = 256;
  33.  
  34. var
  35.   Suspended: Array[0..MaxMonitor div 8] of Byte;
  36.  
  37. function IsInSuspendList( TID: Longint ): Boolean; assembler {&frame-} {&uses none};
  38. asm
  39.                 mov     ecx,TID
  40.                 cmp     ecx,MaxMonitor
  41.                 mov     al,0
  42.                 jge     @@exit
  43.                 lea     eax,Suspended
  44.                 bt      [eax],ecx
  45.                 setc    al
  46. @@exit:
  47. end;
  48.  
  49. {---- tMutexSem definition ----}
  50.  
  51. constructor tMutexSem.create; assembler {&frame+} {&uses none};
  52. asm             mov     ecx,Self
  53.            lock bts     [ecx].Owner,31                {Lock semaphore updates}
  54.                 jnc     @@ok
  55.                 mov     al,0
  56.                 ret     4
  57. @@ok:           xor     eax,eax
  58.                 mov     [ecx].Next,eax
  59.            lock xchg    [ecx].Owner,eax
  60.                 mov     al,1
  61. end;
  62.  
  63. function tMutexSem.Request; assembler {&frame-} {&uses none};
  64. asm             mov     eax,fs:[12]            {Get ^Thread Information Block}
  65.                 push    dword ptr [eax]                      {Owner : Longint}
  66.                 push    eax                                   {Next : Pointer}
  67.                 mov     ecx,Self+8
  68.                 push    dword ptr [ecx]                       {Class info ptr}
  69. @@testSem:
  70.            lock bts     [ecx].Owner,31
  71.                 jnc     @@semFree
  72.                 push    ecx
  73.                 push    1          {There is no hurry since semaphore is busy}
  74.                 call    DosSleep                  {Go to sleep for a while...}
  75.                 pop     eax
  76.                 pop     ecx
  77.                 jmp     @@testSem
  78.  
  79. @@semFree:      mov     edx,[ecx].Owner                  {Get semaphore owner}
  80.                 btr     edx,31                     {Reset `semaphor busy` bit}
  81.                 cmp     edx,[esp].Owner                 {Owner = current TID?}
  82.                 jne     @@notOur
  83.                 inc     [ecx].Count
  84.            lock btr     [ecx].Owner,31                     {Release semaphore}
  85.                 add     esp,12
  86.                 mov     al,1
  87.                 ret     4
  88.  
  89. @@notOur:       mov     eax,esp
  90.                 xchg    eax,[ecx].Next
  91.                 test    edx,edx                                   {Owner = 0?}
  92.                 jz      @@notBusy
  93.                 mov     [esp].Next,eax                         {Save ^nextTID}
  94.                 mov     edx,dword ptr [esp].Owner                    {Our TID}
  95.                 cmp     edx,MaxMonitor
  96.                 jge     @@Suspend            {Only monitor Maxmonitor threads}
  97.                 lea     eax,Suspended
  98.                 bts     [eax],edx           {Add to list of suspended threads}
  99. @@Suspend:
  100.            lock btr     [ecx].Owner,31                     {Release semaphore}
  101.                 push    edx                                          {Our TID}
  102.                 call    SuspendThread                     {Sleep until wakeup}
  103.                 mov     edx,dword ptr [esp].Owner                    {Our TID}
  104.                 cmp     edx,MaxMonitor
  105.                 jge     @@DontClear
  106.                 lea     eax,Suspended
  107.                 btr     [eax],edx      {Remove from list of suspended threads}
  108. @@DontClear:
  109.                 add     esp,12
  110.                 mov     al,1
  111.                 ret     4
  112.  
  113. @@notBusy:      xchg    eax,[ecx].Next
  114.                 inc     edx
  115.                 mov     [ecx].Count,edx                    {Request count = 1}
  116.                 pop     edx                                    {Skip classptr}
  117.                 pop     eax                                    {Skip ^nextTID}
  118.                 pop     eax
  119.            lock xchg    [ecx].Owner,eax           {Set owner&unlock semaphore}
  120.                 mov     al,1
  121. end;
  122.  
  123. function tMutexSem.Release; assembler {&frame-} {&uses none};
  124. asm
  125. @@testSem:      mov     ecx,Self
  126.            lock bts     [ecx].Owner,31                {Lock semaphore updates}
  127.                 jnc     @@semFree
  128.                 push    1
  129.                 call    DosSleep
  130.                 pop     eax
  131.                 jmp     @@testSem
  132. @@semFree:      mov     eax,fs:[12]
  133.                 mov     eax,[eax]
  134.                 bts     eax,31              {Set bit 31 in EAX for comparison}
  135.                 cmp     eax,[ecx].Owner
  136.                 je      @@isOur
  137.            lock btr     [ecx].Owner,31                     {Release semaphore}
  138.                 mov     al,0
  139.                 ret     4
  140.  
  141. @@isOur:        dec     [ecx].Count                       {Request count = 1?}
  142.                 jz      @@scanChain
  143.            lock btr     [ecx].Owner,31                     {Release semaphore}
  144.                 mov     al,1
  145.                 ret     4
  146.  
  147. @@scanChain:    mov     edx,eax
  148.                 mov     eax,ecx
  149.                 mov     ecx,[ecx].Next                              {^nextTID}
  150.                 test    ecx,ecx
  151.                 jnz     @@scanChain
  152.                 mov     ecx,Self
  153.                 cmp     eax,ecx
  154.                 je      @@onlyOwner                  {Thread is only in chain}
  155.                 mov     [edx].Next,0                {Remove thread from chain}
  156.                 mov     [ecx].Count,1                 {Set request count to 1}
  157.                 mov     edx,[eax].Owner
  158.                 push    edx
  159.            lock xchg    [ecx].Owner,edx          {Make thread semaphore owner}
  160.                 pop     edx
  161. @@again:
  162.                 push    edx
  163.                 push    edx                          {ResumeThread(TID = EDX)}
  164.                 call    ResumeThread                          {Wake up thread}
  165.                 pop     edx
  166.                 cmp     eax,Error_Not_Frozen          {Not yet sent to sleep?}
  167.                 je      @@again
  168.                 mov     al,1
  169.                 ret     4
  170.  
  171. @@onlyOwner:    xor     eax,eax
  172.            lock xchg    eax,[ecx].tMutexSem.Owner
  173.                 mov     al,1
  174. end;
  175.  
  176. function tMutexSem.Check; assembler {&frame-} {&uses none};
  177. asm             mov     eax,Self
  178.                 mov     eax,[eax].Owner
  179.                 and     eax,7FFFFFFFh
  180.                 setz    al
  181. end;
  182.  
  183. var
  184.   Thread: LongInt;
  185.  
  186. initialization
  187.   // Initialise all threads to be active
  188.   fillchar( Suspended, Sizeof(Suspended), 0 );
  189. finalization
  190.   // Release any threads that have been suspended by tMutexSems
  191.   for Thread := 0 to pred(MaxMonitor) do
  192.     if IsInSuspendList( Thread ) then
  193.       begin
  194.         DosResumeThread( Thread );
  195.         DosKillThread( Thread );
  196.       end;
  197. end.
  198.  
  199.