Interprocess Communication ● ● Originally multiple approaches Today – more standard – some differences between distributions still exist Pipes ● Oldest form of IPC – provided by all distros ● Limitations ● – Historically half-duplex (data moves in only 1 direction) – Can only be used between processes that have a common ancester – Normally created by parent – parent forks child – used between parent & child Most commonly used form of IPC Pipes ● ● Sequence of commands in a pipeline for shell to execute – Shell creates a separate process for each command – Links standard output of one process to standard input of next process using a pipe int pipe (int fd[2]); – 2 file descriptors are returned through fd argument ● ● fd[0] – open for reading fd[1] – open for writing Pipes Pipes ● fstat function – returns file type of pipe (FIFO) ● Can test for a pipe with S_ISFIFO macro Pipes For a pipe from child to parent, parent closes fd[1] & child closes fd[0] Pipes ● ● When 1 end of the pipe is closed – If read is done from a pipe whose write end has been closed – read returns a 0 – If write is done to a pipe whose read end has been closed, signal SIGPIPE is generate PIPE_BUF – specifies pipe buffer size Pipes ● Can use 2 pipes for parent/child synchronization popen & pclose functions ● ● ● ● FILE* popen (const char* cmdsring, const char* type); int pclose (FILE* f); Functions in stdio that open & close pipes – handle all the details (fork, exec, …) Pclose – closes standard I/O stream – waits for command to terminate – returns termination status to shell FIFOs ● ● Named pipes Unnamed pipes – can only be used between related processes with a common ancestor creating the pipe ● FIFOs – unrelated processes can exchange data ● int mkfifo (const char* path, mode_t mode); ● int mkfifoat (int fd, const char* path, mode_t, mode); ● Similar to creating a file ● After fifo has been created, open function to open it ● Normal file I/O functions used with FIFOs FIFOs ● Nonblocking flag (O_NONBLOCK) – Not used when opening ● ● – Used when opening ● ● ● Open for read-only blocks until a different process opens FIFO for writing Open for write-only blocks until a different process opens FIFO for reading Open for read-only returns immediately Open for write-only returns -1 & sets error flat if no process has the FIFO open for reading Write to FIFO that has no process open for reading – SIGPIPE is generated FIFOs ● Common to have multiple writers for a FIFO – ● Have to worry about atomic writes Uses for FIFOS – Shell commands to pass data from one shell pipeline to another – Rendezvous points in client-server applications Using FIFOs to Duplicate Output Streams ● ● FIFOs cannot be used for nonlinear connections since they have names Tee – copies standard input to both standard output & file named on command line mkfifo fifo1 prog3 < fifo1 & prog1 < infile | tee fifo1 | prog2 Client-Server Communication using a FIFO ● ● Each client can write its request to a known FIFO for the server Requests need to be < PIPE_BUF bytes Client-Server Communication using a FIFO ● ● ● Problem – how to send responses back to client Cannot use a single FIFO – clients would not know when to get response One possibility – send process id with request – server create a FIFO for each client – Server cannot tell whether client crashes XSI IPC ● ● ● IPC structures – Message queues – Semaphores – Shared memory segment Each IPC structure – has non-negative integer identifier – internal name for IPC object Cooperating processes need an external naming scheme to be able to access each other – Each IPC object has a key – acts as external name XSI IPC ● Client server rendezvous techniques – Server can create a new IPC structure by specifying a key of IPC_PRIVATE – store ● ● – Client & server – agree on a key by defining the key in a common header ● ● – IPC_PRIVATE – guarantees new IPC structure is created Disadvantage – file system operations are required for server to write integer identifier to a file & for clients to retrieve this identifier Server creates IPC structure specifying this key Potential problem – possible for key to already be associated with an IPC structure Client & server – agree on a pathname & project ID – call ftok to convert these values to a key Permission Structure ● ipc_perm structure associated with each IPC structure struct ipc_perm { uid_t uid; /* owner's effective user id */ gid_t gid; /* owner's effice group id */ uid_t cuid; /* creator's effective user id */ git_t cgid; /* creator's effective group id */ mode_t mode; /* access modes */ ... } ● ● Each implementation has additional members Fields initialized when IPC structure is created Advantages & Disadvantages ● IPC structures are systemwide & do not have reference count – ● Remain in system until explicitly deleted IPC structures not known by names in file system – Cannot access them using file operations Message Queues ● Linked list of messages stored with kernel ● Identified by message queue identifier (queue ID) ● Created by msgget function ● Messages added at end by msgsnd function ● Messages fetched by msgrcv function – ● Can fetch messages by type instead of FIFO Message consists of – Positive long integer type field – Non-negative length – Actual data System Limits Message Queues ● ● int msgget (key_t key, int flag); – Open existing queue or create new queue – Queue ID is returned msgctl (int msqid, int cmd, struct msquid_ds *buf); – Performs various operations on a queue – cmd ● ● ● ● IPC_STAT – fetch msqid_ds structure for queue – storing in buf IPC_SET – copy fields from buf to msqid_ds structure IPC_RMID – remove message queue from system – includes any data still on the queue int msgsnd (int msqid, const soid* ptr, size_t nbytes, int flag); – Data placed on message queue – ptr – points to long integer followed by message data Message Queues ● ssize_t msgrcv (int msqid, void* ptr, size_t nbytes, long type, int flag) – Retrieve message from queue – type – specify which message ● ● ● type == 0 – first message type > 0 – first message whose type is argument type type < 0 – first message whose type is lower than argument type – flag – IPC_NOWAIT – operation nonblocking – When operations succeeds – kernel updates msqid_ds structure Semaphores ● Counter used to provide access to shared resource – Test semaphore that controls resource – If value > 0 ● ● – If value = 0 ● ● ● process can use resource Value decremented Process goes to sleep until semaphore value > 0 Returns to first step When process is finished with shared resource – value incremented & processes waiting for resources are awakened Semaphores ● Test of semaphores value & decrementing value – must be atomic – ● Normally implemented in kernel Binary semaphore – controls single resource – value initialized to 1 XSI Semaphores ● More complicated – Not simply a single non-negative value ● – – Set of 1 or more semaphores Creation of semaphore is independent of its initialization Have to worry about a program that terminates without releasing semaphores it has been allocated XSI Semaphores ● ● int semctl (int semid, int semnum, int cmd, …); – Catchall for various semaphore operations – Last argument union of command specific arguments – Optional int semop (int semid, struct sembuf semoparray[], size_t nops); – Atomically performs an array of operations on a semaphore set – semoparray – pointer to an array of semaphore operations – nops – number of operations XSI Semaphores ● ● Operation on each member of the set – specified by sem_op value – Positive – number of resources being returned by the process value of sem_op added to semaphore's value – Negative – want to obtain resources that semaphore controls – Zero – process wants to wait until semaphore's value becomes 0 Semaphore adjustment on exit – If SEM_UNDO flag is set, kernel remembers the resources allocated from that semaphore – When process terminates – kernel makes adjustments to semaphore counts XSI Semaphores ● Methods of handling shared resources – Semaphores – Record locking – mutex Shared Memory ● ● ● ● Allows 2 or more processes to share a region of memory Fastest form of IPC – data does not need to be copied Need to synchronize access XSI shared memory – anonymous memory segments Shared Memory ● int shmget (key_t key, size_t size, int flag); – ● Obtain a shared memory identifier int shmctl (int shmid, int cmd, struct shmid_ds *buf); – Catchall for various shared memory operations – cmd ● ● ● ● ● IPC_STAT – fetch shmid_ds structure for segment & store it in buf IPT_SET – set 3 fields in structure pointed to by buf IPC_RMID – remove shared memory segment from system SHM_LOCK – lock shared memory segment in memory SHM_UNLOCK – unlock shared memory segment in memory Shared Memory ● void* shmat (int shmid, const void* addr, int flag); – Process attaches to shared memory segment to its address space ● ● ● Addr == 0 – segment is attached to first available address selected by kernel addr != 0 & SHM_RND not specified – segment is attached at address given by addr addr != 0 & SHM_RND is specified – segment is attached at address given by (addr – (addr modulus SHMLBA)) – SHMBLA – low boundary address multiple – power of 2 – for portability – should not specify address – instead put 0 & let system choose address – Address is returned Shared Memory ● int shmdt (const void* addr); ● Detaches memory segment Shared Memory ● ● /dev/zero – Provides unbounded supply of null characters – Writing to it has no effect Memory mapping of /dev/zero – Unnamed memory region created whose size is the second argument to mmap rounded to nearest page size – Memory region is initialized to 0 – Multiple processes can share this region if a common ancestor specifies th MAP_SHARED flag to mmap POSIX Semaphores ● ● Address several deficiencies with XSI semaphores – Higher performance implementations – Simpler to use – Behave better when removed Named & unnamed versions – Differ in how they are created & destroyed – Unnamed can only be used by threads in the same process POSIX Semaphores ● sem_t sem_open (const char* name, int oflag, …, unsigned int value); – ● Only first 2 arguments unless creating a semaphore – then need 2 more (mode & initial value) Portability naming requirements – First character should be '/' – No other characters should be '/' – Max length – implementation defined POSIX Semaphores ● int sem_close (sem_t* sem); – ● Kernel will close open semaphores if this method is not called int sem_unlink (const char* name); – Destroys a semaphore – deferred until last open reference is closed ● int sem_trywait (sem_t* sem); ● int sem_wait (sem_t* sem); ● int sem_timedwait (sem_t* restrict sem, const struct timespec* restrict tsprt); – Decrements value of semaphore – sem_wait blocks but sem_trywait does not – sem_timedwait – block for a specified amount of time POSIX Semaphores ● int sem_post (sem_t* sem); – ● ● int sem_init (sem_t* sem, int pshared, unsigned int value); – Creates unnamed semaphore – pshared – whether semaphore is to be used with multiple processes Int sem_destroy (sem_t* sem); – ● Increments value Destroys unnamed semaphore Int sem_getvalue (sem_t* restrict sem, int* restrict valp); – Retrieves value of semaphore – valp – Need to use synchronization POSIX Semaphores