XPWinSync.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:33k
源码类别:

Email服务器

开发平台:

Delphi

  1. unit XPWinSync;
  2. {
  3.  $Source: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPWinSync.pas,v $
  4.  $Revision: 1.1 $
  5.  $Date: 2004/05/03 15:07:15 $
  6.  Last amended by $Author: pvspain $
  7.  $State: Exp $
  8.  XPWinSync:
  9.  Interfaces and implementing classes which wrap Windows
  10.  synchronisation mechanisms:
  11.  Events (AutoReset and Manual)
  12.  Mutexes
  13.  Semaphores
  14.  CriticalSections
  15.  SharedCounters
  16.  RWSynchronisers
  17.  Copyright (c) 2001 by The Excellent Programming Company Pty Ltd
  18.  (Australia) (ABN 27 005 394 918).
  19.  Contact Paul Spain via email: paul@xpro.com.au
  20.  This unit is free software; you can redistribute it and/or
  21.  modify it under the terms of the GNU Lesser General Public
  22.  License as published by the Free Software Foundation; either
  23.  version 2.1 of the License, or (at your option) any later version.
  24.  This unit is distributed in the hope that it will be useful,
  25.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  27.  Lesser General Public License for more details.
  28.  You should have received a copy of the GNU Lesser General Public
  29.  License along with this unit; if not, the license can be viewed at:
  30.  http://www.gnu.org/copyleft/lesser.html
  31.  or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  32.  Boston, MA  02111-1307  USA
  33.  }
  34. interface
  35. uses
  36.   XPWinBase,
  37.   XPRestore,            // IXPRestore, TXPRestore
  38.   XPSyncRW,             // IXPSyncRW
  39.   Windows,              // THandle,  CreateXXX(), OpenXXX
  40.   SysUtils;             // Exception, Trim(), FmtStr(), AnsiPos(),
  41.                         // AnsiLowerCase()
  42. type
  43. {$IFDEF XPW32E}
  44.   EXPWin32Event = class (EXPWin32) end;
  45.   EXPWin32Synchro = class (EXPWin32) end;
  46.     EXPWin32Mutex = class (EXPWin32Synchro) end;
  47.     EXPWin32Semaphore = class (EXPWin32Synchro) end;
  48.   EXPWin32SharedCounter = class (EXPWin32) end;
  49.   EXPWin32SerialAccess = class (EXPWin32) end;
  50. {$ENDIF}
  51. //////////////////////////////////////////////////////////////////////////////
  52. ///   IXPWinXXXEvent
  53. //////////////////////////////////////////////////////////////////////////////
  54.   IXPWinEvent = interface(IXPWinNamedKernelObject)
  55.     ['{832555D0-0C82-11D5-A261-00608CF441D9}']
  56.     // Behaviour of Signal is the prime difference between Auto and Manual
  57.     // events. For Auto events, Signal will signal (only) the first waiting
  58.     // thread and reset itself. For Manual events, Signal will stay signalled
  59.     // until Reset is called
  60.     procedure Signal;
  61.     end;
  62.   IXPWinAutoEvent = interface(IXPWinEvent)
  63.     ['{7F4EBC21-16E6-11D5-A271-00608CF441D9}']
  64.     end;
  65.   IXPWinManualEvent = interface(IXPWinEvent)
  66.     ['{88C4F111-1500-11D5-A26D-00608CF441D9}']
  67.     procedure Reset;
  68.     // Pulse behaves like Signal for an Auto event, except that it signals
  69.     // _all_ waiting threads (not just the first thread) before resetting
  70.     // itself.
  71.     procedure Pulse;
  72.     end;
  73. //////////////////////////////////////////////////////////////////////////////
  74. ///   IXPSynchro: Mutexes, semaphores and critical sections
  75. //////////////////////////////////////////////////////////////////////////////
  76.   IXPWinSynchro = interface(IXPWinError)
  77.     ['{7F4EBC22-16E6-11D5-A271-00608CF441D9}']
  78.     function Enter: boolean;
  79.     function Leave: boolean;
  80.     end;
  81.   TXPWinSerialAccess = class(TXPWinError, IXPRestore)
  82.     private
  83.     FSync: IXPWinSynchro;
  84.     public
  85.     constructor Create(const ASync: IXPWinSynchro);
  86.     destructor Destroy; override;
  87.     end;
  88. //////////////////////////////////////////////////////////////////////////////
  89. ///   IXPWinMutex
  90. //////////////////////////////////////////////////////////////////////////////
  91.   IXPWinMutex = interface(IXPWinNamedKernelObject)
  92.     ['{BC7BDA82-4151-11D5-A2C1-00608CF441D9}']
  93.     end;
  94. //////////////////////////////////////////////////////////////////////////////
  95. ///   IXPWinXXXSemaphore
  96. //////////////////////////////////////////////////////////////////////////////
  97.   IXPWinSemaphore = interface(IXPWinNamedKernelObject)
  98.     ['{F65C8F71-1700-11D5-A271-00608CF441D9}']
  99.     // Count is number of free entries, not occupied entries
  100.     //
  101.     // There are some caveats on usage of GetCount, as Windows does
  102.     // not provide the facility to retrieve the current count value. The
  103.     // previous Count value can be retrieved via successful calls to
  104.     // Windows.ReleaseSemaphore()
  105.     // Caveats:
  106.     // GetCount is always accurate for a single-handle semaphore kernel object
  107.     // ie a semaphore which has (only) been created, not opened (see
  108.     // IXPWinNamedKernelObject.Instance) and which has been manipulated only
  109.     // by the interface methods, not via Windows API calls on the handle.
  110.     // If the semaphore has more than one handle opened, the count value is only
  111.     // guaranteed correct immediately following IXPSynchro.Leave and
  112.     // IXPWinSemaphore.Release calls.
  113.     // Note that this and the following interface are thread-safe, so the
  114.     // interfaces can be passed among threads rather than creating new handles
  115.     // via calls to GetSemaphore().
  116.     function GetCount: integer;
  117.     function Acquire: boolean;
  118.     procedure Release;
  119.     property Count: integer read GetCount;
  120.     end;
  121.   // This interface can be used when the semaphore has been created rather than
  122.   // opened, ie when Instance = koCreated (IXPWinNamedKernelObject.Instance)
  123.   IXPWinCreatedSemaphore = interface(IXPWinSemaphore)
  124.     ['{64F2B390-26F8-11D5-8CAD-0080ADB62643}']
  125.     function GetCapacity: integer;
  126.     // Use Open as the first call on a new interface which has been created via
  127.     // GetSemaphore() with the CreateOpen parameter as false. This scenario is
  128.     // useful to initialize resources upon creation, before releasing them for
  129.     // use.
  130.     function Open: boolean;
  131.     property Capacity: integer read GetCapacity;
  132.     end;
  133. //////////////////////////////////////////////////////////////////////////////
  134. ///   IXPSharedCounter
  135. //////////////////////////////////////////////////////////////////////////////
  136. const
  137.   XPCounterError = System.Low(integer);
  138. type
  139.   IXPSharedCounter = interface
  140.     ['{BC7BDA81-4151-11D5-A2C1-00608CF441D9}']
  141.     function GetValue: integer;
  142.     procedure SetValue(const Value: integer);
  143.     function Inc(const Delta: integer = 1): integer;
  144.     function Dec(const Delta: integer = 1): integer;
  145.     property Value: integer read GetValue write SetValue;
  146.     end;
  147. //////////////////////////////////////////////////////////////////////////////
  148. ///   Creator functions: unit entry points
  149. //////////////////////////////////////////////////////////////////////////////
  150. function GetAutoEvent(const CreateAsSignaled: boolean = false;
  151.   const AName: string = '';
  152.   const Inheritable: boolean = true;
  153.   const SecurityDescriptor: Pointer = nil): IXPWinAutoEvent;
  154. function GetManualEvent(const CreateAsSignaled: boolean = false;
  155.   const AName: string = '';
  156.   const Inheritable: boolean = true;
  157.   const SecurityDescriptor: Pointer = nil): IXPWinManualEvent;
  158. { Mutexes and Semaphores must be instantiated  at a scope which is *local* to
  159.   each interested thread. The common Name value ensures we are connecting
  160.   with the same kernel object. }
  161. function GetMutex(const AName: string = ''; const Inheritable: boolean = true;
  162.   const SecurityDescriptor: Pointer = nil): IXPWinMutex;
  163. function GetSemaphore(const Capacity: integer; const AName: string = '';
  164.   const CreateOpen: boolean = true; const Inheritable: boolean = true;
  165.   const SecurityDescriptor: Pointer = nil): IXPWinSemaphore;
  166. { Critical sections must be instantiated at a scope which is common to all
  167.   interested threads, ie at process *global* scope. }
  168. function CreateCriticalSection: IXPWinSynchro;
  169. function GetSharedCounter(const InitialValue: integer = 0;
  170.   const AName: string = ''; const Inheritable: boolean = true;
  171.   const SecurityDescriptor: Pointer = nil): IXPSharedCounter;
  172. { CreateThreadIXPSyncRW creates an interface for intra-process thread
  173.  synchronisation. }
  174. function CreateThreadRWSynchroniser(
  175.   const SyncPriority: TXPSyncPriority = spReaders): IXPSyncRW;
  176. { CreateProcessIXPSyncRW creates an interface for inter-process thread
  177.  synchronisation. }
  178. function GetProcessRWSynchroniser(const Name: string = '';
  179.   const SyncPriority: TXPSyncPriority = spReaders;
  180.   const Inheritable: boolean = true;
  181.   const SecurityDescriptor: Pointer = nil): IXPSyncRW;
  182. implementation
  183. const CVSID: string = '$Header: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPWinSync.pas,v 1.1 2004/05/03 15:07:15 pvspain Exp $';
  184. ///////////////////////////////////////////////////////////////////////////////
  185. ///     TXPSerialAccess implementation
  186. ///////////////////////////////////////////////////////////////////////////////
  187. constructor TXPWinSerialAccess.Create(const ASync: IXPWinSynchro);
  188.   begin
  189. {$IFDEF XPW32E}
  190.   inherited Create(EXPWin32SerialAccess);
  191. {$ELSE}
  192.   inherited Create;
  193. {$ENDIF}
  194.   FSync := ASync;
  195.   if not FSync.Enter then
  196.     Error('TXPSerialAccess.Create');
  197.   end;
  198. destructor TXPWinSerialAccess.Destroy;
  199.   begin
  200.   if not FSync.Leave then
  201.     Error('TXPSerialAccess.Destroy');
  202.   inherited;
  203.   end;
  204. ///////////////////////////////////////////////////////////////////////////////
  205. ///     IXPWinXXXEvent implementation
  206. ///////////////////////////////////////////////////////////////////////////////
  207. type
  208.   TXPWinEvent = class(TXPWinNamedKernelObject, IXPWinEvent)
  209.     private
  210.     //
  211.     // IXPWinEvent implementation
  212.     //
  213.     procedure Signal;
  214.     public
  215.     constructor Create(const AName: string; const CreateAsSignaled: boolean;
  216.       const ManualReset: boolean; const Inheritable: boolean;
  217.       const SecurityDescriptor: Pointer);
  218.     end;
  219.   TXPWinAutoEvent = class(TXPWinEvent, IXPWinAutoEvent)
  220.     public
  221.     constructor Create(const AName: string; const CreateAsSignaled: boolean;
  222.       const Inheritable: boolean; const SecurityDescriptor: Pointer);
  223.     end;
  224.   TXPWinManualEvent = class(TXPWinEvent, IXPWinManualEvent)
  225.     private
  226.     //
  227.     // IXPWinManualEvent implementation
  228.     //
  229.     procedure Reset;
  230.     procedure Pulse;
  231.     public
  232.     constructor Create(const AName: string;  const CreateAsSignaled: boolean;
  233.       const Inheritable: boolean; const SecurityDescriptor: Pointer);
  234.     end;
  235. constructor TXPWinEvent.Create(const AName: string;
  236.   const CreateAsSignaled: boolean; const ManualReset: boolean;
  237.   const Inheritable: boolean; const SecurityDescriptor: Pointer);
  238.   begin
  239.   inherited Create(AName, Inheritable, SecurityDescriptor);
  240. {$IFDEF XPW32E}
  241.   SetException(EXPWin32Event);
  242. {$ENDIF}
  243.   FHandle := Windows.CreateEvent(@FSecurityAttributes, ManualReset,
  244.     CreateAsSignaled, PChar(GetName));
  245.   if FHandle = 0 then
  246.     Error('TXPWinEvent.Create: Windows.CreateEvent failure')
  247.   else if Windows.GetLastError = 0 then
  248.     FInstance := koCreated
  249.   else if Windows.GetLastError = ERROR_ALREADY_EXISTS then
  250.     FInstance := koOpened;
  251.   end;
  252. procedure TXPWinEvent.Signal;
  253.   begin
  254.   Windows.SetEvent(FHandle);
  255.   end;
  256. { TXPWinAutoEvent }
  257. constructor TXPWinAutoEvent.Create(const AName: string;
  258.   const CreateAsSignaled: boolean; const Inheritable: boolean;
  259.   const SecurityDescriptor: Pointer);
  260.   const
  261.   ManualReset = false;
  262.   begin
  263.   inherited Create(AName, CreateAsSignaled, ManualReset, Inheritable,
  264.     SecurityDescriptor);
  265.   end;
  266. { TXPWinManualEvent }
  267. constructor TXPWinManualEvent.Create(const AName: string;
  268.   const CreateAsSignaled: boolean; const Inheritable: boolean;
  269.   const SecurityDescriptor: Pointer);
  270.   const
  271.   ManualReset = true;
  272.   begin
  273.   inherited Create(AName, CreateAsSignaled, ManualReset, Inheritable,
  274.     SecurityDescriptor);
  275.   end;
  276. procedure TXPWinManualEvent.Pulse;
  277.   begin
  278.   Windows.PulseEvent(GetHandle);
  279.   end;
  280. procedure TXPWinManualEvent.Reset;
  281.   begin
  282.   Windows.ResetEvent(GetHandle);
  283.   end;
  284. //////////////////////////////////////////////////////////////////////////////
  285. ///   TXPWinMutex implementation
  286. //////////////////////////////////////////////////////////////////////////////
  287. type
  288.   TXPWinMutex = class(TXPWinNamedKernelObject, IXPWinMutex, IXPWinSynchro)
  289.     private
  290.     //
  291.     // IXPSynchro implementation
  292.     //
  293.     function Enter: boolean;
  294.     function Leave: boolean;
  295.     public
  296.     constructor Create(const AName: string; const Inheritable: boolean;
  297.       const SecurityDescriptor: Pointer);
  298.     end;
  299. constructor TXPWinMutex.Create(const AName: string; const Inheritable: boolean;
  300.   const SecurityDescriptor: Pointer);
  301.   const
  302.   EnterOnCreate = false;
  303.   begin
  304.   inherited Create(AName, Inheritable, SecurityDescriptor);
  305. {$IFDEF XPW32E}
  306.   SetException(EXPWin32Mutex);
  307. {$ENDIF}
  308.   FHandle := Windows.CreateMutex(@FSecurityAttributes, EnterOnCreate,
  309.     PChar(GetName));
  310.   if FHandle = 0 then
  311.     Error('TXPWinMutex.Create: Windows.CreateMutex failure')
  312.   else if Windows.GetLastError = 0 then
  313.     FInstance := koCreated
  314.   else if Windows.GetLastError = ERROR_ALREADY_EXISTS then
  315.     FInstance := koOpened;
  316.   end;
  317. function TXPWinMutex.Enter: boolean;
  318.   begin
  319.   Result := Wait;
  320.   if not Result then
  321.     SetLastContext('TXPWinMutex.Enter: ' + GetLastContext);
  322.   end;
  323. function TXPWinMutex.Leave: boolean;
  324.   begin
  325.   Result := Windows.ReleaseMutex(FHandle);
  326.   if not Result then
  327.     Error('TXPWinMutex.Leave: Windows.ReleaseMutex failure');
  328.   end;
  329. //////////////////////////////////////////////////////////////////////////////
  330. ///   TXPWinSemaphore implementation
  331. //////////////////////////////////////////////////////////////////////////////
  332. type
  333.   TXPWinSemaphore = class(TXPWinNamedKernelObject, IXPWinSynchro,
  334.     IXPWinSemaphore, IXPWinCreatedSemaphore)
  335.     private
  336.     FCapacity: integer;
  337.     FCount: integer;
  338.     //
  339.     // IXPSynchro implementation
  340.     //
  341.     function Enter: boolean;
  342.     function Leave: boolean;
  343.     //
  344.     // IXPWinSemaphore implementation
  345.     //
  346.     function GetCount: integer;
  347.     function Acquire: boolean;
  348.     procedure Release;
  349.     //
  350.     // IXPWinCreatedSemaphore implementation
  351.     //
  352.     function Open: boolean;
  353.     function GetCapacity: integer;
  354.     protected
  355.     function IsSignaled: boolean; override;
  356.     function Wait: boolean; override;
  357.     function WaitFor(const Millisecs: cardinal): boolean; override;
  358.     public
  359.     constructor Create(const ACapacity: integer; const AName: string;
  360.       const CreateOpen: boolean; const Inheritable: boolean;
  361.       const SecurityDescriptor: Pointer);
  362.     end;
  363. constructor TXPWinSemaphore.Create(const ACapacity: integer;
  364.   const AName: string; const CreateOpen: boolean; const Inheritable: boolean;
  365.   const SecurityDescriptor: Pointer);
  366.   var
  367.   InitCount: integer;
  368.   begin
  369.   inherited Create(AName, Inheritable, SecurityDescriptor);
  370. {$IFDEF XPW32E}
  371.   SetException(EXPWin32Semaphore);
  372. {$ENDIF}
  373.   FCapacity := -1;
  374.   FCount := -1;
  375.   if CreateOpen then
  376.     InitCount := ACapacity
  377.   else
  378.     InitCount := 0;
  379.   FHandle := Windows.CreateSemaphore(@FSecurityAttributes, InitCount,
  380.     ACapacity, PChar(GetName));
  381.   if FHandle = 0 then
  382.     Error('TXPWinSemaphore.Create: Windows.CreateSemaphore failure')
  383.   else if Windows.GetLastError = 0 then
  384.     begin
  385.     FInstance := koCreated;
  386.     FCapacity := ACapacity;
  387.     FCount := InitCount;
  388.     end
  389.   else if Windows.GetLastError = ERROR_ALREADY_EXISTS then
  390.     FInstance := koOpened;
  391.   end;
  392. function TXPWinSemaphore.GetCapacity: integer;
  393.   begin
  394.   Result := FCapacity;
  395.   end;
  396. function TXPWinSemaphore.GetCount: integer;
  397.   begin
  398.   Result := FCount;
  399.   end;
  400. function TXPWinSemaphore.Enter: boolean;
  401.   begin
  402.   Result := Wait;
  403.   if not Result then
  404.     SetLastContext('TXPWinSemaphore.Enter: ' + GetLastContext);
  405.   end;
  406. function TXPWinSemaphore.IsSignaled: boolean;
  407.   begin
  408.   Result := inherited IsSignaled;
  409.   if Result then
  410.     Windows.InterlockedDecrement(FCount)
  411.   else
  412.     SetLastContext('TXPWinSemaphore.IsSignaled: ' + GetLastContext);
  413.   end;
  414. function TXPWinSemaphore.Wait: boolean;
  415.   begin
  416.   Result := inherited Wait;
  417.   if Result then
  418.     Windows.InterlockedDecrement(FCount)
  419.   else
  420.     SetLastContext('TXPWinSemaphore.Wait: ' + GetLastContext);
  421.   end;
  422. function TXPWinSemaphore.WaitFor(const Millisecs: cardinal): boolean;
  423.   begin
  424.   Result := inherited WaitFor(Millisecs);
  425.   if Result then
  426.     Windows.InterlockedDecrement(FCount)
  427.   else
  428.     SetLastContext('TXPWinSemaphore.WaitFor: ' + GetLastContext);
  429.   end;
  430. function TXPWinSemaphore.Leave: boolean;
  431.   const
  432.   ReleaseCount = 1;
  433.   begin
  434.   Result := Windows.ReleaseSemaphore(FHandle, ReleaseCount, @FCount);
  435.   if Result then
  436.     Windows.InterlockedIncrement(FCount)
  437.   else
  438.     Error('TXPWinSemaphore.Leave: Windows.ReleaseSemaphore failure');
  439.   end;
  440. function TXPWinSemaphore.Acquire: boolean;
  441.   begin
  442.   Result := Enter;
  443.   if not Result then
  444.     SetLastContext('TXPWinSemaphore.Acquire: ' + GetLastContext);
  445.   end;
  446. procedure TXPWinSemaphore.Release;
  447.   begin
  448.   Leave;
  449.   end;
  450. function TXPWinSemaphore.Open: boolean;
  451.   begin
  452.   Result := (FCount = 0);
  453.   if not Result then
  454.     exit;
  455.   if not Windows.ReleaseSemaphore(FHandle, FCapacity, @FCount) then
  456.     Error('TXPWinSemaphore.Open: Windows.ReleaseSemaphore failure')
  457.   else
  458.     // Set new Count value
  459.     Windows.InterlockedExchange(FCount, FCount + FCapacity);
  460.   end;
  461. //////////////////////////////////////////////////////////////////////////////
  462. ///   TXPCriticalSectiom implementation
  463. //////////////////////////////////////////////////////////////////////////////
  464. type
  465.   TXPWinCriticalSection = class(TXPWinError, IXPWinSynchro)
  466.     private
  467.     FCriticalSection: TRTLCriticalSection;
  468.     //
  469.     // IXPSynchro implementation
  470.     //
  471.     function Enter: boolean;
  472.     function Leave: boolean;
  473.     public
  474.     constructor Create;
  475.     destructor Destroy; override;
  476.     end;
  477. constructor TXPWinCriticalSection.Create;
  478.   begin
  479. {$IFDEF XPW32E}
  480.   inherited Create(EXPWin32);
  481. {$ELSE}
  482.   inherited Create;
  483. {$ENDIF}
  484.   Windows.InitializeCriticalSection(FCriticalSection);
  485.   end;
  486. destructor TXPWinCriticalSection.Destroy;
  487.   begin
  488.   Windows.DeleteCriticalSection(FCriticalSection);
  489.   inherited Destroy;
  490.   end;
  491. function TXPWinCriticalSection.Enter: boolean;
  492.   begin
  493.   Windows.EnterCriticalSection(FCriticalSection);
  494.   Result := true;
  495.   end;
  496. function TXPWinCriticalSection.Leave: boolean;
  497.   begin
  498.   Result := true;
  499.   Windows.LeaveCriticalSection(FCriticalSection);
  500.   end;
  501. //////////////////////////////////////////////////////////////////////////////
  502. ///   IXPWinCounter implementation
  503. //////////////////////////////////////////////////////////////////////////////
  504. type
  505.   PInteger = ^integer;
  506.   TXPWinSharedCounter = class(TXPWinNamedKernelObject, IXPSharedCounter)
  507.     private
  508.     FMutex: IXPWinMutex;
  509.     FSync: IXPWinSynchro;
  510.     FCounter: PInteger;
  511.     function GetView: boolean;
  512.     procedure ReleaseView;
  513.     //
  514.     // IXPCounter implementation
  515.     //
  516.     function GetValue: integer;
  517.     procedure SetValue(const Value: integer);
  518.     function Inc(const Delta: integer): integer;
  519.     function Dec(const Delta: integer): integer;
  520.     public
  521.     constructor Create(const InitialValue: integer; const AName: string;
  522.       const Inheritable: boolean; const SecurityDescriptor: Pointer);
  523.     end;
  524. constructor TXPWinSharedCounter.Create(const InitialValue: integer;
  525.   const AName: string; const Inheritable: boolean;
  526.   const SecurityDescriptor: Pointer);
  527.   var
  528.   SerialAccess: IXPRestore;
  529.   const
  530.   PageFileHandle = $FFFFFFFF;
  531.   HiSize = 0;
  532.   begin
  533.   inherited Create(AName, Inheritable, SecurityDescriptor);
  534. {$IFDEF XPW32E}
  535.   SetException(EXPWin32SharedCounter);
  536. {$ENDIF}
  537.   FMutex := XPWinSync.GetMutex(GetName + '.XPCounter.Mutex', Inheritable,
  538.     SecurityDescriptor);
  539.   FSync := FMutex as IXPWinSynchro;
  540.   SerialAccess := TXPWinSerialAccess.Create(FSync);
  541.   // TODO: This call shouldn't be required as we only want to exclude
  542.   // if mutex created - so we can set init value. However, the EnterOnCreate
  543.   // argument doesn't work in Windows NT SP5 as documented, ie you don't get
  544.   // initial ownership when requested if the mutex is created
  545.   // Use this call to create or open file mapping object. Check last error
  546.   // value to determine case
  547.   FHandle := Windows.CreateFileMapping(PageFileHandle,
  548.     @FSecurityAttributes, PAGE_READWRITE, HiSize, System.Sizeof(integer),
  549.     PChar(GetName));
  550.   if FHandle = 0 then
  551.     begin
  552.     Error('TXPWinSharedCounter.Create: Windows.CreateFileMapping failure');
  553.     exit;
  554.     end;
  555.   // Store result from GetLastError
  556.   SetLastError;
  557.   if GetLastError = 0 then
  558.     begin
  559.     FInstance := koCreated;
  560.     // Set initial value
  561.     if GetView then
  562.       begin
  563.       FCounter^ := InitialValue;
  564.       ReleaseView;
  565.       end;
  566.     end
  567.   else if GetLastError = ERROR_ALREADY_EXISTS then
  568.     FInstance := koOpened;
  569.   end;
  570. function TXPWinSharedCounter.GetView: boolean;
  571.   const
  572.   HiOffset = 0;
  573.   LoOffset = 0;
  574.   Length = System.Sizeof(integer);
  575.   begin
  576.   if not FSync.Enter then
  577.     begin
  578.     Error('TXPWinSharedCounter.GetView');
  579.     Result := false;
  580.     end
  581.   else
  582.     begin
  583.     // Create view onto file mapping
  584.     FCounter := Windows.MapViewOfFile(FHandle, FILE_MAP_WRITE,
  585.       HiOffset, LoOffset, Length);
  586.     Result := FCounter <> nil;
  587.     if not Result then
  588.       Error('TXPWinSharedCounter.GetView: Windows.MapViewOfFile failure');
  589.     end;
  590.   end;
  591. procedure TXPWinSharedCounter.ReleaseView;
  592.   begin
  593.   if not FSync.Leave then
  594.     Error('TXPWinSharedCounter.ReleaseView');
  595.   if (FCounter <> nil) and (not Windows.UnmapViewOfFile(FCounter)) then
  596.     Error('TXPWinSharedCounter.ReleaseView: Windows.UnmapViewOfFile failure');
  597.   end;
  598. function TXPWinSharedCounter.Dec(const Delta: integer): integer;
  599.   begin
  600.   Result := Inc(-Delta);
  601.   end;
  602. function TXPWinSharedCounter.GetValue: integer;
  603.   begin
  604.   if GetView then
  605.     begin
  606.     Result := FCounter^;
  607.     ReleaseView;
  608.     end
  609.   else
  610.     Result := XPCounterError;
  611.   end;
  612. function TXPWinSharedCounter.Inc(const Delta: integer): integer;
  613.   begin
  614.   if GetView then
  615.     begin
  616.     System.Inc(FCounter^, Delta);
  617.     Result := FCounter^;
  618.     ReleaseView;
  619.     end
  620.   else
  621.     Result := XPCounterError;
  622.   end;
  623. procedure TXPWinSharedCounter.SetValue(const Value: integer);
  624.   begin
  625.   if GetView then
  626.     begin
  627.     FCounter^ := Value;
  628.     ReleaseView;
  629.     end
  630.   end;
  631. //////////////////////////////////////////////////////////////////////////////
  632. ///   IXPSyncRW implementation
  633. //////////////////////////////////////////////////////////////////////////////
  634.   // "Readers and writers" implementation (1)
  635.   //
  636.   // Single writer and multiple (unlimited) readers
  637.   // Priority given to readers, ie writer must wait till all
  638.   // readers have finished. (Can lead to writer starvation)
  639.   // Implementation uses critical sections and is therefore limited
  640.   // to a single process.
  641. type TXPWinThreadRWSynchroniser = class(TSyncRWBase)
  642.     private
  643.     FReaders: integer;
  644.     FAccess: IXPWinSynchro;
  645.     FMutex: IXPWinSynchro;
  646.     protected
  647.     // Use ReadBegin/ReadEnd with a try..finally context
  648.     procedure ReadBegin; override;
  649.     procedure ReadEnd; override;
  650.     // Use WriteBegin/WriteEnd with a try..finally context
  651.     procedure WriteBegin; override;
  652.     procedure WriteEnd; override;
  653.     public
  654.     constructor Create;
  655.     end;
  656. type TXPWinProcessRWSynchroniser = class(TSyncRWBase)
  657.     private
  658.     FName: string;
  659.     FReaders: IXPSharedCounter;
  660.     FAccess: IXPWinSynchro;
  661.     FBlockReaders: IXPWinSynchro;
  662.     protected
  663.     // Use ReadBegin/ReadEnd with a try..finally context
  664.     procedure ReadBegin; override;
  665.     procedure ReadEnd; override;
  666.     // Use WriteBegin/WriteEnd with a try..finally context
  667.     procedure WriteBegin; override;
  668.     procedure WriteEnd; override;
  669.     public
  670.     constructor Create(const Name: string; const Inheritable: boolean;
  671.       const SecurityDescriptor: Pointer);
  672.     end;
  673.   // "Readers and writers" implementation (2)
  674.   //
  675.   // Single writer and multiple (unlimited) readers
  676.   // Priority given to writers, ie no more readers allowed once a writer
  677.   // is waiting, and waiting writers given priority over waiting readers.
  678.   // ( Can lead to reader starvation. )
  679.   // Implementation uses critical sections and is therefore limited
  680.   // to a single process.
  681. type TXPWinThreadWRSynchroniser = class(TSyncRWBase)
  682.     private
  683.     FReaders: integer;
  684.     FWriters: integer;
  685.     FAccess: IXPWinSynchro;
  686.     FQueueReader: IXPWinSynchro;
  687.     FBlockReaders: IXPWinSynchro;
  688.     FRMutex: IXPWinSynchro;
  689.     FWMutex: IXPWinSynchro;
  690.     protected
  691.     // Use ReadBegin/ReadEnd with a try..finally context
  692.     procedure ReadBegin; override;
  693.     procedure ReadEnd; override;
  694.     // Use WriteBegin/WriteEnd with a try..finally context
  695.     procedure WriteBegin; override;
  696.     procedure WriteEnd; override;
  697.     public
  698.     constructor Create;
  699.     end;
  700. type TXPWinProcessWRSynchroniser = class(TSyncRWBase)
  701.     private
  702.     FReaders: IXPSharedCounter;
  703.     FWriters: IXPSharedCounter;
  704.     FName: string;
  705.     FAccess: IXPWinSynchro;
  706.     FBlockReaders: IXPWinSynchro;
  707.     protected
  708.     // Use ReadBegin/ReadEnd with a try..finally context
  709.     procedure ReadBegin; override;
  710.     procedure ReadEnd; override;
  711.     // Use WriteBegin/WriteEnd with a try..finally context
  712.     procedure WriteBegin; override;
  713.     procedure WriteEnd; override;
  714.     public
  715.     constructor Create(const Name: string; const Inheritable: boolean;
  716.       const SecurityDescriptor: Pointer);
  717.     end;
  718. /////////////////////////////////////////////////////////////////////////////
  719. //  TThreadSyncRW implementation
  720. //  Based on: Courtois et al, Communications of the ACM,
  721. //            Vol 14, No 10 Oct 1971, pp. 667-668
  722. /////////////////////////////////////////////////////////////////////////////
  723. constructor TXPWinThreadRWSynchroniser.Create;
  724.   begin
  725.   inherited Create;
  726.   FAccess := XPWinSync.CreateCriticalSection;
  727.   FMutex := XPWinSync.CreateCriticalSection;
  728.   end;
  729. procedure TXPWinThreadRWSynchroniser.ReadBegin;
  730.   begin
  731.   FMutex.Enter;
  732.   try
  733.     System.Inc(FReaders);
  734.     if FReaders = 1 then
  735.       FAccess.Enter;
  736.   finally
  737.     FMutex.Leave;
  738.     end;
  739.   end;
  740. procedure TXPWinThreadRWSynchroniser.ReadEnd;
  741.   begin
  742.   FMutex.Enter;
  743.   try
  744.     System.Dec(FReaders);
  745.     if FReaders = 0 then
  746.       FAccess.Leave;
  747.   finally
  748.     FMutex.Leave;
  749.     end;
  750.   end;
  751. procedure TXPWinThreadRWSynchroniser.WriteBegin;
  752.   begin
  753.   FAccess.Enter;
  754.   end;
  755. procedure TXPWinThreadRWSynchroniser.WriteEnd;
  756.   begin
  757.   FAccess.Leave;
  758.   end;
  759. /////////////////////////////////////////////////////////////////////////////
  760. //  TProcessSyncRW implementation
  761. /////////////////////////////////////////////////////////////////////////////
  762. constructor TXPWinProcessRWSynchroniser.Create(const Name: string;
  763.   const Inheritable: boolean; const SecurityDescriptor: Pointer);
  764.   begin
  765.   inherited Create;
  766.   FName := Name;
  767.   FReaders := XPWinSync.GetSharedCounter(0, FName + '.FReaders', Inheritable,
  768.     SecurityDescriptor);
  769.   FAccess := XPWinSync.GetMutex(FName + '.FAccess', Inheritable,
  770.     SecurityDescriptor) as IXPWinSynchro;
  771.   FBlockReaders := XPWinSync.GetMutex(FName + '.FMutex', Inheritable,
  772.     SecurityDescriptor) as IXPWinSynchro;
  773.   end;
  774. procedure TXPWinProcessRWSynchroniser.ReadBegin;
  775.   begin
  776.   FBlockReaders.Enter;
  777.   try
  778.     if FReaders.Inc = 1 then
  779.       FAccess.Enter;
  780.   finally
  781.     FBlockReaders.Leave;
  782.     end;
  783.   end;
  784. procedure TXPWinProcessRWSynchroniser.ReadEnd;
  785.   begin
  786.   if FReaders.Dec = 0 then
  787.     FAccess.Leave;
  788.   end;
  789. procedure TXPWinProcessRWSynchroniser.WriteBegin;
  790.   begin
  791.   FAccess.Enter;
  792.   end;
  793. procedure TXPWinProcessRWSynchroniser.WriteEnd;
  794.   begin
  795.   FAccess.Leave;
  796.   end;
  797. /////////////////////////////////////////////////////////////////////////////
  798. //  TThreadSyncWR implementation
  799. //  Based on: Courtois et al, Communications of the ACM,
  800. //            Vol 14, No 10 Oct 1971, pp. 667-668
  801. /////////////////////////////////////////////////////////////////////////////
  802. constructor TXPWinThreadWRSynchroniser.Create;
  803.   begin
  804.   inherited Create;
  805.   FAccess := XPWinSync.CreateCriticalSection;
  806.   FQueueReader := XPWinSync.CreateCriticalSection;
  807.   FBlockReaders := XPWinSync.CreateCriticalSection;
  808.   FRMutex := XPWinSync.CreateCriticalSection;
  809.   FWMutex := XPWinSync.CreateCriticalSection;
  810.   end;
  811. procedure TXPWinThreadWRSynchroniser.ReadBegin;
  812.   begin
  813.   FQueueReader.Enter;
  814.   try
  815.     FBlockReaders.Enter;
  816.     try
  817.       FRMutex.Enter;
  818.       try
  819.         System.Inc(FReaders);
  820.         if FReaders = 1 then
  821.           FAccess.Enter;
  822.       finally
  823.         FRMutex.Leave;
  824.         end;
  825.     finally
  826.       FBlockReaders.Leave;
  827.       end;
  828.   finally
  829.     FQueueReader.Leave;
  830.     end;
  831.   end;
  832. procedure TXPWinThreadWRSynchroniser.ReadEnd;
  833.   begin
  834.   FRMutex.Enter;
  835.   try
  836.     System.Dec(FReaders);
  837.     if FReaders = 0 then
  838.       FAccess.Leave;
  839.   finally
  840.     FRMutex.Leave;
  841.     end;
  842.   end;
  843. procedure TXPWinThreadWRSynchroniser.WriteBegin;
  844.   begin
  845.   FWMutex.Enter;
  846.   try
  847.     System.Inc(FWriters);
  848.     if (FWriters = 1) then
  849.       FBlockReaders.Enter;
  850.   finally
  851.     FWMutex.Leave;
  852.     end;
  853.   FAccess.Enter;
  854.   end;
  855. procedure TXPWinThreadWRSynchroniser.WriteEnd;
  856.   begin
  857.   FAccess.Leave;
  858.   FWMutex.Enter;
  859.   try
  860.     System.Dec(FWriters);
  861.     if FWriters = 0 then
  862.       FBlockReaders.Leave;
  863.   finally
  864.     FWMutex.Leave;
  865.     end;
  866.   end;
  867. /////////////////////////////////////////////////////////////////////////////
  868. //  TProcessSyncWR implementation
  869. /////////////////////////////////////////////////////////////////////////////
  870. constructor TXPWinProcessWRSynchroniser.Create(const Name: string;
  871.   const Inheritable: boolean; const SecurityDescriptor: Pointer);
  872.   const
  873.   InitialValue = 0;
  874.   begin
  875.   inherited Create;
  876.   FName := Name;
  877.   FReaders := XPWinSync.GetSharedCounter(InitialValue, FName + '.FReaders',
  878.     Inheritable, SecurityDescriptor);
  879.   FWriters := XPWinSync.GetSharedCounter(InitialValue, FName + '.FWriters',
  880.     Inheritable, SecurityDescriptor);
  881.   FAccess := XPWinSync.GetMutex(FName + '.FAccess', Inheritable,
  882.     SecurityDescriptor) as IXPWinSynchro;
  883.   FBlockReaders := XPWinSync.GetMutex(FName + '.FBlockReaders', Inheritable,
  884.     SecurityDescriptor) as IXPWinSynchro;
  885.   end;
  886. procedure TXPWinProcessWRSynchroniser.ReadBegin;
  887.   begin
  888.   FBlockReaders.Enter;
  889.   try
  890.     if FReaders.Inc = 1 then
  891.       FAccess.Enter;
  892.   finally
  893.     FBlockReaders.Leave;
  894.     end;
  895.   end;
  896. procedure TXPWinProcessWRSynchroniser.ReadEnd;
  897.   begin
  898.   if FReaders.Dec = 0 then
  899.     FAccess.Leave;
  900.   end;
  901. procedure TXPWinProcessWRSynchroniser.WriteBegin;
  902.   begin
  903.   if FWriters.Inc = 1 then
  904.     FBlockReaders.Enter;
  905.   FAccess.Enter;
  906.   end;
  907. procedure TXPWinProcessWRSynchroniser.WriteEnd;
  908.   begin
  909.   FAccess.Leave;
  910.   if FWriters.Dec = 0 then
  911.     FBlockReaders.Leave;
  912.   end;
  913. ///////////////////////////////////////////////////////////////////////////////
  914. ///    Global functions
  915. ///////////////////////////////////////////////////////////////////////////////
  916. function GetAutoEvent(const CreateAsSignaled: boolean;
  917.   const AName: string; const Inheritable: boolean;
  918.   const SecurityDescriptor: Pointer): IXPWinAutoEvent;
  919.   begin
  920.   Result := TXPWinAutoEvent.Create(AName, CreateAsSignaled, Inheritable,
  921.     SecurityDescriptor);
  922.   end;
  923. function GetManualEvent(const CreateAsSignaled: boolean;
  924.   const AName: string; const Inheritable: boolean;
  925.   const SecurityDescriptor: Pointer): IXPWinManualEvent;
  926.   begin
  927.   Result := TXPWinManualEvent.Create(AName, CreateAsSignaled, Inheritable,
  928.     SecurityDescriptor);
  929.   end;
  930. function GetMutex(const AName: string; const Inheritable: boolean;
  931.   const SecurityDescriptor: Pointer): IXPWinMutex;
  932.   begin
  933.   Result := TXPWinMutex.Create(AName, Inheritable, SecurityDescriptor);
  934.   end;
  935. function GetSemaphore(const Capacity: integer; const AName: string;
  936.   const CreateOpen: boolean; const Inheritable: boolean;
  937.   const SecurityDescriptor: Pointer): IXPWinSemaphore;
  938.   begin
  939.   Result := TXPWinSemaphore.Create(Capacity, AName, CreateOpen, Inheritable,
  940.     SecurityDescriptor);
  941.   end;
  942. function CreateCriticalSection: IXPWinSynchro;
  943.   begin
  944.   Result := TXPWinCriticalSection.Create;
  945.   end;
  946. function GetSharedCounter(const InitialValue: integer;
  947.   const AName: string; const Inheritable: boolean;
  948.   const SecurityDescriptor: Pointer): IXPSharedCounter;
  949.   begin
  950.   Result := TXPWinSharedCounter.Create(InitialValue, AName, Inheritable,
  951.     SecurityDescriptor);
  952.   end;
  953. function CreateThreadRWSynchroniser(
  954.   const SyncPriority: TXPSyncPriority): IXPSyncRW;
  955.   begin
  956.   if SyncPriority = spWriters then
  957.     Result := TXPWinThreadWRSynchroniser.Create
  958.   else
  959.     Result := TXPWinThreadRWSynchroniser.Create;
  960.   end;
  961. function GetProcessRWSynchroniser(const Name: string;
  962.   const SyncPriority: TXPSyncPriority; const Inheritable: boolean;
  963.   const SecurityDescriptor: Pointer): IXPSyncRW;
  964.   begin
  965.   if SyncPriority = spWriters then
  966.     Result := TXPWinProcessWRSynchroniser.Create(Name, Inheritable,
  967.       SecurityDescriptor)
  968.   else
  969.     Result := TXPWinProcessRWSynchroniser.Create(Name, Inheritable,
  970.       SecurityDescriptor);
  971.   end;
  972. end.