ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/sv5ipc.inc
Revision: 321
Committed: Thu Feb 25 12:10:07 2021 UTC (3 years, 8 months ago) by tony
File size: 21478 byte(s)
Log Message:
tidy up IPC

File Contents

# User Rev Content
1 tony 319 {Used by IBIPC and implements System V IPC}
2 tony 209
3 tony 319 uses IBMessages, ipc, Errors, baseunix;
4    
5 tony 209 const
6     IPCFileName: string = 'FB.SQL.MONITOR1_0';
7     cNumberOfSemaphores = 10;
8     cMutexSemaphore = 0;
9     cMonitorCounter = 1;
10     cReadReadyEventSemaphore = 2;
11     cReadFinishedEventSemaphore = 4;
12     cDataAvailableEventSemaphore = 6;
13     cWriterBusyEventSemaphore = 8;
14 tony 320 cDefaultTimeout = 10; {seconds }
15 tony 209
16     {$IF FPC_FULLVERSION = 30000 }
17     {Fix regression in FPC 3.0.0 ipc.pp unit. Expected to be fixed in fpc 3.0.2}
18     {$IF defined(darwin) }
19     SEM_GETNCNT = 3; { Return the value of sempid (READ) }
20     SEM_GETPID = 4; { Return the value of semval (READ) }
21     SEM_GETVAL = 5; { Return semvals into arg.array (READ) }
22     SEM_GETALL = 6; { Return the value of semzcnt (READ) }
23     SEM_GETZCNT = 7; { Set the value of semval to arg.val (ALTER) }
24     SEM_SETVAL = 8; { Set semvals from arg.array (ALTER) }
25     SEM_SETALL = 9;
26     {$ENDIF}
27     {$ENDIF}
28    
29     function GetLastErrno: cint;
30     begin
31     Result := fpgetErrno
32     end;
33    
34     type
35     {Interprocess Communication Objects. All platform dependent IPC is abstracted
36     into this set of objects }
37    
38     { TIpcCommon }
39    
40 tony 319 TIpcCommon = class(TInterfacedObject)
41     protected
42 tony 320 class var FSemaphoreSetID: cint; {Initialised by TSharedMemory. Used by other classes}
43 tony 209 function sem_op(SemNum, op: integer; flags: cshort = 0): cint;
44     function sem_timedop(SemNum, op: integer; timeout_secs: integer; flags: cshort = 0): cint;
45     function GetSemValue(SemNum: integer): cint;
46     procedure SemInit(SemNum, AValue: cint);
47     public
48 tony 319 function GetSa: PSecurityAttributes;
49 tony 209 property Sa : PSecurityAttributes read GetSa;
50     end;
51    
52     { TSharedMemory }
53    
54     {
55     The shared memory segment is used for interprocess communication and
56     holds both a message buffer and a number of shared variables. Shared
57     memory is allocated to each shared variable using the Allocate function.
58     An underlying assumption is that each process using the shared memory
59     calls "Allocate" in the same order and for the same memory sizes.
60    
61     Linux:
62    
63     The Linux implementation uses Linux shared memory. IPC_PRIVATE is used
64     to allocate the memory and the resulting memory id is written to a
65     well known file. By default this is in the current user's home directory,
66     but this can be over-ridden to specify a globally unique filename.
67    
68     Access to the shared memory is restricted to the current user/group.
69     Note that the Linux semaphore set is also created with the shared memory.
70     }
71    
72 tony 321 ISharedMemory = interface
73     ['{db77bdd4-233a-4c9c-9212-dd7945e2e57c}']
74 tony 320 function IsInitialiser: boolean;
75 tony 321 function Allocate(Size: integer): PByte;
76     function GetLastAllocationSize: integer;
77     property LastAllocationSize: integer read GetLastAllocationSize;
78 tony 320 end;
79    
80 tony 319 TSharedMemory = class(TIpcCommon,ISharedMemory)
81 tony 209 private
82 tony 320 FSharedMemoryID: cint;
83 tony 319 FBuffer: PByte;
84 tony 209 FLastAllocationSize: integer;
85     FUnused: integer;
86 tony 319 FBufptr: PByte;
87     FIPCFileName: AnsiString;
88 tony 320 FInitialiser: boolean;
89 tony 209 procedure DropSharedMemory;
90     procedure GetSharedMemory(MemSize: integer);
91     public
92     constructor Create(MemSize: integer);
93     destructor Destroy; override;
94 tony 319 function Allocate(Size: integer): PByte;
95     function GetLastAllocationSize: integer;
96 tony 320 function IsInitialiser: boolean;
97 tony 319 property LastAllocationSize: integer read GetLastAllocationSize;
98 tony 209 end;
99    
100     {TMutex}
101    
102 tony 319 TMutex = class(TIpcCommon,IMutex)
103 tony 209 private
104     FMutexSemaphore: cint;
105     FLockCount: integer;
106     public
107 tony 320 constructor Create(SemNumber: cint; IsInitialiser: boolean);
108 tony 209 procedure Lock;
109     procedure Unlock;
110     end;
111    
112     { TSingleLockGate }
113    
114     {
115     A single lock gate is either open or closed. When open, any thread can pass
116     through it while, when closed, all threads are blocked as they try to pass
117     through the gate. When the gate is opened, all blocked threads are resumed.
118    
119     There is an implementation assumption that only one writer thread at
120     a time (i.e. the thread which locks or unlocks the gate) can have access to
121     it at any one time. I.e. an external Mutex prevents race conditions.
122    
123     Linux:
124    
125     In the Linux implementation, the gate is implemented by a semaphore
126     and a share memory integer used as a bi-state variable. When the gate
127     is open, the bi-state variable is non-zero. It is set to zero when closed.
128     Another shared memory integer is used to count the number of waiting
129     threads, and a second semaphore is used to protect access to this.
130    
131     The event semaphore is initialised to zero. When a thread passes through the gate
132     it checks the state. If open, the thread continues. If closed then it
133     increments the count of waiting threads and then decrements the semaphore
134     and hence enters an indefinite wait state.
135    
136     When the gate is locked, the state is set to zero. When unlocked, the state
137     is set to one and the semaphore incremented by the number of waiting threads,
138     which itself is then zeroed.
139    
140     Always initialised to the Unlocked state
141     }
142    
143 tony 319 TSingleLockGate = class(TIpcCommon,ISingleLockGate)
144 tony 209 private
145 tony 321 FSharedMemory: ISharedMemory;
146 tony 209 FSemaphore: cint;
147     FMutex: cint;
148     FSignalledState: PInteger;
149     FWaitingThreads: PInteger;
150     function GetWaitingThreads: integer;
151     public
152 tony 321 constructor Create(SemNum: cint; sm: ISharedMemory);
153 tony 209 property WaitingThreads: integer read GetWaitingThreads;
154     public
155     procedure PassthroughGate;
156     procedure Unlock;
157     procedure Lock;
158     end;
159    
160     { TMultilockGate }
161    
162     { This type of Gate is used where several reader threads must pass
163     through the gate before it can be opened for a writer thread.
164    
165     The reader threads register their interest by each locking the gate.
166     The writer thread then waits on the locked gate until all the reader
167     threads have separately unlocked the gate.
168    
169     There is an underlying assumption of a single writer. A Mutex must
170     be used to control access to the gate from the writer side if this
171     assumption is invalid.
172    
173     Linux:
174    
175     The Linux implementation uses a single semaphore to implement the gate,
176     which is initialised to 1 (unlocked), and a count of the number of
177     threads that have locked the gate (LockCount). A mutex semaphore
178     protects access to the LockCount. When the gate is locked, the lockcount
179     is incremented and, if the LockCount was originally zero, the semaphore is
180     set to zero (Gate Closed).
181    
182     Unlocking the gate, is the reverse. The LockCount is decremented and, if it
183     reaches zero, the semaphore is set to one (Gate Opened).
184    
185     When a writer passes through the gate, it checks the LockCount, if zero it
186     proceeds to pass through the gate. Otherwise it decrements and waits on the
187     semaphore. When the writer resumes, it increments the semaphore in order
188     to return it to its unlocked state. The wait is a timed wait, as there is
189     a risk that a reader thread may terminate while the gate is locked. If the
190     LockCount is non-zero, it is decremented and the writer returns to wait on
191     the gate.
192    
193     Always initialised to the Unlocked state
194     }
195    
196 tony 319 TMultilockGate = class(TIpcCommon,IMultiLockGate)
197 tony 209 private
198 tony 321 FSharedMemory: ISharedMemory;
199 tony 209 FOnGateTimeout: TNotifyEvent;
200     FSemaphore: cint;
201     FMutex: cint;
202     FLockCount: PInteger;
203     function GetLockCount: integer;
204     public
205 tony 321 constructor Create(SemNum: cint; sm: ISharedMemory);
206 tony 209 procedure Lock;
207     procedure Unlock;
208     procedure PassthroughGate;
209 tony 319 function GetOnGateTimeout: TNotifyEvent;
210     procedure SetOnGateTimeout(AValue: TNotifyEvent);
211 tony 209 property LockCount: integer read GetLockCount;
212 tony 319 property OnGateTimeout: TNotifyEvent read GetOnGateTimeout write SetOnGateTimeout;
213 tony 209 end;
214    
215 tony 319 { TIPCInterface }
216 tony 209
217 tony 319 TIPCInterface = class(TIpcCommon,IIPCInterface)
218 tony 209 private
219     FMaxBufferSize: integer;
220 tony 321 FSharedMemory: ISharedMemory;
221 tony 319 FWriteLock: IMutex;
222     FBuffer: PByte;
223 tony 209 FTraceDataType,
224     FBufferSize: PInteger;
225     FTimeStamp: PDateTime;
226 tony 319 FMsgNumber: PInteger;
227     FReadReadyEvent: IMultiLockGate;
228     FReadFinishedEvent: IMultiLockGate;
229     FDataAvailableEvent: ISingleLockGate;
230     FWriterBusyEvent: ISingleLockGate;
231 tony 209 public
232     constructor Create;
233     procedure IncMonitorCount;
234     procedure DecMonitorCount;
235     procedure SendTrace(TraceObject: TTraceObject);
236     procedure ReceiveTrace(TraceObject: TTraceObject);
237 tony 319 function GetDataAvailableEvent: ISingleLockGate;
238     function GetWriterBusyEvent: ISingleLockGate;
239     function GetReadReadyEvent: IMultiLockGate;
240     function GetReadFinishedEvent: IMultiLockGate;
241     function GetWriteLock: IMutex;
242     function GetMonitorCount: integer;
243     function GetMaxBufferSize: integer;
244     property DataAvailableEvent: ISingleLockGate read GetDataAvailableEvent;
245     property WriterBusyEvent: ISingleLockGate read GetWriterBusyEvent;
246     property ReadReadyEvent: IMultiLockGate read GetReadReadyEvent;
247     property ReadFinishedEvent: IMultiLockGate read GetReadFinishedEvent;
248     property WriteLock: IMutex read GetWriteLock;
249 tony 209 property MonitorCount: integer read GetMonitorCount;
250 tony 319 property MaxBufferSize: integer read GetMaxBufferSize;
251 tony 209 end;
252    
253     { TSharedMemory }
254    
255     procedure TSharedMemory.GetSharedMemory(MemSize: integer);
256     var F: cint;
257     begin
258 tony 319 if GetEnvironmentVariable('FBSQL_IPCFILENAME') <> '' then
259     FIPCFileName := GetEnvironmentVariable('FBSQL_IPCFILENAME')
260     else
261     FIPCFileName := GetTempDir(true) + IPCFileName + '.' + GetEnvironmentVariable('USER');
262    
263 tony 209 {Get the Shared Memory and Semaphore IDs from the Global File if it exists
264     or create them and the file otherwise }
265    
266     repeat
267 tony 319 F := fpOpen(FIPCFileName, O_WrOnly or O_Creat or O_Excl);
268 tony 209 if F < 0 then
269     begin
270     if fpgetErrno = ESysEEXIST {EEXIST} then
271     begin
272     { looks like it already exists}
273     Sleep(100);
274 tony 319 F := fpOpen(FIPCFileName,O_RdOnly);
275 tony 209 if (F < 0) and (fpgetErrno = ESysENOENT {ENOENT}) then
276     {probably just got deleted }
277     else
278     if F < 0 then
279     IBError(ibxeCannotCreateSharedResource,['Error accessing IPC File - ' +
280     StrError(fpgetErrno)]);
281     end
282     else
283     IBError(ibxeCannotCreateSharedResource,['Error creating IPC File - ' +
284     StrError(fpgetErrno)]);
285     end
286     else
287     FInitialiser := true
288     until F >= 0;
289    
290     if FInitialiser then
291     begin
292     FSharedMemoryID := shmget(IPC_PRIVATE,MemSize, IPC_CREAT or
293     S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP);
294     if FSharedMemoryID < 0 then
295     IBError(ibxeCannotCreateSharedResource,['Cannot create shared memory segment - ' +
296     StrError(fpgetErrno)]);
297    
298     FSemaphoreSetID := semget(IPC_PRIVATE, cNumberOfSemaphores,IPC_CREAT or
299     S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP);
300     if FSemaphoreSetID < 0 then
301     IBError(ibxeCannotCreateSharedResource,['Cannot create shared semaphore set - ' +
302     StrError(fpgetErrno)]);
303    
304     fpWrite(F,FSharedMemoryID,sizeof(FSharedMemoryID));
305     fpWrite(F,FSemaphoreSetID,sizeof(FSemaphoreSetID));
306     end
307     else
308     begin
309     fpRead(F,FSharedMemoryID,sizeof(FSharedMemoryID));
310     fpRead(F,FSemaphoreSetID,sizeof(FSemaphoreSetID));
311     if GetSemValue(cMonitorCounter) = 0 then
312     begin
313     FInitialiser := true;
314     //writeln('Opened file and is initialiser');
315     end
316     end;
317     fpClose(F);
318     end;
319    
320     procedure TSharedMemory.DropSharedMemory;
321     var ds: TShmid_ds;
322     arg: tsemun;
323     begin
324     if shmctl(FSharedMemoryID,IPC_STAT,@ds) < 0 then
325     IBError(ibxeSV5APIError,['Error getting shared memory info' + strError(fpgetErrno)]);
326     if ds.shm_nattch = 0 then { we are the last one out - so, turn off the lights }
327     begin
328     shmctl(FSharedMemoryID,IPC_RMID,nil);
329     semctl(FSemaphoreSetID,0,IPC_RMID,arg);
330 tony 319 DeleteFile(FIPCFileName);
331 tony 209 end;
332     end;
333    
334     constructor TSharedMemory.Create(MemSize: integer);
335     begin
336     inherited Create;
337     FInitialiser := false;
338     GetSharedMemory(MemSize);
339     FBuffer := shmat(FSharedMemoryID,nil,0);
340     if PtrInt(FBuffer) = -1 then
341     IBError(ibxeCannotCreateSharedResource,[StrError(Errno)]);
342     FBufPtr := FBuffer;
343     FUnused := MemSize
344     end;
345    
346     destructor TSharedMemory.Destroy;
347     begin
348     shmdt(FBuffer);
349     DropSharedMemory;
350     inherited Destroy;
351     end;
352    
353 tony 319 function TSharedMemory.Allocate(Size: integer): PByte;
354 tony 209 begin
355     if Size > FUnused then
356     IBError(ibxeCannotCreateSharedResource, ['Not enough shared memory']);
357     Result := FBufPtr;
358    
359     if Size = 0 then
360     begin
361     FLastAllocationSize := FUnused;
362     FUnused := 0
363     end
364     else
365     begin
366     FLastAllocationSize := Size;
367     Dec(FUnused,Size);
368     end;
369     Inc(FBufPtr,Size)
370     end;
371    
372 tony 319 function TSharedMemory.GetLastAllocationSize: integer;
373     begin
374     Result := FLastAllocationSize;
375     end;
376    
377 tony 320 function TSharedMemory.IsInitialiser: boolean;
378     begin
379     Result := FInitialiser;
380     end;
381    
382 tony 209 { TIpcCommon }
383    
384     function TIpcCommon.GetSa: PSecurityAttributes;
385     begin
386     Result := nil
387     end;
388    
389     function TIpcCommon.sem_op(SemNum, op: integer; flags: cshort): cint;
390     var sembuf: TSEMbuf;
391     begin
392     sembuf.sem_num := SemNum;
393     sembuf.sem_op:= op;
394     sembuf.sem_flg := flags or SEM_UNDO;
395     Result := semop(FSemaphoreSetID,@sembuf,1);
396     end;
397    
398     function TIpcCommon.sem_timedop(SemNum, op: integer; timeout_secs: integer;
399     flags: cshort): cint;
400     var sembuf: TSEMbuf;
401     timeout: TimeSpec;
402     begin
403     sembuf.sem_num := SemNum;
404     sembuf.sem_op:= op;
405     sembuf.sem_flg := flags or SEM_UNDO;
406     timeout.tv_sec := timeout_secs;
407     timeout.tv_nsec := 0;
408 tony 319 {$IF declared(semtimedop)}
409 tony 209 Result := semtimedop(FSemaphoreSetID,@sembuf,1,@timeout);
410     {$ELSE}
411     Result := semop(FSemaphoreSetID,@sembuf,1); {May hang on race condition}
412 tony 319 {$IFEND}
413 tony 209 end;
414    
415     function TIpcCommon.GetSemValue(SemNum: integer): cint;
416     var args :TSEMun;
417     begin
418     Result := semctl(FSemaphoreSetID,SemNum,SEM_GETVAL,args);
419     if Result < 0 then
420     IBError(ibxeSV5APIError,['GetSemValue: '+strError(GetLastErrno)]);
421     end;
422    
423     procedure TIpcCommon.SemInit(SemNum, AValue: cint);
424     var args :TSEMun;
425     begin
426     //writeln('Initialising ',SemNum,' to ',AValue);
427     args.val := AValue;
428     if semctl(FSemaphoreSetID,SemNum,SEM_SETVAL,args) < 0 then
429     IBError(ibxeCannotCreateSharedResource,['Unable to initialise Semaphone ' +
430     IntToStr(SemNum) + '- ' + StrError(GetLastErrno)]);
431    
432     end;
433    
434     { TMutex }
435    
436 tony 320 constructor TMutex.Create(SemNumber: cint; IsInitialiser: boolean);
437 tony 209 begin
438     inherited Create;
439     FMutexSemaphore := SemNumber;
440 tony 320 if IsInitialiser then
441 tony 209 SemInit(FMutexSemaphore,1)
442     end;
443    
444     { Obtain ownership of the Mutex and prevent other threads from accessing protected resource }
445    
446     procedure TMutex.Lock;
447     begin
448     //writeln('Lock: Entering Mutex ',FMutexSemaphore,' LockCount=',FLockCount,' State = ',GetSemValue(FMutexSemaphore));
449     if FLockCount = 0 then
450     sem_op(FMutexSemaphore,-1);
451     Inc(FLockCount);
452     //writeln('Lock: Mutex Exit');
453     end;
454    
455     {Give up ownership of the Mutex and allow other threads access }
456    
457     procedure TMutex.Unlock;
458     begin
459     //writeln('UnLock: Entering Mutex, LockCount=',FLockCount);
460     if FLockCount = 0 then Exit;
461     Dec(FLockCount);
462     if FLockCount = 0 then
463     sem_op(FMutexSemaphore,1);
464     //writeln('UnLock: Mutex Exit',' State = ',GetSemValue(FMutexSemaphore));
465     end;
466    
467     { TSingleLockGate }
468    
469     function TSingleLockGate.GetWaitingThreads: integer;
470     begin
471     Result := FWaitingThreads^
472     end;
473    
474 tony 321 constructor TSingleLockGate.Create(SemNum: cint; sm: ISharedMemory);
475 tony 209 begin
476     inherited Create;
477 tony 319 FSharedMemory := sm;
478     FSignalledState := PInteger(FSharedMemory.Allocate(sizeof(FSignalledState)));
479     FWaitingThreads := PInteger(FSharedMemory.Allocate(sizeof(FWaitingThreads)));
480 tony 209 FSemaphore := SemNum;
481     FMutex := SemNum + 1;
482 tony 320 if FSharedMemory.IsInitialiser then
483 tony 209 begin
484     FSignalledState^ := 1;
485     FWaitingThreads^ := 0;
486     SemInit(FSemaphore,0);
487     SemInit(FMutex,1);
488     end;
489     end;
490    
491     procedure TSingleLockGate.PassthroughGate;
492     begin
493     if FSignalledState^ = 0 then
494     begin
495     sem_op(FMutex,-1,0); //Acquire Mutex
496     Inc(FWaitingThreads^);
497     sem_op(FMutex,1,0); //Release Mutex
498     //writeln(ClassName + ': Wait State Entered ',FSemaphore,' = ',GetSemValue(FSemaphore));
499     sem_op(FSemaphore,-1,0); //Enter Wait
500     //writeln(ClassName + ': Wait State Ends ',FSemaphore);
501     end;
502     end;
503    
504     procedure TSingleLockGate.Unlock;
505     begin
506     if FSignalledState^ = 0 then
507     begin
508     FSignalledState^ := 1;
509     sem_op(FMutex,-1,0); //Acquire Mutex
510 tony 319 {$IFDEF DEBUG}writeln(ClassName + ': Unlocking' ,FSemaphore);{$ENDIF}
511 tony 209 sem_op(FSemaphore,FWaitingThreads^,0);
512     FWaitingThreads^ := 0;
513     sem_op(FMutex,1,0); //Release Mutex
514     end;
515     end;
516    
517     procedure TSingleLockGate.Lock;
518     begin
519     if FSignalledState^ = 1 then
520     begin
521 tony 319 {$IFDEF DEBUG}writeln(ClassName + ': Locking Gate ',FSemaphore);{$ENDIF}
522 tony 209 SemInit(FSemaphore,0);
523     FSignalledState^ := 0;
524     end;
525     end;
526    
527     { TMultilockGate }
528    
529 tony 321 constructor TMultilockGate.Create(SemNum: cint; sm: ISharedMemory);
530 tony 209 begin
531     inherited Create;
532     FSemaphore := SemNum;
533     FMutex := SemNum + 1;
534 tony 319 FSharedMemory := sm;
535     FLockCount := PInteger(FSharedMemory.Allocate(sizeof(FLockCount)));
536 tony 320 if FSharedMemory.IsInitialiser then
537 tony 209 begin
538     FLockCount^ := 0;
539     SemInit(FSemaphore,1);
540     SemInit(FMutex,1);
541     end;
542     end;
543    
544     function TMultilockGate.GetLockCount: integer;
545     begin
546     Result := FLockCount^
547     end;
548    
549 tony 319 function TMultilockGate.GetOnGateTimeout: TNotifyEvent;
550     begin
551     Result := FOnGateTimeout;
552     end;
553    
554     procedure TMultilockGate.SetOnGateTimeout(AValue: TNotifyEvent);
555     begin
556     FOnGateTimeout := AValue;
557     end;
558    
559 tony 209 procedure TMultilockGate.Lock;
560     begin
561     sem_op(FMutex,-1,0); //Acquire Mutex
562     if FLockCount^ = 0 then
563     begin
564 tony 319 {$IFDEF DEBUG}writeln(ClassName,': Locking ',FSemaphore);{$ENDIF}
565 tony 209 SemInit(FSemaphore,0);
566     end;
567     Inc(FLockCount^);
568     sem_op(FMutex,1,0); //Release Mutex
569     end;
570    
571     procedure TMultilockGate.Unlock;
572     begin
573     sem_op(FMutex,-1,0); //Acquire Mutex
574     Dec(FLockCount^);
575     if FLockCount^ <= 0 then
576     begin
577 tony 319 {$IFDEF DEBUG}writeln(ClassName,': UnLocking ',FSemaphore);{$ENDIF}
578 tony 209 SemInit(FSemaphore,1);
579     FLockCount^ := 0
580     end;
581     sem_op(FMutex,1,0); //Release Mutex
582     end;
583    
584     procedure TMultilockGate.PassthroughGate;
585     begin
586     if FLockCount^ = 0 then
587     Exit;
588 tony 319 {$IFDEF DEBUG}writeln(ClassName,': Waiting on ',FSemaphore);{$ENDIF}
589 tony 209 while sem_timedop(FSemaphore,-1,cDefaultTimeout) < 0 do
590     {looks like we lost a reader}
591     begin
592 tony 319 {$IFDEF DEBUG}writeln(ClassName,': reader lost timeout');{$ENDIF}
593 tony 209 if FLockCount^ > 0 then
594     begin
595     UnLock;
596     if assigned(FOnGateTimeout) then
597     OnGateTimeout(self)
598     end
599     end;
600     sem_op(FSemaphore,1);
601 tony 319 {$IFDEF DEBUG}writeln(ClassName,': Wait done on ',FSemaphore);{$ENDIF}
602 tony 209 end;
603    
604    
605 tony 319 { TIPCInterface }
606 tony 209
607 tony 319 function TIPCInterface.GetMonitorCount: integer;
608 tony 209 begin
609     Result := GetSemValue(cMonitorCounter)
610     end;
611    
612 tony 319 function TIPCInterface.GetMaxBufferSize: integer;
613     begin
614     Result := FMaxBufferSize;
615     end;
616    
617     constructor TIPCInterface.Create;
618     begin
619 tony 209 inherited Create;
620     FSharedMemory := TSharedMemory.Create(cMonitorHookSize);
621    
622 tony 320 FWriteLock := TMutex.Create(cMutexSemaphore,FSharedMemory.IsInitialiser);
623 tony 209
624 tony 319 FDataAvailableEvent := TSingleLockGate.Create(cDataAvailableEventSemaphore,FSharedMemory);
625     FWriterBusyEvent := TSingleLockGate.Create(cWriterBusyEventSemaphore,FSharedMemory);
626     FReadReadyEvent := TMultiLockGate.Create(cReadReadyEventSemaphore,FSharedMemory);
627     FReadFinishedEvent := TMultiLockGate.Create(cReadFinishedEventSemaphore,FSharedMemory);
628 tony 209
629 tony 320 if FSharedMemory.IsInitialiser then
630 tony 209 SemInit(cMonitorCounter,0);
631     FTraceDataType := PInteger(FSharedMemory.Allocate(sizeof(Integer)));
632     FTimeStamp := PDateTime(FSharedMemory.Allocate(sizeof(TDateTime)));
633     FBufferSize := PInteger(FSharedMemory.Allocate(sizeof(Integer)));
634 tony 319 FMsgNumber := PInteger(FSharedMemory.Allocate(sizeof(Integer)));
635 tony 209 FBuffer := FSharedMemory.Allocate(0); //All remaining
636     FMaxBufferSize := FSharedMemory.LastAllocationSize;
637    
638 tony 320 if FSharedMemory.IsInitialiser then
639 tony 209 begin
640     FBufferSize^ := 0;
641 tony 319 FDataAvailableEvent.Lock;
642     FMsgNumber^ := 0;
643 tony 209 end;
644     end;
645    
646 tony 319 procedure TIPCInterface.IncMonitorCount;
647 tony 209 begin
648     sem_op(cMonitorCounter,1);
649     end;
650    
651 tony 319 procedure TIPCInterface.DecMonitorCount;
652 tony 209 begin
653     sem_op(cMonitorCounter,-1,IPC_NOWAIT);
654     end;
655    
656 tony 319 procedure TIPCInterface.SendTrace(TraceObject: TTraceObject);
657 tony 209 begin
658     FTraceDataType^ := Integer(TraceObject.FDataType);
659     FTimeStamp^ := TraceObject.FTimeStamp;
660 tony 319 if Length(TraceObject.FMsg) > MaxBufferSize then
661     FBufferSize^ := MaxBufferSize
662     else
663     FBufferSize^ := Length(TraceObject.FMsg);
664     FMsgNumber^ := TraceObject.FMsgNumber;
665 tony 209 Move(TraceObject.FMsg[1], FBuffer^, FBufferSize^);
666     end;
667    
668 tony 319 procedure TIPCInterface.ReceiveTrace(TraceObject: TTraceObject);
669 tony 209 begin
670 tony 319 SetString(TraceObject.FMsg, PAnsiChar(FBuffer), FBufferSize^);
671 tony 209 TraceObject.FDataType := TTraceFlag(FTraceDataType^);
672     TraceObject.FTimeStamp := TDateTime(FTimeStamp^);
673 tony 319 TraceObject.FMsgNumber := FMsgNumber^;
674 tony 209 end;
675    
676 tony 319 function TIPCInterface.GetDataAvailableEvent: ISingleLockGate;
677     begin
678     Result := FDataAvailableEvent;
679     end;
680 tony 209
681 tony 319 function TIPCInterface.GetWriterBusyEvent: ISingleLockGate;
682     begin
683     Result := FWriterBusyEvent;
684     end;
685 tony 209
686 tony 319 function TIPCInterface.GetReadReadyEvent: IMultiLockGate;
687     begin
688     Result := FReadReadyEvent;
689     end;
690    
691     function TIPCInterface.GetReadFinishedEvent: IMultiLockGate;
692     begin
693     Result := FReadFinishedEvent;
694     end;
695    
696     function TIPCInterface.GetWriteLock: IMutex;
697     begin
698     Result := FWriteLock;
699     end;
700    
701    
702