JclSynch.pas 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772
  1. {**************************************************************************************************}
  2. { }
  3. { Project JEDI Code Library (JCL) }
  4. { }
  5. { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6. { you may not use this file except in compliance with the License. You may obtain a copy of the }
  7. { License at http://www.mozilla.org/MPL/ }
  8. { }
  9. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
  10. { ANY KIND, either express or implied. See the License for the specific language governing rights }
  11. { and limitations under the License. }
  12. { }
  13. { The Original Code is JclSynch.pas. }
  14. { }
  15. { The Initial Developers of the Original Code are Marcel van Brakel and Azret Botash. }
  16. { Portions created by these individuals are Copyright (C) of these individuals. }
  17. { All Rights Reserved. }
  18. { }
  19. { Contributor(s): }
  20. { Marcel van Brakel }
  21. { Olivier Sannier (obones) }
  22. { Matthias Thoma (mthoma) }
  23. { }
  24. {**************************************************************************************************}
  25. { }
  26. { This unit contains various classes and support routines for implementing synchronisation in }
  27. { multithreaded applications. This ranges from interlocked access to simple typed variables to }
  28. { wrapper classes for synchronisation primitives provided by the operating system }
  29. { (critical section, semaphore, mutex etc). It also includes three user defined classes to }
  30. { complement these. }
  31. { }
  32. {**************************************************************************************************}
  33. { }
  34. { Last modified: $Date:: $ }
  35. { Revision: $Rev:: $ }
  36. { Author: $Author:: $ }
  37. { }
  38. {**************************************************************************************************}
  39. unit JclSynch;
  40. {$I jcl.inc}
  41. interface
  42. uses
  43. {$IFDEF UNITVERSIONING}
  44. JclUnitVersioning,
  45. {$ENDIF UNITVERSIONING}
  46. {$IFDEF HAS_UNITSCOPE}
  47. {$IFDEF MSWINDOWS}
  48. Winapi.Windows, JclWin32,
  49. {$ENDIF MSWINDOWS}
  50. {$ELSE ~HAS_UNITSCOPE}
  51. {$IFDEF MSWINDOWS}
  52. Windows, JclWin32,
  53. {$ENDIF MSWINDOWS}
  54. {$ENDIF ~HAS_UNITSCOPE}
  55. JclBase;
  56. // Locked Integer manipulation
  57. //
  58. // Routines to manipulate simple typed variables in a thread safe manner
  59. function LockedAdd(var Target: Integer; Value: Integer): Integer; overload;
  60. function LockedCompareExchange(var Target: Integer; Exch, Comp: Integer): Integer; overload;
  61. function LockedCompareExchange(var Target: TObject; Exch, Comp: TObject): TObject; overload;
  62. function LockedCompareExchange(var Target: Pointer; Exch, Comp: Pointer): Pointer; overload;
  63. function LockedDec(var Target: Integer): Integer; overload;
  64. function LockedExchange(var Target: Integer; Value: Integer): Integer; overload;
  65. function LockedExchangeAdd(var Target: Integer; Value: Integer): Integer; overload;
  66. function LockedExchangeDec(var Target: Integer): Integer; overload;
  67. function LockedExchangeInc(var Target: Integer): Integer; overload;
  68. function LockedExchangeSub(var Target: Integer; Value: Integer): Integer; overload;
  69. function LockedInc(var Target: Integer): Integer; overload;
  70. function LockedSub(var Target: Integer; Value: Integer): Integer; overload;
  71. {$IFDEF CPU64}
  72. function LockedAdd(var Target: Int64; Value: Int64): Int64; overload;
  73. function LockedCompareExchange(var Target: Int64; Exch, Comp: Int64): Int64; overload;
  74. function LockedDec(var Target: Int64): Int64; overload;
  75. function LockedExchange(var Target: Int64; Value: Int64): Int64; overload;
  76. function LockedExchangeAdd(var Target: Int64; Value: Int64): Int64; overload;
  77. function LockedExchangeDec(var Target: Int64): Int64; overload;
  78. function LockedExchangeInc(var Target: Int64): Int64; overload;
  79. function LockedExchangeSub(var Target: Int64; Value: Int64): Int64; overload;
  80. function LockedInc(var Target: Int64): Int64; overload;
  81. function LockedSub(var Target: Int64; Value: Int64): Int64; overload;
  82. {$IFDEF BORLAND}
  83. function LockedDec(var Target: NativeInt): NativeInt; overload;
  84. function LockedInc(var Target: NativeInt): NativeInt; overload;
  85. {$ENDIF BORLAND}
  86. {$ENDIF CPU64}
  87. // TJclDispatcherObject
  88. //
  89. // Base class for operating system provided synchronisation primitives
  90. type
  91. TJclWaitResult = (wrAbandoned, wrError, wrIoCompletion, wrSignaled, wrTimeout);
  92. TJclWaitHandle = THandle;
  93. TJclDispatcherObject = class(TObject)
  94. private
  95. FExisted: Boolean;
  96. FHandle: TJclWaitHandle;
  97. FName: string;
  98. public
  99. constructor Attach(AHandle: TJclWaitHandle);
  100. destructor Destroy; override;
  101. //function MsgWaitFor(const TimeOut: Cardinal): TJclWaitResult; Mask: DWORD): TJclWaitResult;
  102. //function MsgWaitForEx(const TimeOut: Cardinal): TJclWaitResult; Mask: DWORD): TJclWaitResult;
  103. function SignalAndWait(const Obj: TJclDispatcherObject; TimeOut: Cardinal;
  104. Alertable: Boolean): TJclWaitResult;
  105. function WaitAlertable(const TimeOut: Cardinal): TJclWaitResult;
  106. function WaitFor(const TimeOut: Cardinal): TJclWaitResult;
  107. function WaitForever: TJclWaitResult;
  108. property Existed: Boolean read FExisted;
  109. property Handle: TJclWaitHandle read FHandle;
  110. property Name: string read FName;
  111. end;
  112. // Wait functions
  113. //
  114. // Object enabled Wait functions (takes TJclDispatcher objects as parameter as
  115. // opposed to handles) mostly for convenience
  116. function WaitForMultipleObjects(const Objects: array of TJclDispatcherObject;
  117. WaitAll: Boolean; TimeOut: Cardinal): Cardinal;
  118. function WaitAlertableForMultipleObjects(const Objects: array of TJclDispatcherObject;
  119. WaitAll: Boolean; TimeOut: Cardinal): Cardinal;
  120. type
  121. TJclCriticalSection = class(TObject)
  122. private
  123. FCriticalSection: TRTLCriticalSection;
  124. public
  125. constructor Create; virtual;
  126. destructor Destroy; override;
  127. class procedure CreateAndEnter(var CS: TJclCriticalSection);
  128. procedure Enter;
  129. procedure Leave;
  130. end;
  131. TJclCriticalSectionEx = class(TJclCriticalSection)
  132. private
  133. FSpinCount: Cardinal;
  134. function GetSpinCount: Cardinal;
  135. procedure SetSpinCount(const Value: Cardinal);
  136. public
  137. constructor Create; override;
  138. constructor CreateEx(SpinCount: Cardinal; NoFailEnter: Boolean); virtual;
  139. class function GetSpinTimeOut: Cardinal;
  140. class procedure SetSpinTimeOut(const Value: Cardinal);
  141. function TryEnter: Boolean;
  142. property SpinCount: Cardinal read GetSpinCount write SetSpinCount;
  143. end;
  144. TJclEvent = class(TJclDispatcherObject)
  145. public
  146. constructor Create(SecAttr: PSecurityAttributes; Manual, Signaled: Boolean; const Name: string);
  147. constructor Open(Access: Cardinal; Inheritable: Boolean; const Name: string);
  148. function Pulse: Boolean;
  149. function ResetEvent: Boolean;
  150. function SetEvent: Boolean;
  151. end;
  152. TJclWaitableTimer = class(TJclDispatcherObject)
  153. private
  154. FResume: Boolean;
  155. public
  156. constructor Create(SecAttr: PSecurityAttributes; Manual: Boolean; const Name: string);
  157. constructor Open(Access: Cardinal; Inheritable: Boolean; const Name: string);
  158. function Cancel: Boolean;
  159. function SetTimer(const DueTime: Int64; Period: Longint; Resume: Boolean): Boolean;
  160. function SetTimerApc(const DueTime: Int64; Period: Longint; Resume: Boolean; Apc: TFNTimerAPCRoutine; Arg: Pointer): Boolean;
  161. end;
  162. TJclSemaphore = class(TJclDispatcherObject)
  163. public
  164. constructor Create(SecAttr: PSecurityAttributes; Initial, Maximum: Longint; const Name: string);
  165. constructor Open(Access: Cardinal; Inheritable: Boolean; const Name: string);
  166. function Release(ReleaseCount: Longint): Boolean;
  167. function ReleasePrev(ReleaseCount: Longint; var PrevCount: Longint): Boolean;
  168. end;
  169. TJclMutex = class(TJclDispatcherObject)
  170. public
  171. constructor Create(SecAttr: PSecurityAttributes; InitialOwner: Boolean;
  172. const Name: string);
  173. constructor Open(Access: Cardinal; Inheritable: Boolean; const Name: string);
  174. function Acquire(const TimeOut: Cardinal = INFINITE): Boolean;
  175. function Release: Boolean;
  176. end;
  177. POptexSharedInfo = ^TOptexSharedInfo;
  178. TOptexSharedInfo = record
  179. SpinCount: Integer; // number of times to try and enter the optex before
  180. // waiting on kernel event, 0 on single processor
  181. LockCount: Integer; // count of enter attempts
  182. ThreadId: Longword; // id of thread that owns the optex, 0 if free
  183. RecursionCount: Integer; // number of times the optex is owned, 0 if free
  184. end;
  185. TJclOptex = class(TObject)
  186. private
  187. FEvent: TJclEvent;
  188. FExisted: Boolean;
  189. FFileMapping: THandle;
  190. FName: string;
  191. FSharedInfo: POptexSharedInfo;
  192. function GetUniProcess: Boolean;
  193. function GetSpinCount: Integer;
  194. procedure SetSpinCount(Value: Integer);
  195. public
  196. constructor Create(const Name: string = ''; SpinCount: Integer = 4000);
  197. destructor Destroy; override;
  198. procedure Enter;
  199. procedure Leave;
  200. function TryEnter: Boolean;
  201. property Existed: Boolean read FExisted;
  202. property Name: string read FName;
  203. property SpinCount: Integer read GetSpinCount write SetSpinCount;
  204. property UniProcess: Boolean read GetUniProcess;
  205. end;
  206. TMrewPreferred = (mpReaders, mpWriters, mpEqual);
  207. TMrewThreadInfo = record
  208. ThreadId: Longword; // client-id of thread
  209. RecursionCount: Integer; // number of times a thread accessed the mrew
  210. Reader: Boolean; // true if reader, false if writer
  211. end;
  212. TMrewThreadInfoArray = array of TMrewThreadInfo;
  213. TJclMultiReadExclusiveWrite = class(TObject)
  214. private
  215. FLock: TJclCriticalSection;
  216. FPreferred: TMrewPreferred;
  217. FSemReaders: TJclSemaphore;
  218. FSemWriters: TJclSemaphore;
  219. FState: Integer;
  220. FThreads: TMrewThreadInfoArray;
  221. FWaitingReaders: Integer;
  222. FWaitingWriters: Integer;
  223. procedure AddToThreadList(ThreadId: Longword; Reader: Boolean);
  224. procedure RemoveFromThreadList(Index: Integer);
  225. function FindThread(ThreadId: Longword): Integer;
  226. procedure ReleaseWaiters(WasReading: Boolean);
  227. protected
  228. procedure Release;
  229. public
  230. constructor Create(Preferred: TMrewPreferred);
  231. destructor Destroy; override;
  232. procedure BeginRead;
  233. procedure BeginWrite;
  234. procedure EndRead;
  235. procedure EndWrite;
  236. end;
  237. PMetSectSharedInfo = ^TMetSectSharedInfo;
  238. TMetSectSharedInfo = record
  239. Initialized: LongBool; // Is the metered section initialized?
  240. SpinLock: Longint; // Used to gain access to this structure
  241. ThreadsWaiting: Longint; // Count of threads waiting
  242. AvailableCount: Longint; // Available resource count
  243. MaximumCount: Longint; // Maximum resource count
  244. end;
  245. PMeteredSection = ^TMeteredSection;
  246. TMeteredSection = record
  247. Event: THandle; // Handle to a kernel event object
  248. FileMap: THandle; // Handle to memory mapped file
  249. SharedInfo: PMetSectSharedInfo;
  250. end;
  251. TJclMeteredSection = class(TObject)
  252. private
  253. FMetSect: PMeteredSection;
  254. procedure CloseMeteredSection;
  255. function InitMeteredSection(InitialCount, MaxCount: Longint; const Name: string; OpenOnly: Boolean): Boolean;
  256. function CreateMetSectEvent(const Name: string; OpenOnly: Boolean): Boolean;
  257. function CreateMetSectFileView(InitialCount, MaxCount: Longint; const Name: string; OpenOnly: Boolean): Boolean;
  258. protected
  259. procedure AcquireLock;
  260. procedure ReleaseLock;
  261. public
  262. constructor Create(InitialCount, MaxCount: Longint; const Name: string);
  263. constructor Open(const Name: string);
  264. destructor Destroy; override;
  265. function Enter(TimeOut: Longword): TJclWaitResult;
  266. function Leave(ReleaseCount: Longint): Boolean; overload;
  267. function Leave(ReleaseCount: Longint; out PrevCount: Longint): Boolean; overload;
  268. end;
  269. // Debugging
  270. //
  271. // Note that the following function and structure declarations are all offically
  272. // undocumented and, except for QueryCriticalSection, require Windows NT since
  273. // it is all part of the Windows NT Native API.
  274. { TODO -cTest : Test this structures }
  275. type
  276. TEventInfo = record
  277. EventType: Longint; // 0 = manual, otherwise auto
  278. Signaled: LongBool; // true is signaled
  279. end;
  280. TMutexInfo = record
  281. SignalState: Longint; // >0 = signaled, <0 = |SignalState| recurs. acquired
  282. Owned: ByteBool; // owned by thread
  283. Abandoned: ByteBool; // is abandoned?
  284. end;
  285. TSemaphoreCounts = record
  286. CurrentCount: Longint; // current semaphore count
  287. MaximumCount: Longint; // maximum semaphore count
  288. end;
  289. TTimerInfo = record
  290. Remaining: TLargeInteger; // 100ns intervals until signaled
  291. Signaled: ByteBool; // is signaled?
  292. end;
  293. function QueryCriticalSection(CS: TJclCriticalSection; var Info: TRTLCriticalSection): Boolean;
  294. { TODO -cTest : Test these 4 functions }
  295. function QueryEvent(Handle: THandle; var Info: TEventInfo): Boolean;
  296. function QueryMutex(Handle: THandle; var Info: TMutexInfo): Boolean;
  297. function QuerySemaphore(Handle: THandle; var Info: TSemaphoreCounts): Boolean;
  298. function QueryTimer(Handle: THandle; var Info: TTimerInfo): Boolean;
  299. type
  300. // Exceptions
  301. EJclWin32HandleObjectError = class(EJclWin32Error);
  302. EJclDispatcherObjectError = class(EJclWin32Error);
  303. EJclCriticalSectionError = class(EJclWin32Error);
  304. EJclEventError = class(EJclWin32Error);
  305. EJclWaitableTimerError = class(EJclWin32Error);
  306. EJclSemaphoreError = class(EJclWin32Error);
  307. EJclMutexError = class(EJclWin32Error);
  308. EJclMeteredSectionError = class(EJclError);
  309. function ValidateMutexName(const aName: string): string;
  310. {$IFDEF UNITVERSIONING}
  311. const
  312. UnitVersioning: TUnitVersionInfo = (
  313. RCSfile: '$URL$';
  314. Revision: '$Revision$';
  315. Date: '$Date$';
  316. LogPath: 'JCL\source\common';
  317. Extra: '';
  318. Data: nil
  319. );
  320. {$ENDIF UNITVERSIONING}
  321. implementation
  322. uses
  323. {$IFDEF HAS_UNITSCOPE}
  324. System.SysUtils,
  325. {$ELSE ~HAS_UNITSCOPE}
  326. SysUtils,
  327. {$ENDIF ~HAS_UNITSCOPE}
  328. JclLogic, JclRegistry, JclResources,
  329. JclSysInfo, JclStrings;
  330. const
  331. RegSessionManager = {HKLM\} 'SYSTEM\CurrentControlSet\Control\Session Manager';
  332. RegCritSecTimeout = {RegSessionManager\} 'CriticalSectionTimeout';
  333. // Locked Integer manipulation
  334. function LockedAdd(var Target: Integer; Value: Integer): Integer;
  335. asm
  336. {$IFDEF CPU32}
  337. // --> EAX Target
  338. // EDX Value
  339. // <-- EAX Result
  340. MOV ECX, EAX
  341. MOV EAX, EDX
  342. LOCK XADD [ECX], EAX
  343. ADD EAX, EDX
  344. {$ENDIF CPU32}
  345. {$IFDEF CPU64}
  346. // --> RCX Target
  347. // EDX Value
  348. // <-- EAX Result
  349. MOV EAX, EDX
  350. LOCK XADD [RCX], EAX
  351. ADD EAX, EDX
  352. {$ENDIF CPU64}
  353. end;
  354. function LockedCompareExchange(var Target: Integer; Exch, Comp: Integer): Integer;
  355. asm
  356. {$IFDEF CPU32}
  357. // --> EAX Target
  358. // EDX Exch
  359. // ECX Comp
  360. // <-- EAX Result
  361. XCHG EAX, ECX
  362. // EAX Comp
  363. // EDX Exch
  364. // ECX Target
  365. LOCK CMPXCHG [ECX], EDX
  366. {$ENDIF CPU32}
  367. {$IFDEF CPU64}
  368. // --> RCX Target
  369. // EDX Exch
  370. // R8 Comp
  371. // <-- EAX Result
  372. MOV RAX, R8
  373. // RCX Target
  374. // EDX Exch
  375. // RAX Comp
  376. LOCK CMPXCHG [RCX], EDX
  377. {$ENDIF CPU64}
  378. end;
  379. function LockedCompareExchange(var Target: Pointer; Exch, Comp: Pointer): Pointer;
  380. asm
  381. {$IFDEF CPU32}
  382. // --> EAX Target
  383. // EDX Exch
  384. // ECX Comp
  385. // <-- EAX Result
  386. XCHG EAX, ECX
  387. // EAX Comp
  388. // EDX Exch
  389. // ECX Target
  390. LOCK CMPXCHG [ECX], EDX
  391. {$ENDIF CPU32}
  392. {$IFDEF CPU64}
  393. // --> RCX Target
  394. // RDX Exch
  395. // R8 Comp
  396. // <-- RAX Result
  397. MOV RAX, R8
  398. // RCX Target
  399. // RDX Exch
  400. // RAX Comp
  401. LOCK CMPXCHG [RCX], RDX
  402. {$ENDIF CPU64}
  403. end;
  404. function LockedCompareExchange(var Target: TObject; Exch, Comp: TObject): TObject;
  405. asm
  406. {$IFDEF CPU32}
  407. // --> EAX Target
  408. // EDX Exch
  409. // ECX Comp
  410. // <-- EAX Result
  411. XCHG EAX, ECX
  412. // EAX Comp
  413. // EDX Exch
  414. // ECX Target
  415. LOCK CMPXCHG [ECX], EDX
  416. {$ENDIF CPU32}
  417. {$IFDEF CPU64}
  418. // --> RCX Target
  419. // RDX Exch
  420. // R8 Comp
  421. // <-- RAX Result
  422. MOV RAX, R8
  423. // --> RCX Target
  424. // RDX Exch
  425. // RAX Comp
  426. LOCK CMPXCHG [RCX], RDX
  427. {$ENDIF CPU64}
  428. end;
  429. function LockedDec(var Target: Integer): Integer;
  430. asm
  431. {$IFDEF CPU32}
  432. // --> EAX Target
  433. // <-- EAX Result
  434. MOV ECX, EAX
  435. MOV EAX, -1
  436. LOCK XADD [ECX], EAX
  437. DEC EAX
  438. {$ENDIF CPU32}
  439. {$IFDEF CPU64}
  440. // --> RCX Target
  441. // <-- EAX Result
  442. MOV EAX, -1
  443. LOCK XADD [RCX], EAX
  444. DEC EAX
  445. {$ENDIF CPU64}
  446. end;
  447. function LockedExchange(var Target: Integer; Value: Integer): Integer;
  448. asm
  449. {$IFDEF CPU32}
  450. // --> EAX Target
  451. // EDX Value
  452. // <-- EAX Result
  453. MOV ECX, EAX
  454. MOV EAX, EDX
  455. // ECX Target
  456. // EAX Value
  457. LOCK XCHG [ECX], EAX
  458. {$ENDIF CPU32}
  459. {$IFDEF CPU64}
  460. // --> RCX Target
  461. // EDX Value
  462. // <-- EAX Result
  463. MOV EAX, EDX
  464. // RCX Target
  465. // EAX Value
  466. LOCK XCHG [RCX], EAX
  467. {$ENDIF CPU64}
  468. end;
  469. function LockedExchangeAdd(var Target: Integer; Value: Integer): Integer;
  470. asm
  471. {$IFDEF CPU32}
  472. // --> EAX Target
  473. // EDX Value
  474. // <-- EAX Result
  475. MOV ECX, EAX
  476. MOV EAX, EDX
  477. // ECX Target
  478. // EAX Value
  479. LOCK XADD [ECX], EAX
  480. {$ENDIF CPU32}
  481. {$IFDEF CPU64}
  482. // --> RCX Target
  483. // EDX Value
  484. // <-- EAX Result
  485. MOV EAX, EDX
  486. // RCX Target
  487. // EAX Value
  488. LOCK XADD [RCX], EAX
  489. {$ENDIF CPU64}
  490. end;
  491. function LockedExchangeDec(var Target: Integer): Integer;
  492. asm
  493. {$IFDEF CPU32}
  494. // --> EAX Target
  495. // <-- EAX Result
  496. MOV ECX, EAX
  497. MOV EAX, -1
  498. LOCK XADD [ECX], EAX
  499. {$ENDIF CPU32}
  500. {$IFDEF CPU64}
  501. // --> RCX Target
  502. // <-- EAX Result
  503. MOV EAX, -1
  504. LOCK XADD [RCX], EAX
  505. {$ENDIF CPU64}
  506. end;
  507. function LockedExchangeInc(var Target: Integer): Integer;
  508. asm
  509. {$IFDEF CPU32}
  510. // --> EAX Target
  511. // <-- EAX Result
  512. MOV ECX, EAX
  513. MOV EAX, 1
  514. LOCK XADD [ECX], EAX
  515. {$ENDIF CPU32}
  516. {$IFDEF CPU64}
  517. // --> RCX Target
  518. // <-- EAX Result
  519. MOV EAX, 1
  520. LOCK XADD [RCX], EAX
  521. {$ENDIF CPU64}
  522. end;
  523. function LockedExchangeSub(var Target: Integer; Value: Integer): Integer;
  524. asm
  525. {$IFDEF CPU32}
  526. // --> EAX Target
  527. // EDX Value
  528. // <-- EAX Result
  529. MOV ECX, EAX
  530. NEG EDX
  531. MOV EAX, EDX
  532. // ECX Target
  533. // EAX -Value
  534. LOCK XADD [ECX], EAX
  535. {$ENDIF CPU32}
  536. {$IFDEF CPU64}
  537. // --> RCX Target
  538. // EDX Value
  539. // <-- EAX Result
  540. NEG EDX
  541. MOV EAX, EDX
  542. // RCX Target
  543. // EAX -Value
  544. LOCK XADD [RCX], EAX
  545. {$ENDIF CPU64}
  546. end;
  547. function LockedInc(var Target: Integer): Integer;
  548. asm
  549. {$IFDEF CPU32}
  550. // --> EAX Target
  551. // <-- EAX Result
  552. MOV ECX, EAX
  553. MOV EAX, 1
  554. LOCK XADD [ECX], EAX
  555. INC EAX
  556. {$ENDIF CPU32}
  557. {$IFDEF CPU64}
  558. // --> RCX Target
  559. // <-- EAX Result
  560. MOV EAX, 1
  561. LOCK XADD [RCX], EAX
  562. INC EAX
  563. {$ENDIF CPU64}
  564. end;
  565. function LockedSub(var Target: Integer; Value: Integer): Integer;
  566. asm
  567. {$IFDEF CPU32}
  568. // --> EAX Target
  569. // EDX Value
  570. // <-- EAX Result
  571. MOV ECX, EAX
  572. NEG EDX
  573. MOV EAX, EDX
  574. LOCK XADD [ECX], EAX
  575. ADD EAX, EDX
  576. {$ENDIF CPU32}
  577. {$IFDEF CPU64}
  578. // --> RCX Target
  579. // EDX Value
  580. // <-- EAX Result
  581. NEG EDX
  582. MOV EAX, EDX
  583. LOCK XADD [RCX], EAX
  584. ADD EAX, EDX
  585. {$ENDIF CPU64}
  586. end;
  587. {$IFDEF CPU64}
  588. // Locked Int64 manipulation
  589. function LockedAdd(var Target: Int64; Value: Int64): Int64;
  590. asm
  591. // --> RCX Target
  592. // RDX Value
  593. // <-- RAX Result
  594. MOV RAX, RDX
  595. LOCK XADD [RCX], RAX
  596. ADD RAX, RDX
  597. end;
  598. function LockedCompareExchange(var Target: Int64; Exch, Comp: Int64): Int64;
  599. asm
  600. // --> RCX Target
  601. // RDX Exch
  602. // R8 Comp
  603. // <-- RAX Result
  604. MOV RAX, R8
  605. LOCK CMPXCHG [RCX], RDX
  606. end;
  607. function LockedDec(var Target: Int64): Int64;
  608. asm
  609. // --> RCX Target
  610. // <-- RAX Result
  611. MOV RAX, -1
  612. LOCK XADD [RCX], RAX
  613. DEC RAX
  614. end;
  615. function LockedExchange(var Target: Int64; Value: Int64): Int64;
  616. asm
  617. // --> RCX Target
  618. // RDX Value
  619. // <-- RAX Result
  620. MOV RAX, RDX
  621. LOCK XCHG [RCX], RAX
  622. end;
  623. function LockedExchangeAdd(var Target: Int64; Value: Int64): Int64;
  624. asm
  625. // --> RCX Target
  626. // RDX Value
  627. // <-- RAX Result
  628. MOV RAX, RDX
  629. LOCK XADD [RCX], RAX
  630. end;
  631. function LockedExchangeDec(var Target: Int64): Int64;
  632. asm
  633. // --> RCX Target
  634. // <-- RAX Result
  635. MOV RAX, -1
  636. LOCK XADD [RCX], RAX
  637. end;
  638. function LockedExchangeInc(var Target: Int64): Int64;
  639. asm
  640. // --> RCX Target
  641. // <-- RAX Result
  642. MOV RAX, 1
  643. LOCK XADD [RCX], RAX
  644. end;
  645. function LockedExchangeSub(var Target: Int64; Value: Int64): Int64;
  646. asm
  647. // --> RCX Target
  648. // RDX Value
  649. // <-- RAX Result
  650. NEG RDX
  651. MOV RAX, RDX
  652. LOCK XADD [RCX], RAX
  653. end;
  654. function LockedInc(var Target: Int64): Int64;
  655. asm
  656. // --> RCX Target
  657. // <-- RAX Result
  658. MOV RAX, 1
  659. LOCK XADD [RCX], RAX
  660. INC RAX
  661. end;
  662. function LockedSub(var Target: Int64; Value: Int64): Int64;
  663. asm
  664. // --> RCX Target
  665. // RDX Value
  666. // <-- RAX Result
  667. NEG RDX
  668. MOV RAX, RDX
  669. LOCK XADD [RCX], RAX
  670. ADD RAX, RDX
  671. end;
  672. {$IFDEF BORLAND}
  673. function LockedDec(var Target: NativeInt): NativeInt;
  674. asm
  675. // --> RCX Target
  676. // <-- RAX Result
  677. MOV RAX, -1
  678. LOCK XADD [RCX], RAX
  679. DEC RAX
  680. end;
  681. function LockedInc(var Target: NativeInt): NativeInt;
  682. asm
  683. // --> RCX Target
  684. // <-- RAX Result
  685. MOV RAX, 1
  686. LOCK XADD [RCX], RAX
  687. INC RAX
  688. end;
  689. {$ENDIF BORLAND}
  690. {$ENDIF CPU64}
  691. //=== { TJclDispatcherObject } ===============================================
  692. function MapSignalResult(const Ret: DWORD): TJclWaitResult;
  693. begin
  694. case Ret of
  695. WAIT_ABANDONED:
  696. Result := wrAbandoned;
  697. WAIT_OBJECT_0:
  698. Result := wrSignaled;
  699. WAIT_TIMEOUT:
  700. Result := wrTimeout;
  701. WAIT_IO_COMPLETION:
  702. Result := wrIoCompletion;
  703. WAIT_FAILED:
  704. Result := wrError;
  705. else
  706. Result := wrError;
  707. end;
  708. end;
  709. constructor TJclDispatcherObject.Attach(AHandle: TJclWaitHandle);
  710. begin
  711. inherited Create;
  712. FExisted := True;
  713. FHandle := AHandle;
  714. FName := '';
  715. end;
  716. destructor TJclDispatcherObject.Destroy;
  717. begin
  718. CloseHandle(FHandle);
  719. inherited Destroy;
  720. end;
  721. { TODO: Use RTDL Version of SignalObjectAndWait }
  722. function TJclDispatcherObject.SignalAndWait(const Obj: TJclDispatcherObject;
  723. TimeOut: Cardinal; Alertable: Boolean): TJclWaitResult;
  724. begin
  725. // Note: Do not make this method virtual! It's only available on NT 4 up...
  726. Result := MapSignalResult(Cardinal({$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.SignalObjectAndWait(Obj.Handle, Handle, TimeOut, Alertable)));
  727. end;
  728. function TJclDispatcherObject.WaitAlertable(const TimeOut: Cardinal): TJclWaitResult;
  729. begin
  730. Result := MapSignalResult({$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.WaitForSingleObjectEx(FHandle, TimeOut, True));
  731. end;
  732. function TJclDispatcherObject.WaitFor(const TimeOut: Cardinal): TJclWaitResult;
  733. begin
  734. Result := MapSignalResult({$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.WaitForSingleObject(FHandle, TimeOut));
  735. end;
  736. function TJclDispatcherObject.WaitForever: TJclWaitResult;
  737. begin
  738. Result := WaitFor(INFINITE);
  739. end;
  740. // Wait functions
  741. function WaitForMultipleObjects(const Objects: array of TJclDispatcherObject;
  742. WaitAll: Boolean; TimeOut: Cardinal): Cardinal;
  743. var
  744. Handles: array of TJclWaitHandle;
  745. I, Count: Integer;
  746. begin
  747. Count := High(Objects) + 1;
  748. SetLength(Handles, Count);
  749. for I := 0 to Count - 1 do
  750. Handles[I] := Objects[I].Handle;
  751. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.WaitForMultipleObjects(Count, @Handles[0], WaitAll, TimeOut);
  752. end;
  753. function WaitAlertableForMultipleObjects(const Objects: array of TJclDispatcherObject;
  754. WaitAll: Boolean; TimeOut: Cardinal): Cardinal;
  755. var
  756. Handles: array of TJclWaitHandle;
  757. I, Count: Integer;
  758. begin
  759. Count := High(Objects) + 1;
  760. SetLength(Handles, Count);
  761. for I := 0 to Count - 1 do
  762. Handles[I] := Objects[I].Handle;
  763. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.WaitForMultipleObjectsEx(Count, @Handles[0], WaitAll, TimeOut, True);
  764. end;
  765. //=== { TJclCriticalSection } ================================================
  766. constructor TJclCriticalSection.Create;
  767. begin
  768. inherited Create;
  769. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InitializeCriticalSection(FCriticalSection);
  770. end;
  771. destructor TJclCriticalSection.Destroy;
  772. begin
  773. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.DeleteCriticalSection(FCriticalSection);
  774. inherited Destroy;
  775. end;
  776. class procedure TJclCriticalSection.CreateAndEnter(var CS: TJclCriticalSection);
  777. var
  778. NewCritSect: TJclCriticalSection;
  779. begin
  780. NewCritSect := TJclCriticalSection.Create;
  781. if LockedCompareExchange(Pointer(CS), Pointer(NewCritSect), nil) <> nil then
  782. begin
  783. // LoadInProgress was <> nil -> no exchange took place, free the CS
  784. NewCritSect.Free;
  785. end;
  786. CS.Enter;
  787. end;
  788. procedure TJclCriticalSection.Enter;
  789. begin
  790. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.EnterCriticalSection(FCriticalSection);
  791. end;
  792. procedure TJclCriticalSection.Leave;
  793. begin
  794. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.LeaveCriticalSection(FCriticalSection);
  795. end;
  796. //== { TJclCriticalSectionEx } ===============================================
  797. const
  798. DefaultCritSectSpinCount = 4000;
  799. constructor TJclCriticalSectionEx.Create;
  800. begin
  801. CreateEx(DefaultCritSectSpinCount, False);
  802. end;
  803. { TODO: Use RTDL Version of InitializeCriticalSectionAndSpinCount }
  804. constructor TJclCriticalSectionEx.CreateEx(SpinCount: Cardinal;
  805. NoFailEnter: Boolean);
  806. begin
  807. FSpinCount := SpinCount;
  808. if NoFailEnter then
  809. SpinCount := SpinCount or Cardinal($80000000);
  810. if not InitializeCriticalSectionAndSpinCount(FCriticalSection, SpinCount) then
  811. raise EJclCriticalSectionError.CreateRes(@RsSynchInitCriticalSection);
  812. end;
  813. function TJclCriticalSectionEx.GetSpinCount: Cardinal;
  814. begin
  815. // Spinning only makes sense on multiprocessor systems. On a single processor
  816. // system the thread would simply waste cycles while the owning thread is
  817. // suspended and thus cannot release the critical section.
  818. if ProcessorCount = 1 then
  819. Result := 0
  820. else
  821. Result := FSpinCount;
  822. end;
  823. class function TJclCriticalSectionEx.GetSpinTimeOut: Cardinal;
  824. begin
  825. Result := Cardinal(RegReadInteger(HKEY_LOCAL_MACHINE, RegSessionManager,
  826. RegCritSecTimeout));
  827. end;
  828. { TODO: Use RTLD version of SetCriticalSectionSpinCount }
  829. procedure TJclCriticalSectionEx.SetSpinCount(const Value: Cardinal);
  830. begin
  831. FSpinCount := SetCriticalSectionSpinCount(FCriticalSection, Value);
  832. end;
  833. class procedure TJclCriticalSectionEx.SetSpinTimeOut(const Value: Cardinal);
  834. begin
  835. RegWriteInteger(HKEY_LOCAL_MACHINE, RegSessionManager, RegCritSecTimeout,
  836. Integer(Value));
  837. end;
  838. { TODO: Use RTLD version of TryEnterCriticalSection }
  839. function TJclCriticalSectionEx.TryEnter: Boolean;
  840. begin
  841. Result := TryEnterCriticalSection(FCriticalSection);
  842. end;
  843. //== { TJclEvent } ===========================================================
  844. constructor TJclEvent.Create(SecAttr: PSecurityAttributes; Manual, Signaled: Boolean; const Name: string);
  845. begin
  846. inherited Create;
  847. FName := Name;
  848. FHandle := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CreateEvent(SecAttr, Manual, Signaled, PChar(FName));
  849. if FHandle = 0 then
  850. raise EJclEventError.CreateRes(@RsSynchCreateEvent);
  851. FExisted := GetLastError = ERROR_ALREADY_EXISTS;
  852. end;
  853. constructor TJclEvent.Open(Access: Cardinal; Inheritable: Boolean;
  854. const Name: string);
  855. begin
  856. FName := Name;
  857. FExisted := True;
  858. FHandle := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.OpenEvent(Access, Inheritable, PChar(Name));
  859. if FHandle = 0 then
  860. raise EJclEventError.CreateRes(@RsSynchOpenEvent);
  861. end;
  862. function TJclEvent.Pulse: Boolean;
  863. begin
  864. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.PulseEvent(FHandle);
  865. end;
  866. function TJclEvent.ResetEvent: Boolean;
  867. begin
  868. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.ResetEvent(FHandle);
  869. end;
  870. function TJclEvent.SetEvent: Boolean;
  871. begin
  872. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.SetEvent(FHandle);
  873. end;
  874. //=== { TJclWaitableTimer } ==================================================
  875. { TODO: Use RTLD version of CreateWaitableTimer }
  876. constructor TJclWaitableTimer.Create(SecAttr: PSecurityAttributes;
  877. Manual: Boolean; const Name: string);
  878. begin
  879. FName := Name;
  880. FResume := False;
  881. FHandle := CreateWaitableTimer(SecAttr, Manual, PChar(Name));
  882. if FHandle = 0 then
  883. raise EJclWaitableTimerError.CreateRes(@RsSynchCreateWaitableTimer);
  884. FExisted := GetLastError = ERROR_ALREADY_EXISTS;
  885. end;
  886. { TODO: Use RTLD version of CancelWaitableTimer }
  887. function TJclWaitableTimer.Cancel: Boolean;
  888. begin
  889. Result := CancelWaitableTimer(FHandle);
  890. end;
  891. { TODO: Use RTLD version of OpenWaitableTimer }
  892. constructor TJclWaitableTimer.Open(Access: Cardinal; Inheritable: Boolean;
  893. const Name: string);
  894. begin
  895. FExisted := True;
  896. FName := Name;
  897. FResume := False;
  898. FHandle := OpenWaitableTimer(Access, Inheritable, PChar(Name));
  899. if FHandle = 0 then
  900. raise EJclWaitableTimerError.CreateRes(@RsSynchOpenWaitableTimer);
  901. end;
  902. { TODO: Use RTLD version of SetWaitableTimer }
  903. function TJclWaitableTimer.SetTimer(const DueTime: Int64; Period: Longint;
  904. Resume: Boolean): Boolean;
  905. var
  906. DT: Int64;
  907. begin
  908. DT := DueTime;
  909. FResume := Resume;
  910. Result := SetWaitableTimer(FHandle, DT, Period, nil, nil, FResume);
  911. end;
  912. { TODO -cHelp : OS restrictions }
  913. function TJclWaitableTimer.SetTimerApc(const DueTime: Int64; Period: Longint;
  914. Resume: Boolean; Apc: TFNTimerAPCRoutine; Arg: Pointer): Boolean;
  915. var
  916. DT: Int64;
  917. begin
  918. DT := DueTime;
  919. FResume := Resume;
  920. Result := RtdlSetWaitableTimer(FHandle, DT, Period, Apc, Arg, FResume);
  921. { TODO : Exception for Win9x, older WinNT? }
  922. // if not Result and (GetLastError = ERROR_CALL_NOT_IMPLEMENTED) then
  923. // RaiseLastOSError;
  924. end;
  925. //== { TJclSemaphore } =======================================================
  926. constructor TJclSemaphore.Create(SecAttr: PSecurityAttributes;
  927. Initial, Maximum: Integer; const Name: string);
  928. begin
  929. Assert((Initial >= 0) and (Maximum > 0));
  930. FName := Name;
  931. FHandle := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CreateSemaphore(SecAttr, Initial, Maximum, PChar(Name));
  932. if FHandle = 0 then
  933. raise EJclSemaphoreError.CreateRes(@RsSynchCreateSemaphore);
  934. FExisted := GetLastError = ERROR_ALREADY_EXISTS;
  935. end;
  936. constructor TJclSemaphore.Open(Access: Cardinal; Inheritable: Boolean;
  937. const Name: string);
  938. begin
  939. FName := Name;
  940. FExisted := True;
  941. FHandle := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.OpenSemaphore(Access, Inheritable, PChar(Name));
  942. if FHandle = 0 then
  943. raise EJclSemaphoreError.CreateRes(@RsSynchOpenSemaphore);
  944. end;
  945. function TJclSemaphore.ReleasePrev(ReleaseCount: Longint;
  946. var PrevCount: Longint): Boolean;
  947. begin
  948. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.ReleaseSemaphore(FHandle, ReleaseCount, @PrevCount);
  949. end;
  950. function TJclSemaphore.Release(ReleaseCount: Integer): Boolean;
  951. begin
  952. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.ReleaseSemaphore(FHandle, ReleaseCount, nil);
  953. end;
  954. //=== { TJclMutex } ==========================================================
  955. function TJclMutex.Acquire(const TimeOut: Cardinal): Boolean;
  956. begin
  957. Result := WaitFor(TimeOut) = wrSignaled;
  958. end;
  959. constructor TJclMutex.Create(SecAttr: PSecurityAttributes; InitialOwner: Boolean; const Name: string);
  960. begin
  961. inherited Create;
  962. FName := Name;
  963. FHandle := JclWin32.CreateMutex(SecAttr, Ord(InitialOwner), PChar(Name));
  964. if FHandle = 0 then
  965. raise EJclMutexError.CreateRes(@RsSynchCreateMutex);
  966. FExisted := GetLastError = ERROR_ALREADY_EXISTS;
  967. end;
  968. constructor TJclMutex.Open(Access: Cardinal; Inheritable: Boolean; const Name: string);
  969. begin
  970. inherited Create;
  971. FName := Name;
  972. FExisted := True;
  973. FHandle := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.OpenMutex(Access, Inheritable, PChar(Name));
  974. if FHandle = 0 then
  975. raise EJclMutexError.CreateRes(@RsSynchOpenMutex);
  976. end;
  977. function TJclMutex.Release: Boolean;
  978. begin
  979. Result := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.ReleaseMutex(FHandle);
  980. end;
  981. //=== { TJclOptex } ==========================================================
  982. constructor TJclOptex.Create(const Name: string; SpinCount: Integer);
  983. begin
  984. FExisted := False;
  985. FName := Name;
  986. if Name = '' then
  987. begin
  988. // None shared optex, don't need filemapping, sharedinfo is local
  989. FFileMapping := 0;
  990. FEvent := TJclEvent.Create(nil, False, False, '');
  991. FSharedInfo := AllocMem(SizeOf(TOptexSharedInfo));
  992. end
  993. else
  994. begin
  995. // Shared optex, event protects access to sharedinfo. Creation of filemapping
  996. // doesn't need protection as it will automatically "open" instead of "create"
  997. // if another process already created it.
  998. FEvent := TJclEvent.Create(nil, False, False, 'Optex_Event_' + Name);
  999. FExisted := FEvent.Existed;
  1000. FFileMapping := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE,
  1001. 0, SizeOf(TOptexSharedInfo), PChar('Optex_MMF_' + Name));
  1002. Assert(FFileMapping <> 0);
  1003. FSharedInfo := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.MapViewOfFile(FFileMapping, FILE_MAP_WRITE, 0, 0, 0);
  1004. Assert(FSharedInfo <> nil);
  1005. end;
  1006. SetSpinCount(SpinCount);
  1007. end;
  1008. destructor TJclOptex.Destroy;
  1009. begin
  1010. FreeAndNil(FEvent);
  1011. if UniProcess then
  1012. FreeMem(FSharedInfo)
  1013. else
  1014. begin
  1015. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.UnmapViewOfFile(FSharedInfo);
  1016. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CloseHandle(FFileMapping);
  1017. end;
  1018. inherited Destroy;
  1019. end;
  1020. procedure TJclOptex.Enter;
  1021. var
  1022. ThreadId: Longword;
  1023. begin
  1024. if TryEnter then
  1025. Exit;
  1026. ThreadId := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetCurrentThreadId;
  1027. if {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedIncrement(FSharedInfo^.LockCount) = 1 then
  1028. begin
  1029. // Optex was unowned
  1030. FSharedInfo^.ThreadId := ThreadId;
  1031. FSharedInfo^.RecursionCount := 1;
  1032. end
  1033. else
  1034. begin
  1035. if FSharedInfo^.ThreadId = ThreadId then
  1036. begin
  1037. // We already owned it, increase ownership count
  1038. Inc(FSharedInfo^.RecursionCount)
  1039. end
  1040. else
  1041. begin
  1042. // Optex is owner by someone else, wait for it to be released and then
  1043. // immediately take ownership
  1044. FEvent.WaitForever;
  1045. FSharedInfo^.ThreadId := ThreadId;
  1046. FSharedInfo^.RecursionCount := 1;
  1047. end;
  1048. end;
  1049. end;
  1050. function TJclOptex.GetSpinCount: Integer;
  1051. begin
  1052. Result := FSharedInfo^.SpinCount;
  1053. end;
  1054. function TJclOptex.GetUniProcess: Boolean;
  1055. begin
  1056. Result := FFileMapping = 0;
  1057. end;
  1058. procedure TJclOptex.Leave;
  1059. begin
  1060. Dec(FSharedInfo^.RecursionCount);
  1061. if FSharedInfo^.RecursionCount > 0 then
  1062. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedDecrement(FSharedInfo^.LockCount)
  1063. else
  1064. begin
  1065. FSharedInfo^.ThreadId := 0;
  1066. if {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedDecrement(FSharedInfo^.LockCount) > 0 then
  1067. FEvent.SetEvent;
  1068. end;
  1069. end;
  1070. procedure TJclOptex.SetSpinCount(Value: Integer);
  1071. begin
  1072. if Value < 0 then
  1073. Value := DefaultCritSectSpinCount;
  1074. // Spinning only makes sense on multiprocessor systems
  1075. if ProcessorCount > 1 then
  1076. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedExchange(Integer(FSharedInfo^.SpinCount), Value);
  1077. end;
  1078. function TJclOptex.TryEnter: Boolean;
  1079. var
  1080. ThreadId: Longword;
  1081. ThreadOwnsOptex: Boolean;
  1082. SpinCount: Integer;
  1083. begin
  1084. ThreadId := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetCurrentThreadId;
  1085. SpinCount := FSharedInfo^.SpinCount;
  1086. repeat
  1087. //ThreadOwnsOptex := InterlockedCompareExchange(Pointer(FSharedInfo^.LockCount),
  1088. // Pointer(1), Pointer(0)) = Pointer(0); // not available on win95
  1089. ThreadOwnsOptex := LockedCompareExchange(FSharedInfo^.LockCount, 1, 0) = 0;
  1090. if ThreadOwnsOptex then
  1091. begin
  1092. // Optex was unowned
  1093. FSharedInfo^.ThreadId := ThreadId;
  1094. FSharedInfo^.RecursionCount := 1;
  1095. end
  1096. else
  1097. begin
  1098. if FSharedInfo^.ThreadId = ThreadId then
  1099. begin
  1100. // We already owned the Optex
  1101. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedIncrement(FSharedInfo^.LockCount);
  1102. Inc(FSharedInfo^.RecursionCount);
  1103. ThreadOwnsOptex := True;
  1104. end;
  1105. end;
  1106. Dec(SpinCount);
  1107. until ThreadOwnsOptex or (SpinCount <= 0);
  1108. Result := ThreadOwnsOptex;
  1109. end;
  1110. //=== { TJclMultiReadExclusiveWrite } ========================================
  1111. constructor TJclMultiReadExclusiveWrite.Create(Preferred: TMrewPreferred);
  1112. begin
  1113. inherited Create;
  1114. FLock := TJclCriticalSection.Create;
  1115. FPreferred := Preferred;
  1116. FSemReaders := TJclSemaphore.Create(nil, 0, MaxInt, '');
  1117. FSemWriters := TJclSemaphore.Create(nil, 0, MaxInt, '');
  1118. SetLength(FThreads, 0);
  1119. FState := 0;
  1120. FWaitingReaders := 0;
  1121. FWaitingWriters := 0;
  1122. end;
  1123. destructor TJclMultiReadExclusiveWrite.Destroy;
  1124. begin
  1125. FreeAndNil(FSemReaders);
  1126. FreeAndNil(FSemWriters);
  1127. FreeAndNil(FLock);
  1128. inherited Destroy;
  1129. end;
  1130. procedure TJclMultiReadExclusiveWrite.AddToThreadList(ThreadId: Longword;
  1131. Reader: Boolean);
  1132. var
  1133. L: Integer;
  1134. begin
  1135. // Caller must own lock
  1136. L := Length(FThreads);
  1137. SetLength(FThreads, L + 1);
  1138. FThreads[L].ThreadId := ThreadId;
  1139. FThreads[L].RecursionCount := 1;
  1140. FThreads[L].Reader := Reader;
  1141. end;
  1142. procedure TJclMultiReadExclusiveWrite.BeginRead;
  1143. var
  1144. ThreadId: Longword;
  1145. Index: Integer;
  1146. MustWait: Boolean;
  1147. begin
  1148. MustWait := False;
  1149. ThreadId := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetCurrentThreadId;
  1150. FLock.Enter;
  1151. try
  1152. Index := FindThread(ThreadId);
  1153. if Index >= 0 then
  1154. begin
  1155. // Thread is on threadslist so it is already reading
  1156. Inc(FThreads[Index].RecursionCount);
  1157. end
  1158. else
  1159. begin
  1160. // Request to read (first time)
  1161. AddToThreadList(ThreadId, True);
  1162. if FState >= 0 then
  1163. begin
  1164. // MREW is unowned or only readers. If there are no waiting writers or
  1165. // readers are preferred then allow thread to continue, otherwise it must
  1166. // wait it's turn
  1167. if (FPreferred = mpReaders) or (FWaitingWriters = 0) then
  1168. Inc(FState)
  1169. else
  1170. begin
  1171. Inc(FWaitingReaders);
  1172. MustWait := True;
  1173. end;
  1174. end
  1175. else
  1176. begin
  1177. // MREW is owner by a writer, must wait
  1178. Inc(FWaitingReaders);
  1179. MustWait := True;
  1180. end;
  1181. end;
  1182. finally
  1183. FLock.Leave;
  1184. end;
  1185. if MustWait then
  1186. FSemReaders.WaitForever;
  1187. end;
  1188. procedure TJclMultiReadExclusiveWrite.BeginWrite;
  1189. var
  1190. ThreadId: Longword;
  1191. Index: Integer;
  1192. MustWait: Boolean;
  1193. begin
  1194. MustWait := False;
  1195. FLock.Enter;
  1196. try
  1197. ThreadId := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.GetCurrentThreadId;
  1198. Index := FindThread(ThreadId);
  1199. if Index < 0 then
  1200. begin
  1201. // Request to write (first time)
  1202. AddToThreadList(ThreadId, False);
  1203. if FState = 0 then
  1204. begin
  1205. // MREW is unowned so start writing
  1206. FState := -1;
  1207. end
  1208. else
  1209. begin
  1210. // MREW is owner, must wait
  1211. Inc(FWaitingWriters);
  1212. MustWait := True;
  1213. end;
  1214. end
  1215. else
  1216. begin
  1217. if FThreads[Index].Reader then
  1218. begin
  1219. // Request to write while reading
  1220. Inc(FThreads[Index].RecursionCount);
  1221. FThreads[Index].Reader := False;
  1222. Dec(FState);
  1223. if FState = 0 then
  1224. begin
  1225. // MREW is unowned so start writing
  1226. FState := -1;
  1227. end
  1228. else
  1229. begin
  1230. // MREW is owned, must wait
  1231. MustWait := True;
  1232. Inc(FWaitingWriters);
  1233. end;
  1234. end
  1235. else
  1236. // Requesting to write while already writing
  1237. Inc(FThreads[Index].RecursionCount);
  1238. end;
  1239. finally
  1240. FLock.Leave;
  1241. end;
  1242. if MustWait then
  1243. FSemWriters.WaitFor(INFINITE);
  1244. end;
  1245. procedure TJclMultiReadExclusiveWrite.EndRead;
  1246. begin
  1247. Release;
  1248. end;
  1249. procedure TJclMultiReadExclusiveWrite.EndWrite;
  1250. begin
  1251. Release;
  1252. end;
  1253. function TJclMultiReadExclusiveWrite.FindThread(ThreadId: Longword): Integer;
  1254. var
  1255. I: Integer;
  1256. begin
  1257. // Caller must lock
  1258. Result := -1;
  1259. for I := 0 to Length(FThreads) - 1 do
  1260. if FThreads[I].ThreadId = ThreadId then
  1261. begin
  1262. Result := I;
  1263. Exit;
  1264. end;
  1265. end;
  1266. procedure TJclMultiReadExclusiveWrite.Release;
  1267. var
  1268. ThreadId: Longword;
  1269. Index: Integer;
  1270. WasReading: Boolean;
  1271. begin
  1272. ThreadId := GetCurrentThreadId;
  1273. FLock.Enter;
  1274. try
  1275. Index := FindThread(ThreadId);
  1276. if Index >= 0 then
  1277. begin
  1278. Dec(FThreads[Index].RecursionCount);
  1279. if FThreads[Index].RecursionCount = 0 then
  1280. begin
  1281. WasReading := FThreads[Index].Reader;
  1282. if WasReading then
  1283. Dec(FState)
  1284. else
  1285. FState := 0;
  1286. RemoveFromThreadList(Index);
  1287. if FState = 0 then
  1288. ReleaseWaiters(WasReading);
  1289. end;
  1290. end;
  1291. finally
  1292. FLock.Leave;
  1293. end;
  1294. end;
  1295. procedure TJclMultiReadExclusiveWrite.ReleaseWaiters(WasReading: Boolean);
  1296. var
  1297. ToRelease: TMrewPreferred;
  1298. begin
  1299. // Caller must Lock
  1300. ToRelease := mpEqual;
  1301. case FPreferred of
  1302. mpReaders:
  1303. if FWaitingReaders > 0 then
  1304. ToRelease := mpReaders
  1305. else
  1306. if FWaitingWriters > 0 then
  1307. ToRelease := mpWriters;
  1308. mpWriters:
  1309. if FWaitingWriters > 0 then
  1310. ToRelease := mpWriters
  1311. else
  1312. if FWaitingReaders > 0 then
  1313. ToRelease := mpReaders;
  1314. mpEqual:
  1315. if WasReading then
  1316. begin
  1317. if FWaitingWriters > 0 then
  1318. ToRelease := mpWriters
  1319. else
  1320. if FWaitingReaders > 0 then
  1321. ToRelease := mpReaders;
  1322. end
  1323. else
  1324. begin
  1325. if FWaitingReaders > 0 then
  1326. ToRelease := mpReaders
  1327. else
  1328. if FWaitingWriters > 0 then
  1329. ToRelease := mpWriters;
  1330. end;
  1331. end;
  1332. case ToRelease of
  1333. mpReaders:
  1334. begin
  1335. FState := FWaitingReaders;
  1336. FWaitingReaders := 0;
  1337. FSemReaders.Release(FState);
  1338. end;
  1339. mpWriters:
  1340. begin
  1341. FState := -1;
  1342. Dec(FWaitingWriters);
  1343. FSemWriters.Release(1);
  1344. end;
  1345. mpEqual:
  1346. // no waiters
  1347. end;
  1348. end;
  1349. procedure TJclMultiReadExclusiveWrite.RemoveFromThreadList(Index: Integer);
  1350. var
  1351. L: Integer;
  1352. begin
  1353. // Caller must Lock
  1354. L := Length(FThreads);
  1355. if Index < (L - 1) then
  1356. Move(FThreads[Index + 1], FThreads[Index], SizeOf(TMrewThreadInfo) * (L - Index - 1));
  1357. SetLength(FThreads, L - 1);
  1358. end;
  1359. //=== { TJclMeteredSection } =================================================
  1360. const
  1361. MAX_METSECT_NAMELEN = 128;
  1362. constructor TJclMeteredSection.Create(InitialCount, MaxCount: Integer; const Name: string);
  1363. begin
  1364. if (MaxCount < 1) or (InitialCount > MaxCount) or (InitialCount < 0) or
  1365. (Length(Name) > MAX_METSECT_NAMELEN) then
  1366. raise EJclMeteredSectionError.CreateRes(@RsMetSectInvalidParameter);
  1367. FMetSect := PMeteredSection(AllocMem(SizeOf(TMeteredSection)));
  1368. if FMetSect <> nil then
  1369. begin
  1370. if not InitMeteredSection(InitialCount, MaxCount, Name, False) then
  1371. begin
  1372. CloseMeteredSection;
  1373. FMetSect := nil;
  1374. raise EJclMeteredSectionError.CreateRes(@RsMetSectInitialize);
  1375. end;
  1376. end;
  1377. end;
  1378. constructor TJclMeteredSection.Open(const Name: string);
  1379. begin
  1380. FMetSect := nil;
  1381. if Name = '' then
  1382. raise EJclMeteredSectionError.CreateRes(@RsMetSectNameEmpty);
  1383. FMetSect := PMeteredSection(AllocMem(SizeOf(TMeteredSection)));
  1384. Assert(FMetSect <> nil);
  1385. if not InitMeteredSection(0, 0, Name, True) then
  1386. begin
  1387. CloseMeteredSection;
  1388. FMetSect := nil;
  1389. raise EJclMeteredSectionError.CreateRes(@RsMetSectInitialize);
  1390. end;
  1391. end;
  1392. destructor TJclMeteredSection.Destroy;
  1393. begin
  1394. CloseMeteredSection;
  1395. inherited Destroy;
  1396. end;
  1397. procedure TJclMeteredSection.AcquireLock;
  1398. begin
  1399. while {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedExchange(FMetSect^.SharedInfo^.SpinLock, 1) <> 0 do
  1400. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.Sleep(0);
  1401. end;
  1402. procedure TJclMeteredSection.CloseMeteredSection;
  1403. begin
  1404. if FMetSect <> nil then
  1405. begin
  1406. if FMetSect^.SharedInfo <> nil then
  1407. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.UnmapViewOfFile(FMetSect^.SharedInfo);
  1408. if FMetSect^.FileMap <> 0 then
  1409. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CloseHandle(FMetSect^.FileMap);
  1410. if FMetSect^.Event <> 0 then
  1411. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CloseHandle(FMetSect^.Event);
  1412. FreeMem(FMetSect);
  1413. end;
  1414. end;
  1415. function TJclMeteredSection.CreateMetSectEvent(const Name: string; OpenOnly: Boolean): Boolean;
  1416. var
  1417. FullName: string;
  1418. begin
  1419. if Name = '' then
  1420. FMetSect^.Event := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CreateEvent(nil, False, False, nil)
  1421. else
  1422. begin
  1423. FullName := 'JCL_MSECT_EVT_' + Name;
  1424. if OpenOnly then
  1425. FMetSect^.Event := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.OpenEvent(0, False, PChar(FullName))
  1426. else
  1427. FMetSect^.Event := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CreateEvent(nil, False, False, PChar(FullName));
  1428. end;
  1429. Result := FMetSect^.Event <> 0;
  1430. end;
  1431. function TJclMeteredSection.CreateMetSectFileView(InitialCount, MaxCount: Longint;
  1432. const Name: string; OpenOnly: Boolean): Boolean;
  1433. var
  1434. FullName: string;
  1435. LastError: DWORD;
  1436. begin
  1437. Result := False;
  1438. if Name = '' then
  1439. FMetSect^.FileMap := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TMetSectSharedInfo), nil)
  1440. else
  1441. begin
  1442. FullName := 'JCL_MSECT_MMF_' + Name;
  1443. if OpenOnly then
  1444. FMetSect^.FileMap := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.OpenFileMapping(0, False, PChar(FullName))
  1445. else
  1446. FMetSect^.FileMap := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TMetSectSharedInfo), PChar(FullName));
  1447. end;
  1448. if FMetSect^.FileMap <> 0 then
  1449. begin
  1450. LastError := GetLastError;
  1451. FMetSect^.SharedInfo := {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.MapViewOfFile(FMetSect^.FileMap, FILE_MAP_WRITE, 0, 0, 0);
  1452. if FMetSect^.SharedInfo <> nil then
  1453. begin
  1454. if LastError = ERROR_ALREADY_EXISTS then
  1455. while not FMetSect^.SharedInfo^.Initialized do Sleep(0)
  1456. else
  1457. begin
  1458. FMetSect^.SharedInfo^.SpinLock := 0;
  1459. FMetSect^.SharedInfo^.ThreadsWaiting := 0;
  1460. FMetSect^.SharedInfo^.AvailableCount := InitialCount;
  1461. FMetSect^.SharedInfo^.MaximumCount := MaxCount;
  1462. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedExchange(Integer(FMetSect^.SharedInfo^.Initialized), 1);
  1463. end;
  1464. Result := True;
  1465. end;
  1466. end;
  1467. end;
  1468. function TJclMeteredSection.Enter(TimeOut: Longword): TJclWaitResult;
  1469. begin
  1470. Result := wrSignaled;
  1471. while Result = wrSignaled do
  1472. begin
  1473. AcquireLock;
  1474. try
  1475. if FMetSect^.SharedInfo^.AvailableCount >= 1 then
  1476. begin
  1477. Dec(FMetSect^.SharedInfo^.AvailableCount);
  1478. Result := MapSignalResult(WAIT_OBJECT_0);
  1479. Exit;
  1480. end;
  1481. Inc(FMetSect^.SharedInfo^.ThreadsWaiting);
  1482. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.ResetEvent(FMetSect^.Event);
  1483. finally
  1484. ReleaseLock;
  1485. end;
  1486. Result := MapSignalResult({$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.WaitForSingleObject(FMetSect^.Event, TimeOut));
  1487. end;
  1488. end;
  1489. function TJclMeteredSection.InitMeteredSection(InitialCount, MaxCount: Longint;
  1490. const Name: string; OpenOnly: Boolean): Boolean;
  1491. begin
  1492. Result := False;
  1493. if CreateMetSectEvent(Name, OpenOnly) then
  1494. Result := CreateMetSectFileView(InitialCount, MaxCount, Name, OpenOnly);
  1495. end;
  1496. function TJclMeteredSection.Leave(ReleaseCount: Integer; out PrevCount: Integer): Boolean;
  1497. var
  1498. Count: Integer;
  1499. begin
  1500. Result := False;
  1501. AcquireLock;
  1502. try
  1503. PrevCount := FMetSect^.SharedInfo^.AvailableCount;
  1504. if (ReleaseCount < 0) or
  1505. (FMetSect^.SharedInfo^.AvailableCount + ReleaseCount > FMetSect^.SharedInfo^.MaximumCount) then
  1506. begin
  1507. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.SetLastError(ERROR_INVALID_PARAMETER);
  1508. Exit;
  1509. end;
  1510. Inc(FMetSect^.SharedInfo^.AvailableCount, ReleaseCount);
  1511. ReleaseCount := Min(ReleaseCount, FMetSect^.SharedInfo^.ThreadsWaiting);
  1512. if FMetSect^.SharedInfo^.ThreadsWaiting > 0 then
  1513. begin
  1514. for Count := 0 to ReleaseCount - 1 do
  1515. begin
  1516. Dec(FMetSect^.SharedInfo^.ThreadsWaiting);
  1517. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.SetEvent(FMetSect^.Event);
  1518. end;
  1519. end;
  1520. finally
  1521. ReleaseLock;
  1522. end;
  1523. Result := True;
  1524. end;
  1525. function TJclMeteredSection.Leave(ReleaseCount: Integer): Boolean;
  1526. var
  1527. Previous: Longint;
  1528. begin
  1529. Result := Leave(ReleaseCount, Previous);
  1530. end;
  1531. procedure TJclMeteredSection.ReleaseLock;
  1532. begin
  1533. {$IFDEF HAS_UNITSCOPE}Winapi.{$ENDIF}Windows.InterlockedExchange(FMetSect^.SharedInfo^.SpinLock, 0);
  1534. end;
  1535. //=== Debugging ==============================================================
  1536. function QueryCriticalSection(CS: TJclCriticalSection; var Info: TRTLCriticalSection): Boolean;
  1537. begin
  1538. Result := CS <> nil;
  1539. if Result then
  1540. Info := CS.FCriticalSection;
  1541. end;
  1542. // Native API functions
  1543. // http://undocumented.ntinternals.net/
  1544. { TODO: RTLD version }
  1545. type
  1546. TNtQueryProc = function (Handle: THandle; InfoClass: Byte; Info: Pointer;
  1547. Len: Longint; ResLen: PLongint): Longint; stdcall;
  1548. var
  1549. _QueryEvent: TNtQueryProc = nil;
  1550. _QueryMutex: TNtQueryProc = nil;
  1551. _QuerySemaphore: TNtQueryProc = nil;
  1552. _QueryTimer: TNtQueryProc = nil;
  1553. function CallQueryProc(var P: TNtQueryProc; const Name: string; Handle: THandle;
  1554. Info: Pointer; InfoSize: Longint): Boolean;
  1555. var
  1556. NtDll: THandle;
  1557. Status: Longint;
  1558. begin
  1559. Result := False;
  1560. if @P = nil then
  1561. begin
  1562. NtDll := GetModuleHandle(PChar('ntdll.dll'));
  1563. if NtDll <> 0 then
  1564. @P := GetProcAddress(NtDll, PChar(Name));
  1565. end;
  1566. if @P <> nil then
  1567. begin
  1568. Status := P(Handle, 0, Info, InfoSize, nil);
  1569. Result := (Status and $80000000) = 0;
  1570. end;
  1571. end;
  1572. function QueryEvent(Handle: THandle; var Info: TEventInfo): Boolean;
  1573. begin
  1574. Result := CallQueryProc(_QueryEvent, 'NtQueryEvent', Handle, @Info, SizeOf(Info));
  1575. end;
  1576. function QueryMutex(Handle: THandle; var Info: TMutexInfo): Boolean;
  1577. begin
  1578. Result := CallQueryProc(_QueryMutex, 'NtQueryMutex', Handle, @Info, SizeOf(Info));
  1579. end;
  1580. function QuerySemaphore(Handle: THandle; var Info: TSemaphoreCounts): Boolean;
  1581. begin
  1582. Result := CallQueryProc(_QuerySemaphore, 'NtQuerySemaphore', Handle, @Info, SizeOf(Info));
  1583. end;
  1584. function QueryTimer(Handle: THandle; var Info: TTimerInfo): Boolean;
  1585. begin
  1586. Result := CallQueryProc(_QueryTimer, 'NtQueryTimer', Handle, @Info, SizeOf(Info));
  1587. end;
  1588. function ValidateMutexName(const aName: string): string;
  1589. const cMutexMaxName = 200;
  1590. begin
  1591. if Length(aName) > cMutexMaxName then
  1592. Result := Copy (aName, Length(aName)-cMutexMaxName, cMutexMaxName)
  1593. else
  1594. Result := aName;
  1595. Result := StrReplaceChar(Result, '\', '_');
  1596. end;
  1597. {$IFDEF UNITVERSIONING}
  1598. initialization
  1599. RegisterUnitVersion(HInstance, UnitVersioning);
  1600. finalization
  1601. UnregisterUnitVersion(HInstance);
  1602. {$ENDIF UNITVERSIONING}
  1603. end.