System V IPC Provides three mechanisms for InterProcess Communication (IPC) : Messages : exchange messages with any process or server. Semaphores : allow unrelated processes to synchronize execution. Shared memory : allow unrelated processes to share memory. Semaphores - General Used to monitor and control the availability of system resources such as shared memory segments. Can be operated on as individual units or as elements in a set. A semaphore set consists of a control structure and an array of individual semaphores (default 25 elements). Semaphores - Functions The semget() function initializes or gains access to a semaphore. semid = semget (key_t key, int nsems, int semflg); key : value associated with the semaphore ID nsems : number of semaphores in array semflg : IPC_CREAT used to create a new resource IPC_EXCL used with IPC_CREAT to ensure failure if the resource exists. rwxrwxrwx access permissions. returns : semid on success. -1 on failure. Semaphores - Functions The semctl() function allows a process to alter permissions and other characteristics of a semaphore set. int semctl (int semid, int semnum, int cmd, union semun arg); semid : id obtained by a call to semget(). cmd : control flags GETVAL SETVAL etc… returns : 0 on success. -1 on failure. arg is a union : (usually optional) union semun{ int val; struct semid_ds *buf; ushort *array; } Semaphores - Functions The semop() function performs operations on a semaphore set. int semop (int semid, struct sembuf *sops, unsigned nsops); semid : id obtained by a call to semget(). sops : array of semaphore operations. nsops : number of operations in array. Operations are described by a structure sembuf: struct sembuf{ ushort sem_num; short sem_op; short sem_flg; } /* semaphore index in array */ /* semaphore operation */ /* operation flags */. Shared Memory - General An efficient means of passing data between processes. One process will create a memory portion which other processes (if permitted) can access. When write access is allowed for more than one process, an outside protocol or mechanism such as a semaphore can be used to prevent inconsistencies and collisions. Shared Memory - Functions The shmget() function is used to obtain access to a shared memory segment. shmid=shmget(key_t key, int size, int shmflg); key : key value of shared memory size : size of the segment in bytes shmflg : IPC_CREAT used to create a new resource IPC_EXCL used with IPC_CREAT to ensure failure if the resource exists. rwxrwxrwx access permissions. returns : shmid on success. -1 on failure. Shared Memory - Functions The shmctl() is used to alter the permissions and other characteristics of a shared memory segment. int shmctl (int shmid, int cmd, struct shmid_ds *buf); shmid : id got from call to shmget(). cmd :control commands IPC_RMID IPC_SET IPC_STAT etc… buf : used to read (IPC_STAT) or write (IPC_SET) information. returns : 0 on success, -1 on failure. Shared Memory - Functions shmat() and shmdt() functions are used to attach and detach shared memory segments respectively. void *shmat(int shmid, const void *shmaddr, int shmflg); int shmdt(const void *shmaddr); shmat() returns a pointer to the head of the shared segment associated with a valid shmid.( values of shmaddr and shmflg are usually set to 0) shmdt() detaches the shared memory segment located at the address indicated by shmaddr. returns : 0 on success. -1 on failure Shared Memory – Example(1/7) shm_server.c creates the string and shared memory portion. shm_client.c attaches itself to the created shared memory portion and uses the string Shared Memory – Example(2/7) shm_server.c #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #define SHMSZ 27 main(){ char c; int shmid; key_t key; char *shm, *s; /* * We'll name our shared memory segment * "5678". */ key = 5678; Shared Memory – Example(3/7) /* * Create the segment. */ if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) { perror("shmget"); exit(1); } /* * Now we attach the segment to our data space. */ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } /* * Now put some things into the memory for the * other process to read. */ s = shm; Shared Memory – Example(4/7) for (c = 'a'; c <= 'z'; c++) *s++ = c; *s = NULL; /* * Finally, we wait until the other process * changes the first character of our memory * to '*', indicating that it has read what * we put there. */ while (*shm != '*') sleep(1); exit(0); } /*main*/ Shared Memory – Example(5/7) shm_client.c #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #define SHMSZ 27 main(){ int shmid; key_t key; char *shm, *s; /* * We need to get the segment named * "5678", created by the server. */ key = 5678; Shared Memory – Example(6/7) /* * Locate the segment. */ if ((shmid = shmget(key, SHMSZ, 0666)) < 0) { perror("shmget"); exit(1); } /* * Now we attach the segment to our data space. */ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } Shared Memory – Example(7/7) /* * Now read what the server put in the memory. */ for (s = shm; *s != NULL; s++) putchar(*s); putchar('\n'); /* * Finally, change the first character of the * segment to '*', indicating we have read * the segment. */ *shm = '*'; exit(0); } /*main*/ System calls Are functions that used to control user processes fork() exit() wait() The fork() System Call (1) A process calling fork() spawns a child process. The child is almost an identical clone of the parent: Program Stack Data Text #include <sys/types.h> #include <unistd.h> pid_t fork(void); The fork() System Call (2) The fork() is one of the those system calls, which is called once, but returns twice! After fork() both the parent and the child are executing the same program. Consider a piece of program On error, fork() returns -1 (see fork_pid.c example): PID=28 PID=28 PID=34 fork() p1 p1 c1 ... pid_t pid = fork(); printf(“PID: %d\n”, pid); ... The parent will print: PID: 34 And the child will always print: PID: 0 The fork() System Call (3) Remember, after fork() the execution order is not guaranteed. Simple fork() examples: fork_pid.c prints out return from fork() fork_child.c fork_child.c distinguishes between the parent and the child fork_pid.c #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char** argv) { pid_t pid = fork(); printf("PID: %d\n", pid); exit(0); I } /*pid is actually an integer*/ /*Child will print 0, parent an ID specified by the OS*/ /*Βoth terminate right after, not very exciting, know.*/ fork_child.c #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { pid_t pid = fork(); printf("PID: %d\n", pid); if(pid == 0) { /* fork a child */ /* both execute this line */ /* child plays here */ printf("Hello I'm a child!! My PID=%d\n", getpid()); } else { /* parent goes here */ printf("Hi! I'm a parent (my PID=%d) of the child with PID=%d\n", getpid(), pid); } /* both terminate */ printf("Process with PID=%d terminates...\n", getpid()); exit(0); } The exit() System Call #include <stdlib.h> void exit(int status); This call gracefully terminates process execution. Gracefully means it does clean up and release of resources, and puts the process into the zombie state. By calling wait(), the parent cleans up all its zombie children. exit() specifies a return value from the program, which a parent process might want to examine as well as status of the dead process. _exit() call is another possibility of quick death without cleanup. The wait() System Call Forces the parent to suspend execution, i.e. wait for its children or a specific child to die (terminate is more appropriate terminology, but a bit less common). The wait() System Call (2) #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); The wait() causes the parent to wait for any child process. The waitpid() waits for the child with specific PID. The status, if not NULL, stores exit information of the child The return value is: PID of the exited process, if no error (-1) if an error has happened References man 2 fork man 2 wait man 3 exit