libasync.pp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. {
  2. $Id$
  3. libasync: Asynchronous event management
  4. Copyright (C) 2001-2002 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. Unix implementation
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. }
  13. unit libasync;
  14. {$MODE objfpc}
  15. interface
  16. type
  17. TAsyncData = record
  18. IsRunning, DoBreak: Boolean;
  19. HasCallbacks: Boolean; // True as long as callbacks are set
  20. FirstTimer: Pointer;
  21. FirstIOCallback: Pointer;
  22. CurIOCallback: Pointer; // current callback being processed within 'run'
  23. NextIOCallback: Pointer; // next callback to get processed within 'run'
  24. FDData: Pointer;
  25. HighestHandle: LongInt;
  26. end;
  27. {$INCLUDE libasynch.inc}
  28. implementation
  29. {$ifdef VER1_0}
  30. uses Linux;
  31. {$else}
  32. uses Unix;
  33. {$endif}
  34. const
  35. MaxHandle = SizeOf(TFDSet) * 8 - 1;
  36. type
  37. PIOCallbackData = ^TIOCallbackData;
  38. TIOCallbackData = record
  39. Next: PIOCallbackData;
  40. IOHandle: LongInt;
  41. ReadCallback, WriteCallback: TAsyncCallback;
  42. ReadUserData, WriteUserData: Pointer;
  43. SavedHandleFlags: LongInt;
  44. end;
  45. {$INCLUDE libasync.inc}
  46. procedure InternalInit(Handle: TAsyncHandle);
  47. begin
  48. Handle^.Data.HighestHandle := -1;
  49. end;
  50. procedure InternalFree(Handle: TAsyncHandle);
  51. var
  52. IOCallback: PIOCallbackData;
  53. begin
  54. IOCallback := PIOCallbackData(Handle^.Data.FirstIOCallback);
  55. while Assigned(IOCallback) do
  56. begin
  57. if (IOCallback^.SavedHandleFlags and Open_NonBlock) = 0 then
  58. fcntl(IOCallback^.IOHandle, F_SetFl, IOCallback^.SavedHandleFlags);
  59. IOCallback := IOCallback^.Next;
  60. end;
  61. if Assigned(Handle^.Data.FDData) then
  62. FreeMem(Handle^.Data.FDData);
  63. end;
  64. procedure InternalRun(Handle: TAsyncHandle; TimeOut: Int64);
  65. var
  66. AsyncResult: Integer;
  67. CurReadFDSet, CurWriteFDSet: TFDSet;
  68. CurIOCallback: PIOCallbackData;
  69. begin
  70. if Handle^.Data.HighestHandle < 0 then
  71. // No I/O checks to do, so just wait...
  72. AsyncResult := Select(0, nil, nil, nil, TimeOut)
  73. else
  74. begin
  75. CurReadFDSet := PFDSet(Handle^.Data.FDData)[0];
  76. CurWriteFDSet := PFDSet(Handle^.Data.FDData)[1];
  77. AsyncResult := Select(Handle^.Data.HighestHandle + 1,
  78. @CurReadFDSet, @CurWriteFDSet, nil, TimeOut);
  79. if AsyncResult > 0 then
  80. begin
  81. // Check for I/O events
  82. Handle^.Data.CurIOCallback := Handle^.Data.FirstIOCallback;
  83. while Assigned(Handle^.Data.CurIOCallback) do
  84. begin
  85. CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
  86. Handle^.Data.NextIOCallback := CurIOCallback^.Next;
  87. if FD_IsSet(CurIOCallback^.IOHandle, CurReadFDSet) and
  88. FD_IsSet(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[0]) and
  89. Assigned(CurIOCallback^.ReadCallback) then
  90. begin
  91. CurIOCallback^.ReadCallback(CurIOCallback^.ReadUserData);
  92. if Handle^.Data.DoBreak then
  93. break;
  94. end;
  95. CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
  96. if Assigned(CurIOCallback) and
  97. FD_IsSet(CurIOCallback^.IOHandle, CurWriteFDSet) and
  98. FD_IsSet(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[1]) and
  99. Assigned(CurIOCallback^.WriteCallback) then
  100. begin
  101. CurIOCallback^.WriteCallback(CurIOCallback^.WriteUserData);
  102. if Handle^.Data.DoBreak then
  103. break;
  104. end;
  105. Handle^.Data.CurIOCallback := Handle^.Data.NextIOCallback;
  106. end;
  107. end;
  108. end;
  109. end;
  110. procedure InternalInitIOCallback(Handle: TAsyncHandle; Data: PIOCallbackData;
  111. InitData: Boolean; CallbackTypes: TCallbackTypes);
  112. var
  113. i: LongInt;
  114. begin
  115. if InitData then
  116. begin
  117. if not Assigned(Handle^.Data.FDData) then
  118. begin
  119. GetMem(Handle^.Data.FDData, SizeOf(TFDSet) * 2);
  120. FD_Zero(PFDSet(Handle^.Data.FDData)[0]);
  121. FD_Zero(PFDSet(Handle^.Data.FDData)[1]);
  122. end;
  123. if Data^.IOHandle > Handle^.Data.HighestHandle then
  124. Handle^.Data.HighestHandle := Data^.IOHandle;
  125. end;
  126. Data^.SavedHandleFlags := fcntl(Data^.IOHandle, F_GetFl);
  127. fcntl(Data^.IOHandle, F_SetFl, Data^.SavedHandleFlags or Open_NonBlock);
  128. case Data^.IOHandle of
  129. StdInputHandle:
  130. i := Open_RdOnly;
  131. StdOutputHandle, StdErrorHandle:
  132. i := Open_WrOnly;
  133. else
  134. i := Data^.SavedHandleFlags and Open_Accmode;
  135. end;
  136. case i of
  137. Open_RdOnly:
  138. if cbRead in CallbackTypes then
  139. FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[0]);
  140. Open_WrOnly:
  141. if cbWrite in CallbackTypes then
  142. FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[1]);
  143. Open_RdWr:
  144. begin
  145. if cbRead in CallbackTypes then
  146. FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[0]);
  147. if cbWrite in CallbackTypes then
  148. FD_Set(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[1]);
  149. end;
  150. end;
  151. end;
  152. procedure InternalClearIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
  153. CallbackTypes: TCallbackTypes);
  154. begin
  155. if cbRead in CallbackTypes then
  156. FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
  157. if cbWrite in CallbackTypes then
  158. FD_Clr(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
  159. end;
  160. function asyncGetTicks: Int64; cdecl;
  161. var
  162. Time: TimeVal;
  163. begin
  164. GetTimeOfDay(Time);
  165. Result := Int64(Time.Sec) * 1000 + Int64(Time.USec div 1000);
  166. end;
  167. end.
  168. {
  169. $Log$
  170. Revision 1.5 2002-09-25 21:53:39 sg
  171. * Split in common implementation an platform dependent implementation
  172. Revision 1.4 2002/09/15 15:51:09 sg
  173. * Removed debugging output code
  174. }