levents.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. { lNet Events abstration
  2. CopyRight (C) 2006 Ales Katona
  3. This library is Free software; you can rediStribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at your
  6. option) any later version.
  7. This program is diStributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
  9. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  10. for more details.
  11. You should have received a Copy of the GNU Library General Public License
  12. along with This library; if not, Write to the Free Software Foundation,
  13. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. This license has been modified. See File LICENSE.ADDON for more inFormation.
  15. Should you find these sources without a LICENSE File, please contact
  16. me at [email protected]
  17. }
  18. unit lEvents;
  19. {$mode objfpc}{$H+}
  20. {$inline on}
  21. {$define nochoice} // let's presume we don't have "optimized" eventer
  22. interface
  23. uses
  24. {$ifdef Linux}
  25. {$undef nochoice} // undefine for all "Optimized" targets
  26. Linux, Contnrs,
  27. {$endif}
  28. {$ifdef BSD}
  29. {$undef nochoice}
  30. BSD,
  31. {$endif}
  32. {$i sys/osunits.inc}
  33. type
  34. TLHandle = class;
  35. TLEventer = class;
  36. TLHandleEvent = procedure (aHandle: TLHandle) of object;
  37. TLHandleErrorEvent = procedure (aHandle: TLHandle; const msg: string) of object;
  38. TLEventerErrorCallback = procedure (const msg: string; Sender: TLEventer) of object;
  39. TArrayP = array of Pointer;
  40. { TLHandle }
  41. TLHandle = class(TObject)
  42. protected
  43. FHandle: THandle;
  44. FEventer: TLEventer; // "queue holder"
  45. FOnRead: TLHandleEvent;
  46. FOnWrite: TLHandleEvent;
  47. FOnError: TLHandleErrorEvent;
  48. FIgnoreWrite: Boolean; // so we can do edge-triggered
  49. FIgnoreRead: Boolean; // so we can do edge-triggered
  50. FIgnoreError: Boolean; // so we can do edge-triggered
  51. FDispose: Boolean; // will free in the after-cycle
  52. FFreeing: Boolean; // used to see if it's in the "to be freed" list
  53. FPrev: TLHandle;
  54. FNext: TLHandle;
  55. FFreeNext: TLHandle;
  56. FUserData: Pointer;
  57. FInternalData: Pointer;
  58. procedure SetIgnoreError(const aValue: Boolean);
  59. procedure SetIgnoreWrite(const aValue: Boolean);
  60. procedure SetIgnoreRead(const aValue: Boolean);
  61. public
  62. constructor Create; virtual;
  63. destructor Destroy; override;
  64. procedure Free; virtual; // this is a trick
  65. property Prev: TLHandle read FPrev write FPrev;
  66. property Next: TLHandle read FNext write FNext;
  67. property FreeNext: TLHandle read FFreeNext write FFreeNext;
  68. property IgnoreWrite: Boolean read FIgnoreWrite write SetIgnoreWrite;
  69. property IgnoreRead: Boolean read FIgnoreRead write SetIgnoreRead;
  70. property IgnoreError: Boolean read FIgnoreError write SetIgnoreError;
  71. property OnRead: TLHandleEvent read FOnRead write FOnRead;
  72. property OnWrite: TLHandleEvent read FOnWrite write FOnWrite;
  73. property OnError: TLHandleErrorEvent read FOnError write FOnError;
  74. property UserData: Pointer read FUserData write FUserData;
  75. property Dispose: Boolean read FDispose write FDispose;
  76. property Handle: THandle read FHandle write FHandle;
  77. property Eventer: TLEventer read FEventer;
  78. end;
  79. { TLTimer }
  80. {
  81. TLTimer = class(TObject)
  82. protected
  83. FOnTimer: TNotifyEvent;
  84. FInterval: TDateTime;
  85. FTimeout: TDateTime;
  86. FPeriodic: Boolean;
  87. FEnabled: Boolean;
  88. FNext: TLTimer;
  89. function GetInterval: Integer;
  90. procedure SetEnabled(NewEnabled: Boolean);
  91. procedure SetInterval(NewInterval: Integer);
  92. public
  93. procedure CallAction;
  94. property Enabled: Boolean read FEnabled write SetEnabled;
  95. property Interval: Integer read GetInterval write SetInterval;
  96. property Periodic: Boolean read FPeriodic write FPeriodic;
  97. property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  98. end;
  99. }
  100. { TLTimeoutManager }
  101. {
  102. TLSetTimeout = procedure(NewTimeout: DWord) of object;
  103. TLTimeoutManager = class
  104. protected
  105. FFirst: TLTimer;
  106. FLast: TLTimer;
  107. FTimeout: DWord;
  108. FSetTimeout: TLSetTimeout;
  109. public
  110. destructor Destroy; override;
  111. procedure AddTimer(ATimer: TLTimer);
  112. procedure RemoveTimer(ATimer: TLTimer);
  113. procedure CallAction;
  114. end;
  115. }
  116. { TLEventer }
  117. TLEventer = class
  118. protected
  119. FRoot: TLHandle;
  120. FCount: Integer;
  121. FOnError: TLEventerErrorCallback;
  122. FReferences: Integer;
  123. FFreeRoot: TLHandle; // the root of "free" list if any
  124. FFreeIter: TLHandle; // the last of "free" list if any
  125. FInLoop: Boolean;
  126. function GetTimeout: DWord; virtual;
  127. procedure SetTimeout(const Value: DWord); virtual;
  128. function Bail(const msg: string; const Ernum: Integer): Boolean;
  129. procedure AddForFree(aHandle: TLHandle);
  130. procedure FreeHandles;
  131. procedure HandleIgnoreError(aHandle: TLHandle); virtual;
  132. procedure HandleIgnoreWrite(aHandle: TLHandle); virtual;
  133. procedure HandleIgnoreRead(aHandle: TLHandle); virtual;
  134. function GetInternalData(aHandle: TLHandle): Pointer;
  135. procedure SetInternalData(aHandle: TLHandle; const aData: Pointer);
  136. procedure SetHandleEventer(aHandle: TLHandle);
  137. public
  138. constructor Create; virtual;
  139. destructor Destroy; override;
  140. function AddHandle(aHandle: TLHandle): Boolean; virtual;
  141. function CallAction: Boolean; virtual;
  142. procedure RemoveHandle(aHandle: TLHandle); virtual;
  143. procedure UnplugHandle(aHandle: TLHandle); virtual;
  144. procedure LoadFromEventer(aEventer: TLEventer); virtual;
  145. procedure Clear;
  146. procedure AddRef;
  147. procedure DeleteRef;
  148. property Timeout: DWord read GetTimeout write SetTimeout;
  149. property OnError: TLEventerErrorCallback read FOnError write FOnError;
  150. property Count: Integer read FCount;
  151. end;
  152. TLEventerClass = class of TLEventer;
  153. { TLSelectEventer }
  154. TLSelectEventer = class(TLEventer)
  155. protected
  156. FTimeout: TTimeVal;
  157. FReadFDSet: TFDSet;
  158. FWriteFDSet: TFDSet;
  159. FErrorFDSet: TFDSet;
  160. function GetTimeout: DWord; override;
  161. procedure SetTimeout(const Value: DWord); override;
  162. procedure ClearSets;
  163. public
  164. constructor Create; override;
  165. function CallAction: Boolean; override;
  166. end;
  167. {$i sys/lkqueueeventerh.inc}
  168. {$i sys/lepolleventerh.inc}
  169. function BestEventerClass: TLEventerClass;
  170. implementation
  171. uses
  172. lCommon;
  173. { TLHandle }
  174. procedure TLHandle.SetIgnoreError(const aValue: Boolean);
  175. begin
  176. if FIgnoreError <> aValue then begin
  177. FIgnoreError := aValue;
  178. if Assigned(FEventer) then
  179. FEventer.HandleIgnoreError(Self);
  180. end;
  181. end;
  182. procedure TLHandle.SetIgnoreWrite(const aValue: Boolean);
  183. begin
  184. if FIgnoreWrite <> aValue then begin
  185. FIgnoreWrite := aValue;
  186. if Assigned(FEventer) then
  187. FEventer.HandleIgnoreWrite(Self);
  188. end;
  189. end;
  190. procedure TLHandle.SetIgnoreRead(const aValue: Boolean);
  191. begin
  192. if FIgnoreRead <> aValue then begin
  193. FIgnoreRead := aValue;
  194. if Assigned(FEventer) then
  195. FEventer.HandleIgnoreRead(Self);
  196. end;
  197. end;
  198. constructor TLHandle.Create;
  199. begin
  200. FOnRead := nil;
  201. FOnWrite := nil;
  202. FOnError := nil;
  203. FUserData := nil;
  204. FEventer := nil;
  205. FPrev := nil;
  206. FNext := nil;
  207. FFreeNext := nil;
  208. FFreeing := False;
  209. FDispose := False;
  210. FIgnoreWrite := False;
  211. FIgnoreRead := False;
  212. FIgnoreError := False;
  213. end;
  214. destructor TLHandle.Destroy;
  215. begin
  216. if Assigned(FEventer) then
  217. FEventer.UnplugHandle(Self);
  218. end;
  219. procedure TLHandle.Free;
  220. begin
  221. if Assigned(FEventer) and FEventer.FInLoop then
  222. FEventer.AddForFree(Self)
  223. else
  224. inherited Free;
  225. end;
  226. { TLTimer }
  227. {
  228. function TLTimer.GetInterval: Integer;
  229. begin
  230. Result := Round(FInterval * MSecsPerDay);
  231. end;
  232. procedure TLTimer.SetEnabled(NewEnabled: integer);
  233. begin
  234. FTimeout := Now + Interval;
  235. FEnabled := true;
  236. end;
  237. procedure TLTimer.SetInterval(const aValue: Integer);
  238. begin
  239. FInterval := AValue / MSecsPerDay;
  240. end;
  241. procedure TLTimer.CallAction;
  242. begin
  243. if FEnabled and Assigned(FOnTimer) and (Now - FStarted >= FInterval) then
  244. begin
  245. FOnTimer(Self);
  246. if not FOneShot then
  247. FStarted := Now
  248. else
  249. FEnabled := false;
  250. end;
  251. end;
  252. }
  253. { TLEventer }
  254. constructor TLEventer.Create;
  255. begin
  256. FRoot := nil;
  257. FFreeRoot := nil;
  258. FFreeIter := nil;
  259. FInLoop := False;
  260. FCount := 0;
  261. FReferences := 1;
  262. end;
  263. destructor TLEventer.Destroy;
  264. begin
  265. Clear;
  266. end;
  267. function TLEventer.GetTimeout: DWord;
  268. begin
  269. Result := 0;
  270. end;
  271. procedure TLEventer.SetTimeout(const Value: DWord);
  272. begin
  273. end;
  274. function TLEventer.Bail(const msg: string; const Ernum: Integer): Boolean;
  275. begin
  276. Result := False; // always false, substitute for caller's result
  277. if Assigned(FOnError) then
  278. FOnError(msg + '[' + IntToStr(Ernum) + ']: ' + LStrError(Ernum), Self);
  279. end;
  280. procedure TLEventer.AddForFree(aHandle: TLHandle);
  281. begin
  282. if not aHandle.FFreeing then begin
  283. aHandle.FFreeing := True;
  284. if not Assigned(FFreeIter) then begin
  285. FFreeIter := aHandle;
  286. FFreeRoot := aHandle;
  287. end else begin
  288. FFreeIter.FreeNext := aHandle;
  289. FFreeIter := aHandle;
  290. end;
  291. end;
  292. end;
  293. procedure TLEventer.FreeHandles;
  294. var
  295. Temp, Temp2: TLHandle;
  296. begin
  297. Temp := FFreeRoot;
  298. while Assigned(Temp) do begin
  299. Temp2 := Temp.FreeNext;
  300. Temp.Free;
  301. Temp := Temp2;
  302. end;
  303. FFreeRoot := nil;
  304. FFreeIter := nil;
  305. end;
  306. procedure TLEventer.HandleIgnoreError(aHandle: TLHandle);
  307. begin
  308. end;
  309. procedure TLEventer.HandleIgnoreWrite(aHandle: TLHandle);
  310. begin
  311. end;
  312. procedure TLEventer.HandleIgnoreRead(aHandle: TLHandle);
  313. begin
  314. end;
  315. function TLEventer.GetInternalData(aHandle: TLHandle): Pointer;
  316. begin
  317. Result := aHandle.FInternalData;
  318. end;
  319. procedure TLEventer.SetInternalData(aHandle: TLHandle; const aData: Pointer);
  320. begin
  321. aHandle.FInternalData := aData;
  322. end;
  323. procedure TLEventer.SetHandleEventer(aHandle: TLHandle);
  324. begin
  325. aHandle.FEventer := Self;
  326. end;
  327. function TLEventer.AddHandle(aHandle: TLHandle): Boolean;
  328. begin
  329. Result := False;
  330. if not Assigned(aHandle.FEventer) then begin
  331. if not Assigned(FRoot) then begin
  332. FRoot := aHandle;
  333. end else begin
  334. if Assigned(FRoot.FNext) then begin
  335. FRoot.FNext.FPrev := aHandle;
  336. aHandle.FNext := FRoot.FNext;
  337. end;
  338. FRoot.FNext := aHandle;
  339. aHandle.FPrev := FRoot;
  340. end;
  341. aHandle.FEventer := Self;
  342. Inc(FCount);
  343. Result := True;
  344. end;
  345. end;
  346. function TLEventer.CallAction: Boolean;
  347. begin
  348. Result := True;
  349. // override in ancestor
  350. end;
  351. procedure TLEventer.RemoveHandle(aHandle: TLHandle);
  352. begin
  353. aHandle.Free;
  354. end;
  355. procedure TLEventer.UnplugHandle(aHandle: TLHandle);
  356. begin
  357. if aHandle.FEventer = Self then begin
  358. aHandle.FEventer := nil; // avoid recursive AV
  359. if Assigned(aHandle.FPrev) then begin
  360. aHandle.FPrev.FNext := aHandle.FNext;
  361. if Assigned(aHandle.FNext) then
  362. aHandle.FNext.FPrev := aHandle.FPrev;
  363. end else if Assigned(aHandle.FNext) then begin
  364. aHandle.FNext.FPrev := aHandle.FPrev;
  365. if aHandle = FRoot then
  366. FRoot := aHandle.FNext;
  367. end else FRoot := nil;
  368. if FCount > 0 then
  369. Dec(FCount);
  370. end;
  371. end;
  372. procedure TLEventer.LoadFromEventer(aEventer: TLEventer);
  373. begin
  374. Clear;
  375. FRoot := aEventer.FRoot;
  376. FOnError := aEventer.FOnError;
  377. end;
  378. procedure TLEventer.Clear;
  379. var
  380. Temp1, Temp2: TLHandle;
  381. begin
  382. Temp1 := FRoot;
  383. Temp2 := FRoot;
  384. while Assigned(Temp2) do begin
  385. Temp1 := Temp2;
  386. Temp2 := Temp1.FNext;
  387. Temp1.Free;
  388. end;
  389. FRoot := nil;
  390. end;
  391. procedure TLEventer.AddRef;
  392. begin
  393. Inc(FReferences);
  394. end;
  395. procedure TLEventer.DeleteRef;
  396. begin
  397. if FReferences > 0 then
  398. Dec(FReferences);
  399. if FReferences = 0 then
  400. Free;
  401. end;
  402. { TLSelectEventer }
  403. constructor TLSelectEventer.Create;
  404. begin
  405. inherited Create;
  406. FTimeout.tv_sec := 0;
  407. FTimeout.tv_usec := 0;
  408. end;
  409. function TLSelectEventer.GetTimeout: DWord;
  410. begin
  411. Result := (FTimeout.tv_sec * 1000) + FTimeout.tv_usec;
  412. end;
  413. procedure TLSelectEventer.SetTimeout(const Value: DWord);
  414. begin
  415. FTimeout.tv_sec := Value div 1000;
  416. FTimeout.tv_usec := Value mod 1000;
  417. end;
  418. procedure TLSelectEventer.ClearSets;
  419. begin
  420. fpFD_ZERO(FReadFDSet);
  421. fpFD_ZERO(FWriteFDSet);
  422. fpFD_ZERO(FErrorFDSet);
  423. end;
  424. function TLSelectEventer.CallAction: Boolean;
  425. var
  426. Temp, Temp2: TLHandle;
  427. MaxHandle, n: Integer;
  428. TempTime: TTimeVal;
  429. begin
  430. if not Assigned(FRoot) then begin
  431. Sleep(FTimeout.tv_sec * 1000 + FTimeout.tv_usec div 1000);
  432. Exit;
  433. end;
  434. FInLoop := True;
  435. Temp := FRoot;
  436. MaxHandle := 0;
  437. ClearSets;
  438. while Assigned(Temp) do begin
  439. if (not Temp.FDispose ) // handle still valid
  440. and ( (not Temp.IgnoreWrite) // check write or
  441. or (not Temp.IgnoreRead ) // check read or
  442. or (not Temp.IgnoreError)) // check for errors
  443. then begin
  444. if not Temp.IgnoreWrite then
  445. fpFD_SET(Temp.FHandle, FWriteFDSet);
  446. if not Temp.IgnoreRead then
  447. fpFD_SET(Temp.FHandle, FReadFDSet);
  448. if not Temp.IgnoreError then
  449. fpFD_SET(Temp.FHandle, FErrorFDSet);
  450. if Temp.FHandle > MaxHandle then
  451. MaxHandle := Temp.FHandle;
  452. end;
  453. Temp2 := Temp;
  454. Temp := Temp.FNext;
  455. if Temp2.FDispose then
  456. Temp2.Free;
  457. end;
  458. TempTime := FTimeout;
  459. n := fpSelect(MaxHandle + 1, @FReadFDSet, @FWriteFDSet, @FErrorFDSet, @TempTime);
  460. if n < 0 then
  461. Bail('Error on select', LSocketError);
  462. Result := n > 0;
  463. if Result then begin
  464. Temp := FRoot;
  465. while Assigned(Temp) do begin
  466. if not Temp.FDispose and (fpFD_ISSET(Temp.FHandle, FWriteFDSet) <> 0) then
  467. if Assigned(Temp.FOnWrite) and not Temp.IgnoreWrite then
  468. Temp.FOnWrite(Temp);
  469. if not Temp.FDispose and (fpFD_ISSET(Temp.FHandle, FReadFDSet) <> 0) then
  470. if Assigned(Temp.FOnRead) and not Temp.IgnoreRead then
  471. Temp.FOnRead(Temp);
  472. if not Temp.FDispose and (fpFD_ISSET(Temp.FHandle, FErrorFDSet) <> 0) then
  473. if Assigned(Temp.FOnError) and not Temp.IgnoreError then
  474. Temp.FOnError(Temp, 'Handle error' + LStrError(LSocketError));
  475. Temp2 := Temp;
  476. Temp := Temp.FNext;
  477. if Temp2.FDispose then
  478. AddForFree(Temp2);
  479. end;
  480. end;
  481. FInLoop := False;
  482. if Assigned(FFreeRoot) then
  483. FreeHandles;
  484. end;
  485. {$i sys/lkqueueeventer.inc}
  486. {$i sys/lepolleventer.inc}
  487. {$ifdef nochoice}
  488. function BestEventerClass: TLEventerClass;
  489. begin
  490. Result := TLSelectEventer;
  491. end;
  492. {$endif}
  493. end.