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

File Contents

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