ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/sv5ipc.inc
Revision: 319
Committed: Thu Feb 25 12:05:40 2021 UTC (3 years, 1 month ago) by tony
File size: 21116 byte(s)
Log Message:
Merge into public release

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