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: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 7793 byte(s)
Log Message:
Committing updates for Release R2-0-0

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