Advanced Operating Systems practical 3
Title: Pipes and signals
Author: Craig Duffy
Module: Advanced Operating Systems
Awards: CRTS 4, BSc Computing (part-time)
Prerequisites: C and UNIX
This worksheet deals with simple interprocess communication using pipes and signals.
One feature of the UNIX fork command call is the ability of the child process to inherit open file descriptors from its parent. This combined with the pipe system call allows UNIX to do some simple interprocess communication. The pipe call is used as follows. It requires an array of two integers to hold the two file descriptors. The following declaration shows how it is used.
int pfd; /* 2 pipe file descriptors */
if ( pipe(pfd) == -1 )
manipulate file descriptors
fork news processes
The pipe file descriptors act just like any other file descriptor, and can beused as arguments to read, write. They cannot be used with the lseek call!
Once the pipe has been created it is possible to use the dup and lose calls to force newly created processes to read and write to the pipe, rather than standard input and standard output. The code
will stop the file descriptor stdout being associated with the terminal, then the dup call will duplicate the pipe writing descriptor, so any write to stdout will now go to the pipe. As dup uses the low numbered available descriptor we now that we will get the recently closed stdout slot. The pipe file descriptor is closed to make sure that the user file table is not cluttered by useless file descriptors.
After this, any process that is forked by this process will be able to write to any other process that is connected to the pipe.
1) Write a simple program that creates a pipe forks two processes and then sends data through the pipe. Use two standard programs such as who and wc.
2) Write a program that fork two programs. These should have two way communication through two pipes. These programs should then create some sub-processes, using fork. Get each process to send through the pipe the pids of their sub process. Then get the receiving process to kill off those processes. The two controlling processes should then send back confirmation that the kill has happened.
The UNIX system has a set of asynchronous messages that can be sent to processes. The signals can be generated by the hardware, the kernel, the user or user processes. The list of signals for SUNOS is
SIGHUP 1 hangup
SIGINT 2 interrupt
SIGQUIT 3* quit
SIGILL 4* illegal instruction
SIGTRAP 5* trace trap
SIGABRT 6* abort (generated by abort(3) routine)
SIGEMT 7* emulator trap
SIGFPE 8* arithmetic exception
SIGKILL 9 kill (cannot be caught, blocked, or ignored)
SIGBUS 10* bus error
SIGSEGV 11* segmentation violation
SIGSYS 12* bad argument to system call
SIGPIPE 13 write on a pipe or other socket with no one to read it
SIGALRM 14 alarm clock
SIGTERM 15 software termination signal
SIGURG 16@ urgent condition present on socket
SIGSTOP 17|+ stop (cannot be caught, blocked, or ignored)
SIGTSTP 18|+ stop signal generated from keyboard
SIGCONT 19@ continue after stop
SIGCHLD 20@ child status has changed
SIGTTIN 21|+ background read attempted from control terminal
SIGTTOU 22|+ background write attempted to control terminal
SIGIO 23@ I/O is possible on a descriptor (see fcntl(2V))
SIGXCPU 24 cpu time limit exceeded (see getrlimit(2))
SIGXFSZ 25 file size limit exceeded (see getrlimit(2))
SIGVTALRM 26 virtual time alarm (see getitimer(2))
SIGPROF 27 profiling timer alarm (see getitimer(2))
SIGWINCH 28@ window changed (see termio(4) and win(4S))
SIGLOST 29* resource lost (see lockd(8C))
SIGUSR1 30 user-defined signal 1
SIGUSR2 31 user-defined signal 2
The starred signals in the list above cause a core image if not caught or ignored.
Each signal has a default action that the kernel will take. It is possible to modify the signal handler routine by the use of the signal system call. This allows your code to provide a handling routine, ignore the signal or restore the default action. To install a handler for the terminal interrupt key, SIGINT, you could use the code
my_handler is the name of a user supplied routine that returns a void, oldsignal should be a pointer that will hold the address of the last installed handler routine. It is possible to restore the default action using
Many signals are generated outside the control of user processes; hardware errors, kernel signals, etc. However it is possible for processes and users to generate signal. The latter can do it using keystrokes, ^C, ^\. Processes can generate signals using the kill system call. This is called
where pid is the process id of a child process and sig is the signal as defined in signal.h.
3) Write a simple piece of code that installs a handler for the SIG_INT signal and makes the user type it twice before aborting. Also use the sigblock(2) call to block the SIG_QUIT call. Explain how sigblock and setsigmask work.
4) Write a program which stops the command rusers requiring ^c to
terminate. This will require you to fork and exec rusers from a parent process, grab its output in a pipe and set an alarm signal going. The alarm will then terminate rusers and allow the parent to grab its output.
5) The signals library is an interface into the sigvec system call. Explain the use of sv_flags options - especially the SV_RESETHAND mask. Why does the system give the ability to have a separate signal stack? Write some code that sets up a user supplied signal stack.
Craig Duffy Page of 26-Apr-16