Lecture 18 Log into Linux. Copy two subdirectories in /home/hwang/cs375/lecture18/ $ cp r /home/hwang/cs375/lecture18/*. Both subdirectories have makefiles. The "sysv" subdirectory has an example/exercise using System V semaphores; the "posix" subdirectory has the same example/exercise using POSIX semaphores. Project 6 has been posted. Due next Thursday. Questions? Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 1
Outline In-class exercise from last class System V IPC overview System V semaphores POSIX semaphores Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 2
In-class Exercise, Last Class Copy and modify pipe_xmpl3.cpp so that the parent reads /etc/passwd and passes all the data to the child via the pipe. The child should read from the pipe and write the data to standard output. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 3
System V IPC Overview Semaphores, message queues, and shared memory are a set of interprocess communication facilities that were introduced in AT&T System V.2 UNIX. They are now common to most modern UNIX systems. The methods allow IPC between unrelated processes. There are many similarities between the three System V IPC methods. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 4
System V IPC Overview When an IPC structure is created (by calling semget( ), msgget( ), or shmget( )) a key must be specified. A key is an integer and is analogous to a filename in a call to open( ). The *get( ) methods associate an integer identifier with each IPC structure. An identifier is analogous to a file descriptor. Keys and identifiers must be unique on the system. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 5
System V IPC Overview There are two ways for a client and server to attach to the same IPC structure. The client and server can agree on a key (put the key in a common header or use ftok( )). Both processes use a *get( ) call to obtain the identifier. The server would typically create the structure. The problem is that it is possible for the key to already be associated with an existing structure. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 6
System V IPC Overview In the other method, the server creates a new structure by using a key value of IPC_PRIVATE in the *get( ) call. This will create a new IPC structure. The IPC identifier must then be passed to other processes with which we wish to communicate. The server could fork a child and pass the identifier to a new program as an argument via exec. The identifier also could be written to file. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 7
System V IPC Overview The three *get( ) functions (semget( ), msgget( ), and shmget( )) all have two similar arguments: a key and an integer flag. They each return an identifier. A new IPC structure is created (normally by the server) if either key is IPC_PRIVATE or key is not associated with an existing IPC structure and the IPC_CREATE bit of flag is specified. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 8
Introduction to Semaphores A semaphore is a protected variable that can be used to synchronize processes or to ensure restricted access to shared resources. To access a shared resource, a process must: 1. Test the corresponding semaphore. 2. If the semaphore is positive, the resource is available and the process decrements the semaphore and uses the resource. 3. If the semaphore is 0, the process sleeps until it is greater than 0. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 9
Introduction to Semphores When the process is done with the resource, it increments the semaphore. A regular variable can not be used as a semaphore, because the test and decrement steps must be performed in a single atomic operation. For this reason, semaphores are implemented inside the kernel. We have described a counting semaphore. A binary semaphore is used to control access to a single unit of a resource. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 10
System V Semaphores System V semaphores are counting semaphores, but we will discuss only their use in binary semaphore applications. The semaphore routines are defined in the <sys/sem.h> header file with related definitions in the <sys/types.h> and <sys/ipc.h> header files. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 11
System V Semaphore Create/acquire a semaphore with semget( ): int semget(key_t key, int nsems, int flags); key is an integer or has the special value IPC_PRIVATE, nsems is the number of semaphores in the set (1 for a single semaphore). semget( ) returns the semaphore identifier. When creating a semaphore, flags is the desired semaphore permissions (e.g., 0600). Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 12
System V Semaphores When accessing an existing semaphore nsems and flags are usually both 0. (To access an existing semaphore created with the IPC_PRIVATE key, we do not use semget( ); we just need the identifier returned by semget( ) when the semaphore is created.) Initialize the semaphore with semctl( ). See sysv/parent.cpp Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 13
System V Semaphores The semctl( ) routine is used to perform a variety of operations on a semaphore (set, delete, change perms, etc): int semctl(int semid, int semnum, int cmd,...); semnum is the semaphore in the set (0 for a single semaphore), cmd can take a number of values (see the man page): semctl(semid, 0, SETVAL, 1); semctl(semid, 0, IPC_RMID); Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 14
System V Semaphores The semop( ) routine is used to acquire and release a semaphore. int semop(int semid, struct sembuf semops[], size_t nops); semid is the identifier, semops is an array of operations, nops is the # of elements in semops[ ] (often 1). struct sembuf is: struct sembuf { ushort sem_num; short sem_op; short sem_flg; }; Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 15
System V Semaphores To acquire a binary semaphore: struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; sem_b.sem_flg = SEM_UNDO; semop(sem_id, &sem_b, 1); This will block if the semaphore is not available. To release the semaphore call semop( ) with sem_b.sem_op equal to +1. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 16
System V Semaphores Here is code to create, initialize, acquire, release, delete a semaphore: semid = semget(ipc_private, 1, 0600); semctl(semid, 0, SETVAL, 1); struct sembuf sop; sop.sem_num = 0; sop.sem_flg = SEM_UNDO; sop.sem_op = 1; // acquire semop(semid, &sop, 1); sop.sem_op = +1; // release semop(semid, &sop, 1); semctl(semid, 0, IPC_RMID); // delete Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 17
POSIX IPC POSIX IPC (semaphores, message queues and shared memory) is simpler and better designed than System V IPC. It is less widely available than System V IPC. Instead of using keys to specify objects, POSIX IPC uses names (strings) instead. You must link with the librt library: g++ o file file.cpp lrt Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 18
POSIX Semaphores POSIX semaphores are defined in header file <semaphore.h> POSIX semaphores are counting semaphores, but can be incremented in steps of one only. Each semaphore object represents only one semaphore and not a set of semaphores. There are two types of POSIX semaphores: named and unnamed. Named semaphores will be discussed first. See posix/parent.cpp Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 19
POSIX Named Semaphores sem_open( ) creates a new semaphore or opens an existing semaphore: sem_t *sem_open(const char *name, int flags); The name should be of the form /somename. If O_CREAT is used in flags then two additional arguments are required: sem_t *sem_open( const char *name, int flags, mode_t perms, unsigned value); perms are permissions. value is initial value. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 20
POSIX Named Semaphores The sem_wait( ) routine is used to acquire (decrement) a semaphore while sem_post( ) releases it: int sem_wait(sem_t *sem); int sem_post(sem_t *sem); sem_wait( ) will block until the semaphore is available. sem_trywait( ) and sem_timedwait( ) routines are also available. sem_getvalue( ) can be used to find the current semaphore value. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 21
POSIX Named Semaphores Use sem_close( ) to close the semaphore: int sem_close(sem_t *sem); sem_unlink( ) will remove a named semaphore. No other sem_open( ) calls will succeed. It is not actually destroyed until all processes have closed the semaphore: int sem_unlink(const char *name); Named semaphores have corresponding file names in the /dev/shm directory and can also be deleted using rm. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 22
POSIX Unnamed Semaphores Instead of using sem_open( ) to create a semaphore you can create one directly: sem_t sem; // method 1 sem_t *sem = malloc(sizeof(sem_t)); // method 2 sem_t *sem = new sem_t; // method 3 This is known as an unnamed semaphore. It must be initialized using sem_init( ): int sem_init(sem_t *sem, int pshared, unsigned value); Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 23
POSIX Unnamed Semaphores If pshared is 0 the semaphore is to be shared between threads and must be a global variable or allocated on the heap (method 2 or 3). If pshared is nonzero the semaphore is to be shared between processes and must be allocated in a shared memory region. value is the desired initial value of the semaphore. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 24
POSIX Unnamed Semaphores An unnamed semaphore is destroyed using sem_destroy( ): int sem_destroy(sem_t *sem); The routines sem_open( ), sem_close( ) and sem_unlink( ) are not used with unnamed semaphores. sem_wait( ) and sem_post( ) are used to acquire an unnamed semaphore. Access to unnamed semaphores is faster than to named semaphores. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 25
In-class Exercise Examine the example programs. We want to guarantee exclusive access to a function foo( ) (defined in foo.cpp). There are two versions of this exercise: one using System V semaphores and one using named POSIX semaphores. Make and run the example programs. (Just run parent, it execs the child.) For both versions, the parent acquires a semaphore before calling foo( ) and then releases it; the child does not. Fix the child. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 26
In-class Exercise Delete any System V semaphores created using the ipcrm utility. (Use ipcs to see a list.) Delete any POSIX semaphores created by deleting the corresponding file in /dev/shm. Modify the parent (in both versions) so that it deletes the semaphore before it exits when it is interrupted with SIGINT (CTRL-C). Hint: use a signal handler. Thursday, October 28 CS 375 UNIX System Programming - Lecture 18 27