The chapter is divided in 2 sections:
Var IPCerror : longint;The IPCerror variable is used to report errors, by all calls.
Const IPC_CREAT = 1 shl 9; { create if key is nonexistent } IPC_EXCL = 2 shl 9; { fail if key exists } IPC_NOWAIT = 4 shl 9; { return error on wait }These constants are used in the various xxxget calls.
IPC_RMID = 0; { remove resource } IPC_SET = 1; { set ipc_perm options } IPC_STAT = 2; { get ipc_perm options } IPC_INFO = 3; { see ipcs }These constants can be passed to the various xxxctl calls.
const MSG_NOERROR = 1 shl 12; MSG_EXCEPT = 2 shl 12; MSGMNI = 128; MSGMAX = 4056; MSGMNB = 16384;These constants are used in the messaging system, they are not for use by the programmer.
const SEM_UNDO = $1000; GETPID = 11; GETVAL = 12; GETALL = 13; GETNCNT = 14; GETZCNT = 15; SETVAL = 16; SETALL = 17;These constants call be specified in the semop call.
SEMMNI = 128; SEMMSL = 32; SEMMNS = (SEMMNI * SEMMSL); SEMOPM = 32; SEMVMX = 32767;These constanst are used internally by the semaphore system, they should not be used by the programmer.
const SHM_R = 4 shl 6; SHM_W = 2 shl 6; SHM_RDONLY = 1 shl 12; SHM_RND = 2 shl 12; SHM_REMAP = 4 shl 12; SHM_LOCK = 11; SHM_UNLOCK = 12;These constants are used in the shmctl call.
Type PULong = ^Cardinal; PWord = ^Word;
Type TKey = Longint;TKey is the type returned by the ftok key generating function.
type PIPC_Perm = ^TIPC_Perm; TIPC_Perm = record key : TKey; uid, gid, cuid, cgid, mode, seq : Word; end;The TIPC_Perm structure is used in all IPC systems to specify the permissions.
Type PSHMid_DS = ^TSHMid_ds; TSHMid_ds = record shm_perm : TIPC_Perm; shm_segsz : longint; shm_atime : longint; shm_dtime : longint; shm_ctime : longint; shm_cpid : word; shm_lpid : word; shm_nattch : integer; shm_npages : word; shm_pages : Pointer; attaches : pointer; end;The TSHMid_ds strucure is used in the shmctl call to set or retrieve settings concerning shared memory.
type PSHMinfo = ^TSHMinfo; TSHMinfo = record shmmax : longint; shmmin : longint; shmmni : longint; shmseg : longint; shmall : longint; end;The TSHMinfo record is used by the shared memory system, and should not be accessed by the programer directly.
type PMSG = ^TMSG; TMSG = record msg_next : PMSG; msg_type : Longint; msg_spot : PChar; msg_stime : Longint; msg_ts : Integer; end;The TMSG record is used in the handling of message queues. There should be few cases where the programmer needs to access this data.
type PMSQid_ds = ^TMSQid_ds; TMSQid_ds = record msg_perm : TIPC_perm; msg_first : PMsg; msg_last : PMsg; msg_stime : Longint; msg_rtime : Longint; msg_ctime : Longint; wwait : Pointer; rwait : pointer; msg_cbytes : word; msg_qnum : word; msg_qbytes : word; msg_lspid : word; msg_lrpid : word; end;The TMSQid_ds record is returned by the msgctl call, and contains all data about a message queue.
PMSGbuf = ^TMSGbuf; TMSGbuf = record mtype : longint; mtext : array[0..0] of char; end;The TMSGbuf record is a record containing the data of a record. you should never use this record directly, instead you should make your own record that follows the structure of the TMSGbuf record, but that has a size that is big enough to accomodate your messages. The mtype field should always be present, and should always be filled.
Type PMSGinfo = ^TMSGinfo; TMSGinfo = record msgpool : Longint; msgmap : Longint; msgmax : Longint; msgmnb : Longint; msgmni : Longint; msgssz : Longint; msgtql : Longint; msgseg : Word; end;The TMSGinfo record is used internally by the message queue system, and should not be used by the programmer directly.
Type PSEMid_ds = ^PSEMid_ds; TSEMid_ds = record sem_perm : tipc_perm; sem_otime : longint; sem_ctime : longint; sem_base : pointer; sem_pending : pointer; sem_pending_last : pointer; undo : pointer; sem_nsems : word; end;The TSEMid_ds structure is returned by the semctl call, and contains all data concerning a semahore.
Type PSEMbuf = ^TSEMbuf; TSEMbuf = record sem_num : word; sem_op : integer; sem_flg : integer; end;The TSEMbuf record us use in the semop call, and is used to specify which operations you want to do.
Type PSEMinfo = ^TSEMinfo; TSEMinfo = record semmap : longint; semmni : longint; semmns : longint; semmnu : longint; semmsl : longint; semopm : longint; semume : longint; semusz : longint; semvmx : longint; semaem : longint; end;The TSEMinfo record is used internally by the semaphore system, and should not be used directly.
Type PSEMun = ^TSEMun; TSEMun = record case longint of 0 : ( val : longint ); 1 : ( buf : PSEMid_ds ); 2 : ( arr : PWord ); 3 : ( padbuf : PSeminfo ); 4 : ( padpad : pointer ); end;The TSEMun variant record (actually a C union) is used in the semctl call.
Path is the name of a file in the file system, ID is a character of your choice. The ftok call does the same as it's C couterpart, so a pascal program and a C program will access the same resource if they use the same Path and ID
For an example, see msgctl, semctl, shmctl.
msgflg can have one or more of the following values (combined by ORs):
For an example, see msgctl.
The msgflg can have a combination of the following values (ORed together):
The function returns True if the message was sent successfully, False otherwise.
For an example, see msgctl.
The msgflg parameter can be used to control the behaviour of the msgrcv call. It consists of an ORed combination of the following flags:
The function returns True if the message was received correctly, False otherwise.
For an example, see msgctl.
buf contains the data that are needed by the call. It can be Nil in case the message queue should be removed.
The function returns True if successfull, False otherwise.
program msgtool; Uses ipc; Type PMyMsgBuf = ^TMyMsgBuf; TMyMsgBuf = record mtype : Longint; mtext : string[255]; end; Procedure DoError (Const Msg : string); begin Writeln (msg,'returned an error : ',ipcerror); halt(1); end; Procedure SendMessage (Id : Longint; Var Buf : TMyMsgBuf; MType : Longint; Const MText : String); begin Writeln ('Sending message.'); Buf.mtype:=mtype; Buf.Mtext:=mtext; If not msgsnd(Id,PMsgBuf(@Buf),256,0) then DoError('msgsnd'); end; Procedure ReadMessage (ID : Longint; Var Buf : TMyMsgBuf; MType : longint); begin Writeln ('Reading message.'); Buf.MType:=MType; If msgrcv(ID,PMSGBuf(@Buf),256,mtype,0) then Writeln ('Type : ',buf.mtype,' Text : ',buf.mtext) else DoError ('msgrcv'); end; Procedure RemoveQueue ( ID : Longint); begin If msgctl (id,IPC_RMID,Nil) then Writeln ('Removed Queue with id',Id); end; Procedure ChangeQueueMode (ID,mode : longint); Var QueueDS : TMSQid_ds; begin If Not msgctl (Id,IPC_STAT,@QueueDS) then DoError ('msgctl : stat'); Writeln ('Old permissions : ',QueueDS.msg_perm.mode); QueueDS.msg_perm.mode:=Mode; if msgctl (ID,IPC_SET,@QueueDS) then Writeln ('New permissions : ',QueueDS.msg_perm.mode) else DoError ('msgctl : IPC_SET'); end; procedure usage; begin Writeln ('Usage : msgtool s(end) <type> <text> (max 255 characters)'); Writeln (' r(eceive) <type>'); Writeln (' d(elete)'); Writeln (' m(ode) <decimal mode>'); halt(1); end; Function StrToInt (S : String): longint; Var M : longint; C : Integer; begin val (S,M,C); If C<>0 Then DoError ('StrToInt : '+S); StrToInt:=M; end; Var Key : TKey; ID : longint; Buf : TMyMsgBuf; begin If Paramcount<1 then Usage; key :=Ftok('.','M'); ID:=msgget(key,IPC_CREAT or 438); If ID<0 then DoError ('MsgGet'); Case upCase(Paramstr(1)[1]) of 'S' : If ParamCount<>3 then Usage else SendMessage (id,Buf,StrToInt(Paramstr(2)),paramstr(3)); 'R' : If ParamCount<>2 then Usage else ReadMessage (id,buf,strtoint(Paramstr(2))); 'D' : If ParamCount<>1 then Usage else RemoveQueue (ID); 'M' : If ParamCount<>2 then Usage else ChangeQueueMode (id,strtoint(paramstr(2))); else Usage end; end.
semflg can have one or more of the following values (combined by ORs):
if a new set of semaphores is created, then there will be nsems semaphores in it.
The fields of the TSEMbuf structure
TSEMbuf = record sem_num : word; sem_op : integer; sem_flg : integer;
should be filled as follows:
The function returns True if the operations were successful, False otherwise.
The arg parameter supplies the data needed for each call. This is a variant record that should be filled differently, according to the command:
Type TSEMun = record case longint of 0 : ( val : longint ); 1 : ( buf : PSEMid_ds ); 2 : ( arr : PWord ); 3 : ( padbuf : PSeminfo ); 4 : ( padpad : pointer ); end;
Which operation is performed, depends on the cmd parameter, which can have one of the following values:
The function returns -1 on error.
Program semtool; { Program to demonstrat the use of semaphores } Uses ipc; Const MaxSemValue = 5; Procedure DoError (Const Msg : String); begin Writeln ('Error : ',msg,' Code : ',IPCerror); Halt(1); end; Function getsemval (ID,Member : longint) : longint; Var S : TSEMun; begin GetSemVal:=SemCtl(id,member,GETVAL,S); end; Procedure DispVal (ID,member : longint); begin writeln ('Value for member ',member,' is ',GetSemVal(ID,Member)); end; Function GetMemberCount (ID : Longint) : longint; Var opts : TSEMun; semds : TSEMid_ds; begin opts.buf:=@semds; If semctl(Id,0,IPC_STAT,opts)<>-1 then GetMemberCount:=semds.sem_nsems else GetMemberCount:=-1; end; Function OpenSem (Key : TKey) : Longint; begin OpenSem:=semget(Key,0,438); If OpenSem=-1 then DoError ('OpenSem'); end; Function CreateSem (Key : TKey; Members : Longint) : Longint; Var Count : Longint; Semopts : TSemun; begin If members>semmsl then DoError ('Sorry, maximum number of semaphores in set exceeded'); Writeln ('Trying to create a new semaphore set with ',members,' members.'); CreateSem:=semget(key,members,IPC_CREAT or IPC_Excl or 438); If CreateSem=-1 then DoError ('Semaphore set already exists.'); Semopts.val:=MaxSemValue; { Initial value of semaphores } For Count:=0 to Members-1 do semctl(CreateSem,count,setval,semopts); end; Procedure lockSem (ID,Member: Longint); Var lock : TSEMbuf; begin With lock do begin sem_num:=0; sem_op:=-1; sem_flg:=IPC_NOWAIT; end; if (member<0) or (member>GetMemberCount(ID)-1) then DoError ('semaphore member out of range'); if getsemval(ID,member)=0 then DoError ('Semaphore resources exhausted (no lock)'); lock.sem_num:=member; Writeln ('Attempting to lock member ',member, ' of semaphore ',ID); if not semop(Id,@lock,1) then DoError ('Lock failed') else Writeln ('Semaphore resources decremented by one'); dispval(ID,Member); end; Procedure UnlockSem (ID,Member: Longint); Var Unlock : TSEMbuf; begin With Unlock do begin sem_num:=0; sem_op:=1; sem_flg:=IPC_NOWAIT; end; if (member<0) or (member>GetMemberCount(ID)-1) then DoError ('semaphore member out of range'); if getsemval(ID,member)=MaxSemValue then DoError ('Semaphore not locked'); Unlock.sem_num:=member; Writeln ('Attempting to unlock member ',member, ' of semaphore ',ID); if not semop(Id,@unlock,1) then DoError ('Unlock failed') else Writeln ('Semaphore resources incremented by one'); dispval(ID,Member); end; Procedure RemoveSem (ID : longint); var S : TSemun; begin If semctl(Id,0,IPC_RMID,s)<>-1 then Writeln ('Semaphore removed') else DoError ('Couldn''t remove semaphore'); end; Procedure ChangeMode (ID,Mode : longint); Var rc : longint; opts : TSEMun; semds : TSEMid_ds; begin opts.buf:=@semds; If not semctl (Id,0,IPC_STAT,opts)<>-1 then DoError ('Couldn''t stat semaphore'); Writeln ('Old permissions were : ',semds.sem_perm.mode); semds.sem_perm.mode:=mode; If semctl(id,0,IPC_SET,opts)<>-1 then Writeln ('Set permissions to ',mode) else DoError ('Couldn''t set permissions'); end; Procedure PrintSem (ID : longint); Var I,cnt : longint; begin cnt:=getmembercount(ID); Writeln ('Semaphore ',ID,' has ',cnt,' Members'); For I:=0 to cnt-1 Do DispVal(id,i); end; Procedure USage; begin Writeln ('Usage : semtool c(reate) <count>'); Writeln (' l(ock) <member>'); Writeln (' u(nlock) <member>'); Writeln (' d(elete)'); Writeln (' m(ode) <mode>'); halt(1); end; Function StrToInt (S : String): longint; Var M : longint; C : Integer; begin val (S,M,C); If C<>0 Then DoError ('StrToInt : '+S); StrToInt:=M; end; Var Key : TKey; ID : Longint; begin If ParamCount<1 then USage; key:=ftok('.','s'); Case UpCase(Paramstr(1)[1]) of 'C' : begin if paramcount<>2 then usage; CreateSem (key,strtoint(paramstr(2))); end; 'L' : begin if paramcount<>2 then usage; ID:=OpenSem (key); LockSem (ID,strtoint(paramstr(2))); end; 'U' : begin if paramcount<>2 then usage; ID:=OpenSem (key); UnLockSem (ID,strtoint(paramstr(2))); end; 'M' : begin if paramcount<>2 then usage; ID:=OpenSem (key); ChangeMode (ID,strtoint(paramstr(2))); end; 'D' : Begin ID:=OpenSem(Key); RemoveSem(Id); end; 'P' : begin ID:=OpenSem(Key); PrintSem(Id); end; else Usage end; end.
flag can have one or more of the following values (combined by ORs):
if a new memory block is created, then it will have size Size semaphores in it.
If shmaddr is Nil, then the system chooses a free unmapped memory region, as high up in memory space as possible.
If shmaddr is non-nil, and SHM_RND is in shmflg, then the returned address is shmaddr, rounded down to SHMLBA. If SHM_RND is not specified, then shmaddr must be a page-aligned address.
The parameter shmflg can be used to control the behaviour of the shmat call. It consists of a ORed combination of the following costants:
For an example, see shmctl.
The function returns True if the memory block was detached successfully, False otherwise.
The buf parameter points to a TSHMid_ds record. The cmd parameter is used to pass which operation is to be performed. It can have one of the following values :
If successful, the function returns True, False otherwise.
Program shmtool; uses ipc,strings; Const SegSize = 100; var key : Tkey; shmid,cntr : longint; segptr : pchar; Procedure USage; begin Writeln ('Usage : shmtool w(rite) text'); writeln (' r(ead)'); writeln (' d(elete)'); writeln (' m(ode change) mode'); halt(1); end; Procedure Writeshm (ID : Longint; ptr : pchar; S : string); begin strpcopy (ptr,s); end; Procedure Readshm(ID : longint; ptr : pchar); begin Writeln ('Read : ',ptr); end; Procedure removeshm (ID : Longint); begin shmctl (ID,IPC_RMID,Nil); writeln ('Shared memory marked for deletion'); end; Procedure CHangeMode (ID : longint; mode : String); Var m : word; code : integer; data : TSHMid_ds; begin val (mode,m,code); if code<>0 then usage; If Not shmctl (shmid,IPC_STAT,@data) then begin writeln ('Error : shmctl :',ipcerror); halt(1); end; writeln ('Old permissions : ',data.shm_perm.mode); data.shm_perm.mode:=m; If Not shmctl (shmid,IPC_SET,@data) then begin writeln ('Error : shmctl :',ipcerror); halt(1); end; writeln ('New permissions : ',data.shm_perm.mode); end; begin if paramcount<1 then usage; key := ftok ('.','S'); shmid := shmget(key,segsize,IPC_CREAT or IPC_EXCL or 438); If shmid=-1 then begin Writeln ('Shared memory exists. Opening as client'); shmid := shmget(key,segsize,0); If shmid = -1 then begin Writeln ('shmget : Error !',ipcerror); halt(1); end end else Writeln ('Creating new shared memory segment.'); segptr:=shmat(shmid,nil,0); if longint(segptr)=-1 then begin Writeln ('Shmat : error !',ipcerror); halt(1); end; case upcase(paramstr(1)[1]) of 'W' : writeshm (shmid,segptr,paramstr(2)); 'R' : readshm (shmid,segptr); 'D' : removeshm(shmid); 'M' : changemode (shmid,paramstr(2)); else begin writeln (paramstr(1)); usage; end; end; end.