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, 8 months 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

# User Rev Content
1 tony 45 (*
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 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$interfaces COM}
35     {$ENDIF}
36    
37 tony 217 { $DEFINE EVENTDEBUG}
38    
39 tony 45 interface
40    
41     uses
42     {$IFDEF WINDOWS}Windows, {$ENDIF} Classes, SysUtils, Firebird, IB, FB30ClientAPI, FB30Attachment,
43 tony 216 syncobjs, FBEvents;
44 tony 45
45     type
46     TFB30Events = class;
47    
48     { TEventhandlerInterface }
49    
50     TEventhandlerInterface = class(Firebird.IEventCallbackImpl)
51     private
52     FOwner: TFB30Events;
53 tony 56 FName: AnsiString;
54 tony 45 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 tony 56 constructor Create(aOwner: TFB30Events; aName: AnsiString);
64 tony 45 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 tony 47 procedure AsyncWaitForEvent(EventHandler: TEventHandler); override;
93 tony 45 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 tony 56 constructor TEventhandlerInterface.Create(aOwner: TFB30Events; aName: AnsiString);
114 tony 45 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 tony 47 FEventHandler := CreateEvent(PSa,false,false,nil);
134 tony 45 {$ELSE}
135     CreateGuid(GUID);
136     FEventWaiting := TEventObject.Create(PSa,false,false,GUIDToString(GUID));
137     {$ENDIF}
138     FOWner := aOwner;
139     FName := aName;
140     addRef;
141 tony 217 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Create'); {$ENDIF}
142 tony 45 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 tony 217 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Destroy'); {$ENDIF}
152 tony 45 inherited Destroy;
153     end;
154    
155     procedure TEventhandlerInterface.addRef;
156     begin
157     Inc(FRef);
158 tony 217 {$IFDEF EVENTDEBUG} writeln(FName,': ref count = ',FRef);{$ENDIF}
159 tony 45 end;
160    
161     function TEventhandlerInterface.release: Integer;
162     begin
163     Dec(FRef);
164 tony 217 {$IFDEF EVENTDEBUG} writeln(FName,': ref count = ',FRef);{$ENDIF}
165 tony 45 if FRef = 0 then Free;
166     Result := FRef;
167     end;
168    
169     procedure TEventhandlerInterface.eventCallbackFunction(length: Cardinal;
170     events: BytePtr);
171     begin
172 tony 217 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Event Callback'); {$ENDIF}
173 tony 45 FOwner.FCriticalSection.Enter;
174     try
175     if FOwner.FResultBuffer <> nil then
176 tony 56 Move(events^, FOwner.FResultBuffer^, Length);
177 tony 45 finally
178     FOwner.FCriticalSection.Leave
179     end;
180 tony 217 {$IFDEF EVENTDEBUG}writeln(FName,' TEventhandlerInterface: Set Event Called'); {$ENDIF}
181 tony 47 {$IFDEF WINDOWS}
182     SetEvent(FEventHandler);
183     {$ELSE}
184     FEventWaiting.SetEvent;
185     {$ENDIF}
186 tony 45 end;
187    
188     procedure TEventhandlerInterface.WaitForEvent;
189     begin
190 tony 217 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Start Event Wait'); {$ENDIF}
191 tony 45 {$IFDEF WINDOWS}
192     WaitForSingleObject(FEventHandler,INFINITE);
193     {$ELSE}
194     FEventWaiting.WaitFor(INFINITE);
195     {$ENDIF}
196 tony 217 {$IFDEF EVENTDEBUG} writeln(FName,' TEventhandlerInterface: Event Wait Ends');{$ENDIF}
197 tony 45 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 tony 217 {$IFDEF EVENTDEBUG} writeln('Event Handler Thread Starts'); {$ENDIF}
213 tony 45 while not Terminated do
214     begin
215     FEventHandler.WaitForEvent;
216 tony 217 {$IFDEF EVENTDEBUG} writeln('Event Handler Ends Wait ',Terminated); {$ENDIF}
217 tony 45
218     if not Terminated then
219     FOwner.EventSignaled;
220     end;
221 tony 217 {$IFDEF EVENTDEBUG} writeln('Event Handler Thread Ends'); {$ENDIF}
222 tony 45 end;
223    
224     constructor TEventHandlerThread.Create(Owner: TFB30Events;
225     EventHandler: TEventhandlerInterface);
226     begin
227 tony 56 inherited Create(false);
228 tony 45 FOwner := Owner;
229     FEventHandler := EventHandler;
230     FreeOnTerminate := true;
231     end;
232    
233     procedure TEventHandlerThread.Terminate;
234     begin
235     inherited Terminate;
236     FEventHandler.CancelWait;
237 tony 217 {$IFDEF EVENTDEBUG} writeln('Event Handler Thread Cancelled'); {$ENDIF}
238 tony 45 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 tony 47 {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 tony 45 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