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

# 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 protected
42 class var FSemaphoreSetID: cint; {Initialised by TSharedMemory. Used by other classes}
43 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 function GetSa: PSecurityAttributes;
49 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 ISharedMemory = interface
73 ['{db77bdd4-233a-4c9c-9212-dd7945e2e57c}']
74 function IsInitialiser: boolean;
75 function Allocate(Size: integer): PByte;
76 function GetLastAllocationSize: integer;
77 property LastAllocationSize: integer read GetLastAllocationSize;
78 end;
79
80 TSharedMemory = class(TIpcCommon,ISharedMemory)
81 private
82 FSharedMemoryID: cint;
83 FBuffer: PByte;
84 FLastAllocationSize: integer;
85 FUnused: integer;
86 FBufptr: PByte;
87 FIPCFileName: AnsiString;
88 FInitialiser: boolean;
89 procedure DropSharedMemory;
90 procedure GetSharedMemory(MemSize: integer);
91 public
92 constructor Create(MemSize: integer);
93 destructor Destroy; override;
94 function Allocate(Size: integer): PByte;
95 function GetLastAllocationSize: integer;
96 function IsInitialiser: boolean;
97 property LastAllocationSize: integer read GetLastAllocationSize;
98 end;
99
100 {TMutex}
101
102 TMutex = class(TIpcCommon,IMutex)
103 private
104 FMutexSemaphore: cint;
105 FLockCount: integer;
106 public
107 constructor Create(SemNumber: cint; IsInitialiser: boolean);
108 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 TSingleLockGate = class(TIpcCommon,ISingleLockGate)
144 private
145 FSharedMemory: ISharedMemory;
146 FSemaphore: cint;
147 FMutex: cint;
148 FSignalledState: PInteger;
149 FWaitingThreads: PInteger;
150 function GetWaitingThreads: integer;
151 public
152 constructor Create(SemNum: cint; sm: ISharedMemory);
153 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 TMultilockGate = class(TIpcCommon,IMultiLockGate)
197 private
198 FSharedMemory: ISharedMemory;
199 FOnGateTimeout: TNotifyEvent;
200 FSemaphore: cint;
201 FMutex: cint;
202 FLockCount: PInteger;
203 function GetLockCount: integer;
204 public
205 constructor Create(SemNum: cint; sm: ISharedMemory);
206 procedure Lock;
207 procedure Unlock;
208 procedure PassthroughGate;
209 function GetOnGateTimeout: TNotifyEvent;
210 procedure SetOnGateTimeout(AValue: TNotifyEvent);
211 property LockCount: integer read GetLockCount;
212 property OnGateTimeout: TNotifyEvent read GetOnGateTimeout write SetOnGateTimeout;
213 end;
214
215 { TIPCInterface }
216
217 TIPCInterface = class(TIpcCommon,IIPCInterface)
218 private
219 FMaxBufferSize: integer;
220 FSharedMemory: ISharedMemory;
221 FWriteLock: IMutex;
222 FBuffer: PByte;
223 FTraceDataType,
224 FBufferSize: PInteger;
225 FTimeStamp: PDateTime;
226 FMsgNumber: PInteger;
227 FReadReadyEvent: IMultiLockGate;
228 FReadFinishedEvent: IMultiLockGate;
229 FDataAvailableEvent: ISingleLockGate;
230 FWriterBusyEvent: ISingleLockGate;
231 public
232 constructor Create;
233 procedure IncMonitorCount;
234 procedure DecMonitorCount;
235 procedure SendTrace(TraceObject: TTraceObject);
236 procedure ReceiveTrace(TraceObject: TTraceObject);
237 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 property MonitorCount: integer read GetMonitorCount;
250 property MaxBufferSize: integer read GetMaxBufferSize;
251 end;
252
253 { TSharedMemory }
254
255 procedure TSharedMemory.GetSharedMemory(MemSize: integer);
256 var F: cint;
257 begin
258 if GetEnvironmentVariable('FBSQL_IPCFILENAME') <> '' then
259 FIPCFileName := GetEnvironmentVariable('FBSQL_IPCFILENAME')
260 else
261 FIPCFileName := GetTempDir(true) + IPCFileName + '.' + GetEnvironmentVariable('USER');
262
263 {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 F := fpOpen(FIPCFileName, O_WrOnly or O_Creat or O_Excl);
268 if F < 0 then
269 begin
270 if fpgetErrno = ESysEEXIST {EEXIST} then
271 begin
272 { looks like it already exists}
273 Sleep(100);
274 F := fpOpen(FIPCFileName,O_RdOnly);
275 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 DeleteFile(FIPCFileName);
331 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 function TSharedMemory.Allocate(Size: integer): PByte;
354 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 function TSharedMemory.GetLastAllocationSize: integer;
373 begin
374 Result := FLastAllocationSize;
375 end;
376
377 function TSharedMemory.IsInitialiser: boolean;
378 begin
379 Result := FInitialiser;
380 end;
381
382 { 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 {$IF declared(semtimedop)}
409 Result := semtimedop(FSemaphoreSetID,@sembuf,1,@timeout);
410 {$ELSE}
411 Result := semop(FSemaphoreSetID,@sembuf,1); {May hang on race condition}
412 {$IFEND}
413 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 constructor TMutex.Create(SemNumber: cint; IsInitialiser: boolean);
437 begin
438 inherited Create;
439 FMutexSemaphore := SemNumber;
440 if IsInitialiser then
441 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 constructor TSingleLockGate.Create(SemNum: cint; sm: ISharedMemory);
475 begin
476 inherited Create;
477 FSharedMemory := sm;
478 FSignalledState := PInteger(FSharedMemory.Allocate(sizeof(FSignalledState)));
479 FWaitingThreads := PInteger(FSharedMemory.Allocate(sizeof(FWaitingThreads)));
480 FSemaphore := SemNum;
481 FMutex := SemNum + 1;
482 if FSharedMemory.IsInitialiser then
483 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 {$IFDEF DEBUG}writeln(ClassName + ': Unlocking' ,FSemaphore);{$ENDIF}
511 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 {$IFDEF DEBUG}writeln(ClassName + ': Locking Gate ',FSemaphore);{$ENDIF}
522 SemInit(FSemaphore,0);
523 FSignalledState^ := 0;
524 end;
525 end;
526
527 { TMultilockGate }
528
529 constructor TMultilockGate.Create(SemNum: cint; sm: ISharedMemory);
530 begin
531 inherited Create;
532 FSemaphore := SemNum;
533 FMutex := SemNum + 1;
534 FSharedMemory := sm;
535 FLockCount := PInteger(FSharedMemory.Allocate(sizeof(FLockCount)));
536 if FSharedMemory.IsInitialiser then
537 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 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 procedure TMultilockGate.Lock;
560 begin
561 sem_op(FMutex,-1,0); //Acquire Mutex
562 if FLockCount^ = 0 then
563 begin
564 {$IFDEF DEBUG}writeln(ClassName,': Locking ',FSemaphore);{$ENDIF}
565 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 {$IFDEF DEBUG}writeln(ClassName,': UnLocking ',FSemaphore);{$ENDIF}
578 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 {$IFDEF DEBUG}writeln(ClassName,': Waiting on ',FSemaphore);{$ENDIF}
589 while sem_timedop(FSemaphore,-1,cDefaultTimeout) < 0 do
590 {looks like we lost a reader}
591 begin
592 {$IFDEF DEBUG}writeln(ClassName,': reader lost timeout');{$ENDIF}
593 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 {$IFDEF DEBUG}writeln(ClassName,': Wait done on ',FSemaphore);{$ENDIF}
602 end;
603
604
605 { TIPCInterface }
606
607 function TIPCInterface.GetMonitorCount: integer;
608 begin
609 Result := GetSemValue(cMonitorCounter)
610 end;
611
612 function TIPCInterface.GetMaxBufferSize: integer;
613 begin
614 Result := FMaxBufferSize;
615 end;
616
617 constructor TIPCInterface.Create;
618 begin
619 inherited Create;
620 FSharedMemory := TSharedMemory.Create(cMonitorHookSize);
621
622 FWriteLock := TMutex.Create(cMutexSemaphore,FSharedMemory.IsInitialiser);
623
624 FDataAvailableEvent := TSingleLockGate.Create(cDataAvailableEventSemaphore,FSharedMemory);
625 FWriterBusyEvent := TSingleLockGate.Create(cWriterBusyEventSemaphore,FSharedMemory);
626 FReadReadyEvent := TMultiLockGate.Create(cReadReadyEventSemaphore,FSharedMemory);
627 FReadFinishedEvent := TMultiLockGate.Create(cReadFinishedEventSemaphore,FSharedMemory);
628
629 if FSharedMemory.IsInitialiser then
630 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 FMsgNumber := PInteger(FSharedMemory.Allocate(sizeof(Integer)));
635 FBuffer := FSharedMemory.Allocate(0); //All remaining
636 FMaxBufferSize := FSharedMemory.LastAllocationSize;
637
638 if FSharedMemory.IsInitialiser then
639 begin
640 FBufferSize^ := 0;
641 FDataAvailableEvent.Lock;
642 FMsgNumber^ := 0;
643 end;
644 end;
645
646 procedure TIPCInterface.IncMonitorCount;
647 begin
648 sem_op(cMonitorCounter,1);
649 end;
650
651 procedure TIPCInterface.DecMonitorCount;
652 begin
653 sem_op(cMonitorCounter,-1,IPC_NOWAIT);
654 end;
655
656 procedure TIPCInterface.SendTrace(TraceObject: TTraceObject);
657 begin
658 FTraceDataType^ := Integer(TraceObject.FDataType);
659 FTimeStamp^ := TraceObject.FTimeStamp;
660 if Length(TraceObject.FMsg) > MaxBufferSize then
661 FBufferSize^ := MaxBufferSize
662 else
663 FBufferSize^ := Length(TraceObject.FMsg);
664 FMsgNumber^ := TraceObject.FMsgNumber;
665 Move(TraceObject.FMsg[1], FBuffer^, FBufferSize^);
666 end;
667
668 procedure TIPCInterface.ReceiveTrace(TraceObject: TTraceObject);
669 begin
670 SetString(TraceObject.FMsg, PAnsiChar(FBuffer), FBufferSize^);
671 TraceObject.FDataType := TTraceFlag(FTraceDataType^);
672 TraceObject.FTimeStamp := TDateTime(FTimeStamp^);
673 TraceObject.FMsgNumber := FMsgNumber^;
674 end;
675
676 function TIPCInterface.GetDataAvailableEvent: ISingleLockGate;
677 begin
678 Result := FDataAvailableEvent;
679 end;
680
681 function TIPCInterface.GetWriterBusyEvent: ISingleLockGate;
682 begin
683 Result := FWriterBusyEvent;
684 end;
685
686 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