libasync.pp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. {
  2. $Id: libasync.pp,v 1.10 2005/02/14 17:13:19 peter Exp $
  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. uses baseunix, Unix;
  30. const
  31. MaxHandle = SizeOf(TFDSet) * 8 - 1;
  32. type
  33. PIOCallbackData = ^TIOCallbackData;
  34. TIOCallbackData = record
  35. Next: PIOCallbackData;
  36. IOHandle: LongInt;
  37. ReadCallback, WriteCallback: TAsyncCallback;
  38. ReadUserData, WriteUserData: Pointer;
  39. SavedHandleFlags: LongInt;
  40. end;
  41. {$INCLUDE libasync.inc}
  42. procedure InternalInit(Handle: TAsyncHandle);
  43. begin
  44. Handle^.Data.HighestHandle := -1;
  45. end;
  46. procedure InternalFree(Handle: TAsyncHandle);
  47. var
  48. IOCallback: PIOCallbackData;
  49. begin
  50. IOCallback := PIOCallbackData(Handle^.Data.FirstIOCallback);
  51. while Assigned(IOCallback) do
  52. begin
  53. if (IOCallback^.SavedHandleFlags and Open_NonBlock) = 0 then
  54. fpfcntl(IOCallback^.IOHandle, F_SetFl, IOCallback^.SavedHandleFlags);
  55. IOCallback := IOCallback^.Next;
  56. end;
  57. if Assigned(Handle^.Data.FDData) then
  58. FreeMem(Handle^.Data.FDData);
  59. end;
  60. procedure InternalRun(Handle: TAsyncHandle; TimeOut: Int64);
  61. var
  62. AsyncResult: Integer;
  63. CurReadFDSet, CurWriteFDSet: TFDSet;
  64. CurIOCallback: PIOCallbackData;
  65. begin
  66. if Handle^.Data.HighestHandle < 0 then
  67. // No I/O checks to do, so just wait...
  68. AsyncResult := fpselect(0, nil, nil, nil, TimeOut)
  69. else
  70. begin
  71. CurReadFDSet := PFDSet(Handle^.Data.FDData)[0];
  72. CurWriteFDSet := PFDSet(Handle^.Data.FDData)[1];
  73. AsyncResult := fpselect(Handle^.Data.HighestHandle + 1,
  74. @CurReadFDSet, @CurWriteFDSet, nil, TimeOut);
  75. if AsyncResult > 0 then
  76. begin
  77. // Check for I/O events
  78. Handle^.Data.CurIOCallback := Handle^.Data.FirstIOCallback;
  79. while Assigned(Handle^.Data.CurIOCallback) do
  80. begin
  81. CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
  82. Handle^.Data.NextIOCallback := CurIOCallback^.Next;
  83. if (fpFD_ISSET(CurIOCallback^.IOHandle,CurReadFDSet) > 0) and
  84. (fpFD_ISSET(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[0]) > 0) and
  85. Assigned(CurIOCallback^.ReadCallback) then
  86. begin
  87. CurIOCallback^.ReadCallback(CurIOCallback^.ReadUserData);
  88. if Handle^.Data.DoBreak then
  89. break;
  90. end;
  91. CurIOCallback := PIOCallbackData(Handle^.Data.CurIOCallback);
  92. if Assigned(CurIOCallback) and
  93. (fpFD_ISSET(CurIOCallback^.IOHandle, CurWriteFDSet) > 0) and
  94. (fpFD_ISSET(CurIOCallback^.IOHandle, PFDSet(Handle^.Data.FDData)[1]) > 0) and
  95. Assigned(CurIOCallback^.WriteCallback) then
  96. begin
  97. CurIOCallback^.WriteCallback(CurIOCallback^.WriteUserData);
  98. if Handle^.Data.DoBreak then
  99. break;
  100. end;
  101. Handle^.Data.CurIOCallback := Handle^.Data.NextIOCallback;
  102. end;
  103. end;
  104. end;
  105. end;
  106. procedure InternalInitIOCallback(Handle: TAsyncHandle; Data: PIOCallbackData;
  107. InitData: Boolean; CallbackTypes: TCallbackTypes);
  108. var
  109. i: LongInt;
  110. begin
  111. if InitData then
  112. begin
  113. if not Assigned(Handle^.Data.FDData) then
  114. begin
  115. GetMem(Handle^.Data.FDData, SizeOf(TFDSet) * 2);
  116. fpFD_ZERO(PFDSet(Handle^.Data.FDData)[0]);
  117. fpFD_ZERO(PFDSet(Handle^.Data.FDData)[1]);
  118. end;
  119. if Data^.IOHandle > Handle^.Data.HighestHandle then
  120. Handle^.Data.HighestHandle := Data^.IOHandle;
  121. end;
  122. Data^.SavedHandleFlags := fpfcntl(Data^.IOHandle, F_GetFl);
  123. fpfcntl(Data^.IOHandle, F_SetFl, Data^.SavedHandleFlags or Open_NonBlock);
  124. case Data^.IOHandle of
  125. StdInputHandle:
  126. i := Open_RdOnly;
  127. StdOutputHandle, StdErrorHandle:
  128. i := Open_WrOnly;
  129. else
  130. i := Data^.SavedHandleFlags and Open_Accmode;
  131. end;
  132. case i of
  133. Open_RdOnly:
  134. if cbRead in CallbackTypes then
  135. fpFD_SET(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[0]);
  136. Open_WrOnly:
  137. if cbWrite in CallbackTypes then
  138. fpFD_SET(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[1]);
  139. Open_RdWr:
  140. begin
  141. if cbRead in CallbackTypes then
  142. fpFD_SET(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[0]);
  143. if cbWrite in CallbackTypes then
  144. fpFD_SET(Data^.IOHandle, PFDSet(Handle^.Data.FDData)[1]);
  145. end;
  146. end;
  147. end;
  148. procedure InternalClearIOCallback(Handle: TAsyncHandle; IOHandle: LongInt;
  149. CallbackTypes: TCallbackTypes);
  150. begin
  151. if not Assigned(Handle) then
  152. exit;
  153. if cbRead in CallbackTypes then
  154. fpFD_CLR(IOHandle, PFDSet(Handle^.Data.FDData)[0]);
  155. if cbWrite in CallbackTypes then
  156. fpFD_CLR(IOHandle, PFDSet(Handle^.Data.FDData)[1]);
  157. end;
  158. function asyncGetTicks: Int64; cdecl;
  159. var
  160. Time: TimeVal;
  161. begin
  162. fpGetTimeOfDay(@time,nil);
  163. Result := Int64(Time.tv_Sec) * 1000 + Int64(Time.tv_USec div 1000);
  164. end;
  165. end.
  166. {
  167. $Log: libasync.pp,v $
  168. Revision 1.10 2005/02/14 17:13:19 peter
  169. * truncate log
  170. }