JclSynch.pas 55 KB

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