COMP2310/COMP6310:
Concurrent and Distributed Systems
Semester 2 2012

Laboratory 9

Signals and UNIX Semaphores


You are expected to use the man pages! Remember that man pages with the same title may appear in multiple sections. If you want to search all sections use man -a.


Signals


A signal is like a message that when delivered to a process may cause it to halt what it is currently doing and execute some alternative set of instructions. We say "may" because a process can elect to ignore certain signals. Each signal is characterized by an integer value, with some values pre-assigned. For instance you may be familiar with the signal used to kill a running process. This signal is known as SIGKILL, has a value of 9, and can be sent to a particular process ID (PID) by issuing the command kill -9 PID. Details of other predefined signals are available from the man pages by typing man 7 signal.

A process may control the effects of signals by installing a signal handler function. In this sense, signals are similar to the traps that you used with PeANUt in COMP2300 (however, signals are not to be confused with traps or interrupts, as they are purely implemented by the software and OS).

In the following code we create two signal handlers. Using the function signal(), we assign these to be executed when our executing process receives either SIGUSR1 or SIGUSR2. We then put our program into an infinite number of 1 second sleeps.

ACTIONS

Frequently students submit programs that compile fine, but fail to terminate properly and end up running forever. Not surprisingly this causes problems when trying to automate the running and testing of their programs. To emulate this behavior the following code uses a random number generator that causes the code to go into an infinite loop ~20% of the times it is executed. ACTIONS

Unix Semaphores


Just to fully convince you that introducing concurrent processing with Java or Ada95 is much easier than using Unix we will now look briefly at using Unix semaphores (or maybe we will look at Unix semaphores because they are important in their own right, especially since they can be shared by completely separate programs).

To obtain a Unix semaphore we use the semget() function:

       int semget(key_t key, int nsems, int semflg);
This returns an identifier that is used to manipulate the semaphore, however rather than obtaining just a single semaphore this function allows the user to allocate an array of nsems semaphores. For this reason, the return value is referred to as the semaphore set id, and therefore to identify a specific semaphore we need to specify both the semaphore set id AND the number of the semaphore within this semaphore set (You should also be aware that there are system dependent limits on the number of semaphores in a semaphore array. E.g. on Linux look in /proc/sys/kernel/sem or /usr/include/linux/sem.h. On Solaris look in /etc/system. You should also consider why such semaphores are allocated in sets, rather than individually).

Of the other parameters of this system call, the first is a key that we will brush over for the moment, while the third is used to determine whether, for example, we want to create a new semaphore set and if so what access permissions to assign it.

Having created a semaphore set it can be manipulated using calls to semctl():

       int semctl(int semid, int semnum, int cmd, ...);
We will use this function to initialize the value of each semaphore. (do man semctl; for more info). While to do the traditional "P" and "V" semaphore operations we use:
       int semop(int semid, struct sembuf *sops, unsigned nsops);
...pretty easy really!!

The following code puts this all together. First it creates a semaphore set with 2 elements. It then initializes the first semaphore within this set a value of 1 while gives the second a value of 0. It then does a double check to verify that these values are set, before forking a second process. Since the semaphore array is created before the call to fork both the parent and the child have access to it. Each process then enters a loop that selectively decrements or increments the first semaphore (ignoring the second semaphore for the time being).

ACTIONS

Next Lab

Shared memory segments and requeue implementations ...... just joking!

If you do want to learn about shared memory, read the man pages for shmget, shmat, shmctl and shmdt, and/or take COMP4300 in the future. If you want to do more Ada take COMP4330, while if you want to learn more computer architecture, build a cluster and run some applications on it do COMP3320 and COMP4340.

PS. it is not just software engineers who write code that runs forever - just mainly software engineers!