libasync.pp 5.4 KB

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