ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/3.0/FB30Events.pas
Revision: 217
Committed: Fri Mar 16 10:27:26 2018 UTC (6 years, 1 month ago) by tony
Content type: text/x-pascal
Original Path: ibx/trunk/fbintf/client/3.0/FB30Events.pas
File size: 8980 byte(s)
Log Message:
Fixes Merged

File Contents

# Content
1 (*
2 * Firebird Interface (fbintf). The fbintf components provide a set of
3 * Pascal language bindings for the Firebird API.
4 *
5 * The contents of this file are subject to the Initial Developer's
6 * Public License Version 1.0 (the "License"); you may not use this
7 * file except in compliance with the License. You may obtain a copy
8 * of the License here:
9 *
10 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11 *
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing rights
15 * and limitations under the License.
16 *
17 * The Initial Developer of the Original Code is Tony Whyman.
18 *
19 * The Original Code is (C) 2016 Tony Whyman, MWA Software
20 * (http://www.mwasoftware.co.uk).
21 *
22 * All Rights Reserved.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 *)
27 unit FB30Events;
28 {$IFDEF MSWINDOWS}
29 {$DEFINE WINDOWS}
30 {$ENDIF}
31
32 {$IFDEF FPC}
33 {$mode delphi}
34 {$interfaces COM}
35 {$ENDIF}
36
37 { $DEFINE EVENTDEBUG}
38
39 interface
40
41 uses
42 {$IFDEF WINDOWS}Windows, {$ENDIF} Classes, SysUtils, Firebird, IB, FB30ClientAPI, FB30Attachment,
43 syncobjs, FBEvents;
44
45 type
46 TFB30Events = class;
47
48 { TEventhandlerInterface }
49
50 TEventhandlerInterface = class(Firebird.IEventCallbackImpl)
51 private
52 FOwner: TFB30Events;
53 FName: AnsiString;
54 FRef: integer;
55 {$IFDEF WINDOWS}
56 {Make direct use of Windows API as TEventObject don't seem to work under
57 Windows!}
58 FEventHandler: THandle;
59 {$ELSE}
60 FEventWaiting: TEventObject;
61 {$ENDIF}
62 public
63 constructor Create(aOwner: TFB30Events; aName: AnsiString);
64 destructor Destroy; override;
65 procedure addRef(); override;
66 function release(): Integer; override;
67 procedure eventCallbackFunction(length: Cardinal; events: BytePtr); override;
68 procedure WaitForEvent;
69 procedure CancelWait;
70 end;
71
72 { TFB30Events }
73
74 TFB30Events = class(TFBEvents,IEvents)
75 private
76 FAttachmentIntf: Firebird.IAttachment;
77 FEventHandlerThread: TObject;
78 FEventsIntf: Firebird.IEvents;
79 FAsyncEventCallback: TEventhandlerInterface;
80 FSyncEventCallback: TEventhandlerInterface;
81 procedure InternalAsyncWaitForEvent(EventHandler: TEventHandler; EventCallBack: TEventhandlerInterface);
82 procedure ReleaseIntf;
83 protected
84 procedure CancelEvents(Force: boolean = false); override;
85 function GetIEvents: IEvents; override;
86 public
87 constructor Create(DBAttachment: TFB30Attachment; Events: TStrings);
88 destructor Destroy; override;
89
90 {IEvents}
91 procedure WaitForEvent;
92 procedure AsyncWaitForEvent(EventHandler: TEventHandler); override;
93 end;
94
95 implementation
96
97 uses FBMessages, FBClientAPI;
98
99 type
100 { TEventHandlerThread }
101
102 TEventHandlerThread = class(TThread)
103 private
104 FOwner: TFB30Events;
105 FEventHandler: TEventhandlerInterface;
106 protected
107 procedure Execute; override;
108 public
109 constructor Create(Owner: TFB30Events; EventHandler: TEventhandlerInterface);
110 procedure Terminate;
111 end;
112
113 constructor TEventhandlerInterface.Create(aOwner: TFB30Events; aName: AnsiString);
114 var
115 PSa : PSecurityAttributes;
116 {$IFDEF WINDOWS}
117 Sd : TSecurityDescriptor;
118 Sa : TSecurityAttributes;
119 begin
120 InitializeSecurityDescriptor(@Sd,SECURITY_DESCRIPTOR_REVISION);
121 SetSecurityDescriptorDacl(@Sd,true,nil,false);
122 Sa.nLength := SizeOf(Sa);
123 Sa.lpSecurityDescriptor := @Sd;
124 Sa.bInheritHandle := true;
125 PSa := @Sa;
126 {$ELSE}
127 GUID : TGUID;
128 begin
129 PSa:= nil;
130 {$ENDIF}
131 inherited Create;
132 {$IFDEF WINDOWS}
133 FEventHandler := CreateEvent(PSa,false,false,nil);
134 {$ELSE}
135 CreateGuid(GUID);
136 FEventWaiting := TEventObject.Create(PSa,false,false,GUIDToString(GUID));
137 {$ENDIF}
138 FOWner := aOwner;
139 FName := aName;
140 addRef;
141 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Create'); {$ENDIF}
142 end;
143
144 destructor TEventhandlerInterface.Destroy;
145 begin
146 {$IFDEF WINDOWS}
147 CloseHandle(FEventHandler);
148 {$ELSE}
149 if assigned(FEventWaiting) then FEventWaiting.Free;
150 {$ENDIF}
151 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Destroy'); {$ENDIF}
152 inherited Destroy;
153 end;
154
155 procedure TEventhandlerInterface.addRef;
156 begin
157 Inc(FRef);
158 {$IFDEF EVENTDEBUG} writeln(FName,': ref count = ',FRef);{$ENDIF}
159 end;
160
161 function TEventhandlerInterface.release: Integer;
162 begin
163 Dec(FRef);
164 {$IFDEF EVENTDEBUG} writeln(FName,': ref count = ',FRef);{$ENDIF}
165 if FRef = 0 then Free;
166 Result := FRef;
167 end;
168
169 procedure TEventhandlerInterface.eventCallbackFunction(length: Cardinal;
170 events: BytePtr);
171 begin
172 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Event Callback'); {$ENDIF}
173 FOwner.FCriticalSection.Enter;
174 try
175 if FOwner.FResultBuffer <> nil then
176 Move(events^, FOwner.FResultBuffer^, Length);
177 finally
178 FOwner.FCriticalSection.Leave
179 end;
180 {$IFDEF EVENTDEBUG}writeln(FName,' TEventhandlerInterface: Set Event Called'); {$ENDIF}
181 {$IFDEF WINDOWS}
182 SetEvent(FEventHandler);
183 {$ELSE}
184 FEventWaiting.SetEvent;
185 {$ENDIF}
186 end;
187
188 procedure TEventhandlerInterface.WaitForEvent;
189 begin
190 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Start Event Wait'); {$ENDIF}
191 {$IFDEF WINDOWS}
192 WaitForSingleObject(FEventHandler,INFINITE);
193 {$ELSE}
194 FEventWaiting.WaitFor(INFINITE);
195 {$ENDIF}
196 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Event Wait Ends');{$ENDIF}
197 end;
198
199 procedure TEventhandlerInterface.CancelWait;
200 begin
201 {$IFDEF WINDOWS}
202 SetEvent(FEventHandler);
203 {$ELSE}
204 FEventWaiting.SetEvent;
205 {$ENDIF}
206 end;
207
208 { TEventHandlerThread }
209
210 procedure TEventHandlerThread.Execute;
211 begin
212 {$IFDEF EVENTDEBUG} writeln('Event Handler Thread Starts'); {$ENDIF}
213 while not Terminated do
214 begin
215 FEventHandler.WaitForEvent;
216 {$IFDEF EVENTDEBUG} writeln('Event Handler Ends Wait ',Terminated); {$ENDIF}
217
218 if not Terminated then
219 FOwner.EventSignaled;
220 end;
221 {$IFDEF EVENTDEBUG} writeln('Event Handler Thread Ends'); {$ENDIF}
222 end;
223
224 constructor TEventHandlerThread.Create(Owner: TFB30Events;
225 EventHandler: TEventhandlerInterface);
226 begin
227 inherited Create(false);
228 FOwner := Owner;
229 FEventHandler := EventHandler;
230 FreeOnTerminate := true;
231 end;
232
233 procedure TEventHandlerThread.Terminate;
234 begin
235 inherited Terminate;
236 FEventHandler.CancelWait;
237 {$IFDEF EVENTDEBUG} writeln('Event Handler Thread Cancelled'); {$ENDIF}
238 end;
239
240 { TFB30Events }
241
242 procedure TFB30Events.CancelEvents(Force: boolean);
243 begin
244 FCriticalSection.Enter;
245 try
246 if not FInWaitState then Exit;
247 if FEventsIntf <> nil then
248 with Firebird30ClientAPI do
249 begin
250 FEventsIntf.Cancel(StatusIntf);
251 if not Force then
252 Check4DataBaseError;
253 end;
254 FInWaitState := false;
255 ReleaseIntf;
256 inherited CancelEvents(Force);
257 finally
258 FCriticalSection.Leave
259 end;
260 end;
261
262 function TFB30Events.GetIEvents: IEvents;
263 begin
264 Result := self;
265 end;
266
267 procedure TFB30Events.InternalAsyncWaitForEvent(EventHandler: TEventHandler;
268 EventCallBack: TEventhandlerInterface);
269 begin
270 FCriticalSection.Enter;
271 try
272 if FInWaitState then
273 IBError(ibxeInEventWait,[nil]);
274
275 FEventHandler := EventHandler;
276 ReleaseIntf;
277 with Firebird30ClientAPI do
278 begin
279 FEventsIntf := FAttachmentIntf.queEvents(
280 StatusIntf,EventCallBack,
281 FEventBufferLen, BytePtr(FEventBuffer));
282 Check4DataBaseError;
283 end;
284 FInWaitState := true;
285
286 finally
287 FCriticalSection.Leave
288 end;
289 end;
290
291 procedure TFB30Events.ReleaseIntf;
292 begin
293 if FEventsIntf <> nil then
294 FEventsIntf.release;
295 FEventsIntf := nil;
296 end;
297
298 constructor TFB30Events.Create(DBAttachment: TFB30Attachment; Events: TStrings);
299 begin
300 inherited Create(DBAttachment,DBAttachment,Events);
301 FAttachmentIntf := DBAttachment.AttachmentIntf;
302 FSyncEventCallback := TEventhandlerInterface.Create(self,'Sync');
303 end;
304
305 destructor TFB30Events.Destroy;
306 begin
307 CancelEvents(true);
308 if assigned(FEventHandlerThread) then
309 TEventHandlerThread(FEventHandlerThread).Terminate;
310 if assigned(FAsyncEventCallback) then TEventhandlerInterface(FAsyncEventCallback).release;
311 if assigned(FSyncEventCallback) then TEventhandlerInterface(FSyncEventCallback).release;
312 ReleaseIntf;
313 inherited Destroy;
314 end;
315
316 procedure TFB30Events.AsyncWaitForEvent(EventHandler: TEventHandler);
317 begin
318 {Seems like we have to create a new callback object each time to avoid empty events}
319 if assigned(FEventHandlerThread) then
320 TEventHandlerThread(FEventHandlerThread).Terminate;
321 if assigned(FAsyncEventCallback) then TEventhandlerInterface(FAsyncEventCallback).release;
322 FAsyncEventCallback := TEventhandlerInterface.Create(self,'Async');
323 FEventHandlerThread := TEventHandlerThread.Create(self,FAsyncEventCallback);
324 InternalAsyncWaitForEvent(EventHandler,FAsyncEventCallback);
325 end;
326
327 procedure TFB30Events.WaitForEvent;
328 begin
329 InternalAsyncWaitForEvent(nil,FSyncEventCallback);
330 FSyncEventCallback.WaitForEvent;
331 end;
332
333 end.
334