ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/3.0/FB30Events.pas
Revision: 215
Committed: Thu Mar 15 16:25:03 2018 UTC (6 years, 1 month ago) by tony
Content type: text/x-pascal
File size: 8374 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 interface
38
39 uses
40 {$IFDEF WINDOWS}Windows, {$ENDIF} Classes, SysUtils, Firebird, IB, FB30ClientAPI, FB30Attachment,
41 syncobjs, FBEvents
42 {$IF defined(FPC) and defined(UNIX)} ,cthreads {$IFEND};
43
44 type
45 TFB30Events = class;
46
47 { TEventhandlerInterface }
48
49 TEventhandlerInterface = class(Firebird.IEventCallbackImpl)
50 private
51 FOwner: TFB30Events;
52 FName: AnsiString;
53 FRef: integer;
54 {$IFDEF WINDOWS}
55 {Make direct use of Windows API as TEventObject don't seem to work under
56 Windows!}
57 FEventHandler: THandle;
58 {$ELSE}
59 FEventWaiting: TEventObject;
60 {$ENDIF}
61 public
62 constructor Create(aOwner: TFB30Events; aName: AnsiString);
63 destructor Destroy; override;
64 procedure addRef(); override;
65 function release(): Integer; override;
66 procedure eventCallbackFunction(length: Cardinal; events: BytePtr); override;
67 procedure WaitForEvent;
68 procedure CancelWait;
69 end;
70
71 { TFB30Events }
72
73 TFB30Events = class(TFBEvents,IEvents)
74 private
75 FAttachmentIntf: Firebird.IAttachment;
76 FEventHandlerThread: TObject;
77 FEventsIntf: Firebird.IEvents;
78 FAsyncEventCallback: TEventhandlerInterface;
79 FSyncEventCallback: TEventhandlerInterface;
80 procedure InternalAsyncWaitForEvent(EventHandler: TEventHandler; EventCallBack: TEventhandlerInterface);
81 procedure ReleaseIntf;
82 protected
83 procedure CancelEvents(Force: boolean = false); override;
84 function GetIEvents: IEvents; override;
85 public
86 constructor Create(DBAttachment: TFB30Attachment; Events: TStrings);
87 destructor Destroy; override;
88
89 {IEvents}
90 procedure WaitForEvent;
91 procedure AsyncWaitForEvent(EventHandler: TEventHandler); override;
92 end;
93
94 implementation
95
96 uses FBMessages, FBClientAPI;
97
98 type
99 { TEventHandlerThread }
100
101 TEventHandlerThread = class(TThread)
102 private
103 FOwner: TFB30Events;
104 FEventHandler: TEventhandlerInterface;
105 protected
106 procedure Execute; override;
107 public
108 constructor Create(Owner: TFB30Events; EventHandler: TEventhandlerInterface);
109 procedure Terminate;
110 end;
111
112 constructor TEventhandlerInterface.Create(aOwner: TFB30Events; aName: AnsiString);
113 var
114 PSa : PSecurityAttributes;
115 {$IFDEF WINDOWS}
116 Sd : TSecurityDescriptor;
117 Sa : TSecurityAttributes;
118 begin
119 InitializeSecurityDescriptor(@Sd,SECURITY_DESCRIPTOR_REVISION);
120 SetSecurityDescriptorDacl(@Sd,true,nil,false);
121 Sa.nLength := SizeOf(Sa);
122 Sa.lpSecurityDescriptor := @Sd;
123 Sa.bInheritHandle := true;
124 PSa := @Sa;
125 {$ELSE}
126 GUID : TGUID;
127 begin
128 PSa:= nil;
129 {$ENDIF}
130 inherited Create;
131 {$IFDEF WINDOWS}
132 FEventHandler := CreateEvent(PSa,false,false,nil);
133 {$ELSE}
134 CreateGuid(GUID);
135 FEventWaiting := TEventObject.Create(PSa,false,false,GUIDToString(GUID));
136 {$ENDIF}
137 FOWner := aOwner;
138 FName := aName;
139 addRef;
140 end;
141
142 destructor TEventhandlerInterface.Destroy;
143 begin
144 {$IFDEF WINDOWS}
145 CloseHandle(FEventHandler);
146 {$ELSE}
147 if assigned(FEventWaiting) then FEventWaiting.Free;
148 {$ENDIF}
149 inherited Destroy;
150 end;
151
152 procedure TEventhandlerInterface.addRef;
153 begin
154 Inc(FRef);
155 // writeln(FName,': ref count = ',FRef);
156 end;
157
158 function TEventhandlerInterface.release: Integer;
159 begin
160 Dec(FRef);
161 // writeln(FName,': ref count = ',FRef);
162 if FRef = 0 then Free;
163 Result := FRef;
164 end;
165
166 procedure TEventhandlerInterface.eventCallbackFunction(length: Cardinal;
167 events: BytePtr);
168 begin
169 // writeln('TEventhandlerInterface: Event Callback');
170 FOwner.FCriticalSection.Enter;
171 try
172 if FOwner.FResultBuffer <> nil then
173 Move(events^, FOwner.FResultBuffer^, Length);
174 finally
175 FOwner.FCriticalSection.Leave
176 end;
177 //writeln('TEventhandlerInterface: Set Event Called');
178 {$IFDEF WINDOWS}
179 SetEvent(FEventHandler);
180 {$ELSE}
181 FEventWaiting.SetEvent;
182 {$ENDIF}
183 end;
184
185 procedure TEventhandlerInterface.WaitForEvent;
186 begin
187 // writeln('TEventhandlerInterface: Start Event Wait');
188 {$IFDEF WINDOWS}
189 WaitForSingleObject(FEventHandler,INFINITE);
190 {$ELSE}
191 FEventWaiting.WaitFor(INFINITE);
192 {$ENDIF}
193 // writeln('TEventhandlerInterface: Event Wait Ends');
194 end;
195
196 procedure TEventhandlerInterface.CancelWait;
197 begin
198 {$IFDEF WINDOWS}
199 SetEvent(FEventHandler);
200 {$ELSE}
201 FEventWaiting.SetEvent;
202 {$ENDIF}
203 end;
204
205 { TEventHandlerThread }
206
207 procedure TEventHandlerThread.Execute;
208 begin
209 while not Terminated do
210 begin
211 FEventHandler.WaitForEvent;
212
213 if not Terminated then
214 FOwner.EventSignaled;
215 end;
216 end;
217
218 constructor TEventHandlerThread.Create(Owner: TFB30Events;
219 EventHandler: TEventhandlerInterface);
220 begin
221 inherited Create(false);
222 FOwner := Owner;
223 FEventHandler := EventHandler;
224 FreeOnTerminate := true;
225 end;
226
227 procedure TEventHandlerThread.Terminate;
228 begin
229 inherited Terminate;
230 FEventHandler.CancelWait;
231 end;
232
233 { TFB30Events }
234
235 procedure TFB30Events.CancelEvents(Force: boolean);
236 begin
237 FCriticalSection.Enter;
238 try
239 if not FInWaitState then Exit;
240 if FEventsIntf <> nil then
241 with Firebird30ClientAPI do
242 begin
243 FEventsIntf.Cancel(StatusIntf);
244 if not Force then
245 Check4DataBaseError;
246 end;
247 FInWaitState := false;
248 ReleaseIntf;
249 inherited CancelEvents(Force);
250 finally
251 FCriticalSection.Leave
252 end;
253 end;
254
255 function TFB30Events.GetIEvents: IEvents;
256 begin
257 Result := self;
258 end;
259
260 procedure TFB30Events.InternalAsyncWaitForEvent(EventHandler: TEventHandler;
261 EventCallBack: TEventhandlerInterface);
262 begin
263 FCriticalSection.Enter;
264 try
265 if FInWaitState then
266 IBError(ibxeInEventWait,[nil]);
267
268 FEventHandler := EventHandler;
269 ReleaseIntf;
270 with Firebird30ClientAPI do
271 begin
272 FEventsIntf := FAttachmentIntf.queEvents(
273 StatusIntf,EventCallBack,
274 FEventBufferLen, BytePtr(FEventBuffer));
275 Check4DataBaseError;
276 end;
277 FInWaitState := true;
278
279 finally
280 FCriticalSection.Leave
281 end;
282 end;
283
284 procedure TFB30Events.ReleaseIntf;
285 begin
286 if FEventsIntf <> nil then
287 FEventsIntf.release;
288 FEventsIntf := nil;
289 end;
290
291 constructor TFB30Events.Create(DBAttachment: TFB30Attachment; Events: TStrings);
292 begin
293 inherited Create(DBAttachment,DBAttachment,Events);
294 FAttachmentIntf := DBAttachment.AttachmentIntf;
295 FSyncEventCallback := TEventhandlerInterface.Create(self,'Sync');
296 end;
297
298 destructor TFB30Events.Destroy;
299 begin
300 CancelEvents(true);
301 if assigned(FEventHandlerThread) then
302 TEventHandlerThread(FEventHandlerThread).Terminate;
303 if assigned(FAsyncEventCallback) then TEventhandlerInterface(FAsyncEventCallback).release;
304 if assigned(FSyncEventCallback) then TEventhandlerInterface(FSyncEventCallback).release;
305 ReleaseIntf;
306 inherited Destroy;
307 end;
308
309 procedure TFB30Events.AsyncWaitForEvent(EventHandler: TEventHandler);
310 begin
311 {Seems like we have to create a new callback object each time to avoid empty events}
312 if assigned(FEventHandlerThread) then
313 TEventHandlerThread(FEventHandlerThread).Terminate;
314 if assigned(FAsyncEventCallback) then TEventhandlerInterface(FAsyncEventCallback).release;
315 FAsyncEventCallback := TEventhandlerInterface.Create(self,'Async');
316 FEventHandlerThread := TEventHandlerThread.Create(self,FAsyncEventCallback);
317 InternalAsyncWaitForEvent(EventHandler,FAsyncEventCallback);
318 end;
319
320 procedure TFB30Events.WaitForEvent;
321 begin
322 InternalAsyncWaitForEvent(nil,FSyncEventCallback);
323 FSyncEventCallback.WaitForEvent;
324 end;
325
326 end.
327