You are on page 1of 41

Operating Systems: IPC

Inter-Process Communication : Message Passing


•Processes can communicate through shared areas of memory
–the Mutual Exclusion problem and Critical Sections
•Semaphores - a synchronisation abstraction
•Monitors - a higher level abstraction
•Inter-Process Message Passing much more useful for information transfer
–can also be used just for synchronisation
–can co-exist with shared memory communication
•Two basic operations : send(message) and receive(message)
–message contents can be anything mutually comprehensible
»data, remote procedure calls, executable code etc.
–usually contains standard fields
»destination process ID, sending process ID for any reply
»message length
»data type, data etc.
1
Operating Systems: IPC

•Fixed-length messages:
–simple to implement - can have pool of standard-sized buffers
»low overheads and efficient for small lengths
­
copying overheads if fixed length too long
–can be inconvenient for user processes with variable amount of data to
pass
»may need a sequence of messages to pass all the data
»long messages may be better passed another way e.g. FTP
­
copying probably involved, sometimes multiple copying into kernel and out

•Variable-length messages:
–more difficult to implement - may need a heap with garbage collection
»more overheads and less efficient, memory fragmentation
–more convenient for user processes

2
Operating Systems: IPC

•Communication links between processes


–not concerned with physical implementation e.g. shared memory, processor
bus, network etc.
–rather with issues of its logical implementation
•Issues:
–how are links established?
–can a link be associated with more than two processes?
–how many links can there be between every pair of processes?
–what is the capacity of a link?
»i.e. buffer space and how much
–fixed v. variable length messages
–unidirectional v. bidirectional ?
»can messages flow in one or both directions between two linked processes
»unidirectional if each linked process can either send orreceive but not both
and each link has at least one receiver process connected to it

3
Operating Systems: IPC

•Naming of links - direct and indirect communications


•Direct:
–each process wanting to communicate must explicitly name the recipient
or sender of the communication
–send and receive primitives defined:
send ( P, message ) : send a message to process P
receive ( Q, message ) : receive a message from process Q
–a link established automatically between every pair of processes that want
to communicate
»processes only need to know each other’s identity
–link is associated with exactly two processes
–link is usually bidirectional but can be unidirectional
– Process A Process B
while (TRUE) { while (TRUE) {
produce an item receive ( A, item )
send ( B, item ) consume item
} }
4
Operating Systems: IPC

•Asymmetric addressing:
–only the sender names the recipient
–recipient not required to name the sender - need not know the sender
send ( P, message ) : send message to process P
receive ( id, message ) : receive from any process, id set to sender
•Disadvantage of direct communications :
–limited modularity - changing the name of a process means changing every
sender and receiver process to match
–need to know process names

•Indirect communications :
–messages sent to and received from mailboxes (or ports)
»mailboxes can be viewed as objects into which messages placed by
processes and from which messages can be removed by other processes
–each mailbox has a unique ID
–two processes can communicate only if they have a shared mailbox
5
Operating Systems: IPC

send ( A, message ) : send a message to mailbox A


receive ( A, message ) : receive a message from mailbox A
–a communications link is only established between a pair of processes if they
have a shared mailbox
–a pair of processes can communicate via several different mailboxes if desired
–a link can be either unidirectional or bidirectional
–a link may be associated with more than two processes
»allows one-to-many, many-to-one, many-to-many communications
–one-to-many : any of several processes may receive from the mailbox
»e.g. a broadcast of some sort
»which of the receivers gets the message?
arbitrary
­ choice of the scheduling system if many waiting?
only
­ allow one process at a time to wait on a receive
–many-to-one : many processes sending to one receiving process
»e.g. a server providing service to a collection of processes
»file server, network server, mail server etc.
»receiver can identify the sender from the message header contents

6
Operating Systems: IPC

•many-to-many :
–e.g. multiple senders requesting service and a pool of receiving servers offering
service - a server farm

•Mailbox Ownership
–process mailbox ownership :
»only the process may receive messages from the mailbox
»other processes may send to the mailbox
»mailbox can be created with the process and destroyed when the process dies
­
process sending to a dead process’s mailbox will need to be signalled
»or through separate create_mailbox and destroy_mailbox calls
­
possibly declare variables of type ‘mailbox’
–system mailbox ownership :
»mailboxes have their own independent existence, not attached to any process
»dynamic connection to a mailbox by processes
for­ send and/or receive

7
Operating Systems: IPC

•Buffering - the number of messages that can reside in a link temporarily


–Zero capacity - queue length 0
»sender must wait until receiver ready to take the message
–Bounded capacity - finite length queue
»messages can be queued as long as queue not full
»otherwise sender will have to wait
–Unbounded capacity
»any number of messages can be queued - in virtual space?
»sender never delayed
•Copying
–need to minimise message copying for efficiency
–copy from sending process into kernel message queue space and then into
receiving process?
»probably inevitable in a distributed system
»advantage that communicating processes are kept separate
­
malfunctions localised to each process

8
Operating Systems: IPC

–direct copy from one process to the other?


»from virtual space to virtual space?
»message queues keep indirect pointers to message in process virtual space
»both processes need to be memory resident i.e. not swapped out to disc, at
time of message transfer
–shared virtual memory
»message mapped into virtual space of both sender and receiver processes
»one physical copy of message in memory ever
»no copying involved beyond normal paging mechanisms
»used in MACH operating system
Aside : Mach’s Copy-on-Write mechanism (also used in Linux forks) :
»single copy of shared material mapped into both processes virtual space
»both processes can read the same copy in physical memory
»if either process tries to write, an exception to the kernel occurs
»kernel makes a copy of the material and remaps virtual space of writing process
onto it
»writing process modifies new copy and leaves old copy intact for other process
9
Operating Systems: IPC

•Synchronised versus Asynchronous Communications


•Synchronised:
–send and receive operations blocking
»sender is suspended until receiving process does a corresponding read
»receiver suspended until a message is sent for it to receive
–properties :
»processes tightly synchronised - the rendezvous of Ada
»effective confirmation of receipt for sender
»at most one message can be outstanding for any process pair
no­ buffer space problems
»easy to implement, with low overhead
–disadvantages :
»sending process might want to continue after its send operation without
waiting for confirmation of receipt
»receiving process might want to do something else if no message is waiting
to be received

10
Operating Systems: IPC

•Asynchronous :
–send and receive operations non-blocking
»sender continues when no corresponding receive outstanding
»receiver continues when no message has been sent
–properties :
»messages need to be buffered until they are received
amount
­ of buffer space to allocate can be problematic
­
a process running amok could clog the system with messages if not careful
»often very convenient rather than be forced to wait
­
particularly for senders
»can increase concurrency
»some awkward kernel decisions avoided
e.g.
­ whether to swap a waiting process out to disc or not
–receivers can poll for messages
»i.e. do a test-receive every so often to see if any messages waiting
»interrupt and signal programming more difficult
»preferable alternative perhaps to have a blocking receive in a separate thread
11
Operating Systems: IPC

•Other combinations :
–non-blocking send + blocking receive
»probably the most useful combination
»sending process can send off several successive messages to one or more
processes if need be without being held up
»receivers wait until something to do i.e. take some action on message
receipt
­ a server process
e.g.
might
­ wait on a read until a service request arrived,
­ transfer the execution of the request to a separate thread
then
then
­ go back and wait on the read for the next request
–blocking send + non-blocking receive
»conceivable but probably not a useful combination
–in practice, sending and receiving processes will each choose independently
•Linux file access normally blocking :
–to set a device to non-blocking (already opened with a descriptor fd) :
fcntl ( fd, F_SETFL, fcntl ( fd, F_GETFL) | O_NDELAY )
12
Operating Systems: IPC

•Missing messages ?
–message sent but never received
»receiver crashed?
»receiver no longer trying to read messages?
–waiting receiver never receives a message
»sender crashed?
»no longer sending messages?

•Crashing processes :
–kernel knows when processes crash
–can notify waiting process
»by synthesised message
»by signal
»terminate process

13
Operating Systems: IPC

•Time-outs
–add a time-limit argument to receive
receive ( mailbox, message, time-limit )
–if no message received by time-limit after issuing the receive:
»kernel can generate an artificial synthesised message saying time-out
»could signal receiver process with a program-error
allows
­ receiver to escape from current program context
–sending process can also be protected using a handshake protocol :
–sender :
send (mailbox, message)
receive (ackmail, ackmess, time-limit)
–receiver :
receive (mailbox, message, time-limit)
if ( message received in time ) send (ackmail, ackmess)

14
Operating Systems: IPC

•Lost messages
–particularly relevant in distributed systems
–OS’s need to be resilient i.e. not crash either the kernel or user processes
–options:
»kernel responsible for detecting message loss and resending
­ to buffer message until receipt confirmed
need
can
­ assume unreliability and demand receipt confirmation within a time limit
»sending process responsible for detecting loss
receipt
­ confirmation within time-limit and optional retransmit
»kernel responsible for detecting loss but just notifies sender
sender
­ can retransmit if desired
–long transmission delays can cause problems
»something delayed a message beyond its time limit but still in transit
­
if message retransmitted, multiple messages flying about
­ to identify messages e.g. serial numbers, and discard any duplicates
need
»scrambled message - checksums etc.
»see Communications module!
15
Operating Systems: IPC

•Message Queuing order


–first-come-first served
»the obvious, simple approach
»may not be adequate for some situations
­ a message to a print server from device driver saying printer gone off-line
e.g.
could
­ use signals instead
–a priority system
»some types of message go to head of the queue
e.g.
­ exception messages
–user selection
»allow receiving process to select which message to receive next
­ from a particular process, to complete some comms protocol
e.g.
»to select a message type
­ a request for a particular kind of service (different mailbox better?)
e.g.
»to postpone a message type
an­ inhibit request (implemented in EMAS)
•Authentication
–of sending and receiving processes - signatures, encryption etc.
16
Operating Systems: IPC

Process Synchronisation using Messages


•A mailbox can correspond to a semaphore:
non-blocking send + blocking receive
–equivalent to :
signal (V) by sender + wait (P) by receiver
•Mutual Exclusion :
–initialise :
» create_mailbox (mutex)
send (mutex, null-message)
–for each process :
» while (TRUE) {
receive (mutex, null-message);
critical section
send (mutex, null-messge);
}
–mutual exclusion just depends on whether mailbox is empty or not
»message is just a token, possesion of which gives right to enter C.S.
17
Operating Systems: IPC

•Producer / Consumer problem using messages :


–Binary semaphores : one message token
–General (counting) semaphores : more than one message token
–message blocks used to buffer data items
–scheme uses two mailboxes
»mayproduce and mayconsume

–producer :
»get a message block from mayproduce
»put data item in block
»send message to mayconsume
–consumer :
»get a message from mayconsume
»consume data in block
»return empty message block to mayproduce mailbox

18
Operating Systems: IPC

–parent process creates message slots


»buffering capacity depends on number of slots created
» slot = empty message
capacity = buffering capacity
create_mailbox ( mayproduce );
create_mailbox ( mayconsume );
for (i=0; i<capacity; i++) send (mayproduce, slot);
start producer and consumer processes
–producer :
» while (TRUE) {
receive (mayproduce, slot);
slot = new data item
send (mayconsume, slot);
}
–consumer :
» while (TRUE) {
receive (mayconsume, slot);
consume data item in slot
send (mayproduce, slot);
}
19
Operating Systems: IPC

–properties :
»no shared global data accessed
»all variables local to each process
»works on a distributed network in principle
»producers and consumers can be heterogeneous
­
written in different programming languages - just need library support
run
­ on different machine architectures - ditto

•Examples of Operating Systems with message passing :

•EMAS - Edinburgh Multi-Access System


–all interprocess comms done with messages
»even kernel processes
–system calls used messages
–signals to processes used messages

20
Operating Systems: IPC

•QNX Real-Time Op. Sys.


–tightly synchronised send and receive
»after send, sending process goes into send-blocked state
»when receiving process issues a receive :
»message block shared between the processes
no­ extra copying or buffering needed
»sending process changed to reply-blocked state
»had the receiver issued a receive before sender issued a send, receiver
would have gone into receive-blocked state
»when receiver has processed the data, it issues a reply, which unblocks
the sender and allows it to continue
­
which process runs first is left to the scheduler
–in error situations, blocked processes can be signalled
»process is unblocked and allowed to deal with the signal
»may need an extra monitoring process to keep track of which messages
actually got through

21
Operating Systems: IPC

•MACH Op. Sys.


–two mailboxes (or ports) created with each process
»kernel mailbox : for system calls
»notify mailbox : for signals
–message calls : msg_send, msg_receive and msg_rpc
»msg_rpc (remote procedure call) is a combination of send and receive -
sends a message and then waits for exactly one return message
–port_allocate : creates a new mailbox
»default buffering of eight messages
–mailbox creator is its owner and is given receive permission to it
»can only have one owner at a time but ownership can be transferred
–messages copied into queue as they are sent
»all with same priority, first-come-first-served
–messages have : fixed length header, variable length data portion
»header contains sender and receiver Ids
»variable part a list of typed data items
­
ownership & receive rights, task states, memory segments etc.
22
Operating Systems: IPC

–when message queue full, sender can opt to :


»wait indefinitely until there is space
»wait at most n milleseconds
»do not wait at all, but return immediately
»temporarily cache the message
­ in the kernel, pending
kept
one
­ space for one such message
­
meant for server tasks e.g. to send a reply to a requester, even though the
requestor’s queue may be full of other messages
–messages can be received from either one mailbox or from one of a set of
mailboxes
–port_status call returns number of messages in a queue
–message transfer done via shared virtual memory if possible to avoid
copying
»only works for one system, not for a distributed system

23
Operating Systems: IPC

•Linux Op. Sys. IPC


–shared files, pipes, sockets etc.
•Shared files :
–one process writes / appends to a file
–other process reads from it
–properties:
»any pair of process with access rights to the file can communicate
»large amounts of data can be transferred
»synchronisation necessary
•Pipes :
–kernel buffers for info transfer, typically 4096 bytes long, used cyclically
–e.g. used by command shells to pipe output from one command to input of
another : $ ls | wc -w
»command shell forks a process to execute each command
»normally waits until sub-process terminates before continuing
­ continues executing if ‘&’ appended to command line
but
24
Operating Systems: IPC

#include <unistd.h>
#include <stdio.h>

main() {
int fda[2]; // file descriptors [0] : read end, [1] write end
char buf[1]; // data buffer

if ( pipe(fda) < 0 ) error (“create pipe failed\n”);

switch ( fork() ) { // fork an identical sub-process


case -1 : error (“fork failed\n”);
case 0: // child process is pipe reader
close ( fda[1] ); // close write of pipe
read ( fda[0], buf, 1 ); // read a character
printf (“%c\n”, buf[0] );
break;
default: // parent process is pipe writer
close ( fda[0] ); // close read end of pipe
write (fda[1], “a”, 1); // write a character
break;
}
}
–fork returns 0 to child process, sub-process ID to parent
–by default : write blocks when buffer full, read blocks when buffer empty
25
Operating Systems: IPC

•Aside : I/O Redirection


–used by a command shell
–dup() system call duplicates a file descriptor using first available table entry
–example : dup() file descriptor number 2 :

file descriptors open file descriptors file descriptors open file descriptors

0 0
1 1
2 2
3 3

–example on next slide : $ ls | wc -w


»ls executed by child process, wc executed by parent process
»file descriptors manipulated with close() and dup() so that pipe
descriptors become standard output to ls and standard input to wc
»execlp replaces current process with the specified command

26
Operating Systems: IPC

#include <unistd.h>
#include <stdio.h>

main() {
int fda[2]; // file descriptors

if ( pipe(fda) < 0 ) error (“create pipe failed\n”);

switch ( fork() ) { // fork an identical sub-process


case -1 : error (“fork failed\n”);
case 0: // run ls in child process
close (1); // close standard output
dup ( fda[1] ); // duplicate pipe write end
close ( fda[1] ); // close pipe write end
close ( fda[0] ); // close pipe read end
execlp (“ls”, “ls”, 0); // execute ls command
error (“failed to exec ls\n”); // should not get here
break;
default:// run wc in parent
close (0); // close standard input
dup (fda[0] ); // duplicate pipe read end
close ( fda[0] ); // close read end of pipe
close (fda[1] ); // close write end of pipe
execlp (“wc”, “wc”, “-w”, 0); // execute wc command
error (“failed to execute4 wc\n”);
break;
}
}

27
Operating Systems: IPC

–redirection to file similarly


»closing standard input and output descriptors followed by opening the
redirection files to re-use the standard I/O descriptor numbers
–example : $ cat <file1 >file2

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#define WRFLAGS (O_WRONLY | O_CREAT | O_TRUNC)
#define MODE600 (S_IRUSR | S_IWUSR)

main() {
close (0); // close standard input
if (open(“file1”, O_RDONLY) == -1) error(“open input file failed\n”);

close (1); // close standard output


if (open(“file2”, WRFLAGS, MODE600) == -1) error(“open output failed\n”);

execlp (“cat”, “cat”, 0); // execute cat command

error(“failed to execute ‘cat’\n”);


}
28
Operating Systems: IPC

•FIFOs - Named Pipes


–can be used by any set of processes, not just forked from a common
ancestor which created the anonymous pipe
–FIFO files have names and directory links
–created with a mknod command or system call :
#define MYNODE (S_IFIFO | S_IRUSR | S_IWUSR)
mknod (“myfifo”, MYMODE, 0);
–can be opened and used by any process with access permission
–same functionality as anonymous pipes with blocking by default
–concurrent writers are permitted
–writes of up to 4096 bytes are guaranteed to be atomic
•System V Unix Compatibility
–shared memory - shmget() creates a sharable memory segment identified by
an ID which can be used by any other process by attaching it with a shmat()
system call
–semaphores (extremely messy!) and messages also available
»see : Advanced Programming in the UNIX Environment by W.R. Stevens
29
Operating Systems: IPC

•Sockets
–intended for communications across a distributed network
–uses the connectionless Internet Protocol and IP addresses at the lowest
level e.g. 129.215.58.7
–datagram packets transmitted to destination IP host
–User Datagram Protocol (UDP) or Transmission Control Protocol (TCP) at
the application level
–TCP is a connection based protocol, with order of packet arrival guaranteed
–a socket is a communication end-point
–once a TCP-socket connection between two processes is made, end-points
made to act like ordinary files, using read() and write() system calls.

30
Operating Systems: IPC

–a Client-Server system :
»creating a socket :
sd­ = socket ( family, type, protocol );
»binding to a local address :
­ ( sd, IP address, addrlen );// address includes port number connection by
bind
client process :
­
connect ( sd, IP address, addrlen ); // servers IP address
»server listens for client connection requests :
listen
­ ( sd, queuelen ); // number of requests that can be queued
»and accepts the request :
­
newsd = accept ( sd, IP address, addrlen );
–accept() normally blocks if no client process waiting to establish a
connection
–can be made non-blocking for server to enquire whether any clients waiting
–connectionless communication with UDP datagram sockets also possible
using sendto() and recvfrom() system calls

31
Operating Systems: IPC

// Server-side socket demo progam

#include <fcntl.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <errno.h>

void close_socket(int sd) {


int cs;
if ((cs = close(sd)) < 0) {
printf(“close socket failed: %s\n”, strerror(errno));
exit(1);
}
}

#define SERVER (129<<24 | 215<<16 | 58<<8 | 7)


#define MESSAGELEN 1024
#define SERVER_PORT 5000

void main() {
int ssd, csd;
struct sockaddr_in server, client;
int sockaddrlen, clientlen, ca;
char message[MESSAGELEN];
int messagelen;

sockaddrlen = sizeof(struct sockaddr_in);

32
Operating Systems: IPC

// create socket
if ((ssd = socket (AF_NET, SOCK_STREAM, 0)) < 0) {
printf(“socket create failed: %s\n”, strerror(errno));
exit(1):
} else printf(server socket created, ssd = %d\n”, ssd);

// bind socket to me
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT); // big/little-endian conversion
server.sin_addr.s_addr = htonl(SERVER);
bzero(&server.sin_zero, 8);
if (bind(ssd, (struct sockaddr *) &server, sockaddrlen) < 0) {
printf(“server bind failed: %s\n”, strerror(errno));
exit(1):
}

// listen on my socket for clients


if (listen(ssd, 1) < 0) {
printf(“listen failed: %s\n”, strerror(errno));
close_socket(ssd);
exit(1);
}

// make socket non-blocking


fcntl(ssd, F_SETFL, fcntl(ssd, F_GETFL) | O_NDELAY);

33
Operating Systems: IPC

// accept a client (non-blocking)


clientlen = sockaddrlen;
while ((csd = accept(ssd, &client, &clientlen)) < 0) {
if (errno == EAGAIN) {
printf(“no client yet\n”);
sleep(1); // wait a sec
} else {
printf(“accept failed: %s\n”, strerror(errno));
close_socker(ssd);
exit(1);
}

ca = ntohl(client.sin_addr.s_addr);
printf(“client accepted, csd = %d, IP = %d.%d.%d.%d\n”,
csd, (ca>>24)&255, (ca>>16)&255, (ca>>8)&255, ca&255);

// send message to client


sprintf(message, “Server calling client : hi!\n”);
messagelen - strlen(message)+1;
if (write(csd, message, messagelen) != messagelen) {
printf(write failed\n”);
close_socket(ssd);
exit(1);
} else printf(“message sent to client\n”);

// receive message from client


if (read(csd, message, MESSAGELEN) < 0) {
if (errno == EAGAIN) {

34
Operating Systems: IPC

printf(“no client message yet\n”);


sleep(1);
} else {
printf(“read failed: %s\n”, strerror(errno));
close_socket(ssd);
exit(1);
}

printf(“client message was:\n%s”, message);

close_socket(ssd);

35
Operating Systems: IPC

// Client-side socket demo program


#include <fcntl.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <errno.h>

void close_socket(int sd) {


int cs;
if ((cs = close(sd)) < 0) {
printf(“close socket failed: %s\n”, strerror(errno));
exit(1);
}
}

#define SERVER (129<<24 | 215<<16 | 58<<8 | 7)


#define MESSAGELEN 1024
#define SERVER_PORT 5000

void main() {
int ssd, csd;
struct sockaddr_in server, client;
int sockaddrlen, clientlen, ca;
char message[MESSAGELEN];
int messagelen;

sockaddrlen = sizeof(struct sockaddr_in);

36
Operating Systems: IPC

// server address
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
server.sin_addr.s_addr = htonl(SERVER);

for (;;) {

//create socket
if ((csd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf(“client socket create failed: %s\n”, strerror(errno));
exit(1);
} else prinf(“client socket create, csd = %d\n”, csd);

// try to connect to server


if (connect(csd, (struct sockaddr *) &server, sockaddrlen) < 0) {
printf(“connect failed: %s\n”, strerror(errno));
// need to destroy socket before trying to connect again
close_socket(csd);
sleep(1);
} else break;
}
printf(“connected to server\n”);

// make socket non-blocking


fcntl(csd, F_SETFL, fcntl(csd, F_GETFL) | O_NDELAY);

37
Operating Systems: IPC

// receive a message from server


while (read(csd, message, MESSAGELEN) < 0) {
if (errno == EAGAIN) {
printf(“no server message yet\n”);
sleep(1);
} else {
printf(“read failed: %s\n”, strerror(errno));
close_socket(csd);
exit(1);
}
}
printf(“server message was:\n%s”, message);

// send a message to server


sprintf(message, “Client calling server : ho!\n”);
messagelen = strlen(message)+1;
if (write(csd, message, messagelen) != messagelen) {
printf(“write failed\n”);
close_socket(csd);
exit(1);
} else printf(“message sent to server\n”);

close_socket(csd);

38
Operating Systems: IPC

•Signals
–the mechanism whereby processes are made aware of events occurring
–asynchronous - can be received by a process at any time in its execution
–examples of Linux signal types:
»SIGINT: interrupt from keyboard
»SIGFPE: floating point exception
»SIGKILL : terminate receiving process
»SIGCHLD : child process stopped or terminated
»SIGSEGV : segment access violation
–default action is usually for kernel to terminate the receiving process
–process can request some other action
»ignore the signal - process will not know it happened
SIGKILL
­ and SIGSTOP cannot be ignored
»restore signal’s default action
»execute a pre-arranged signal-handling function
process
­ can register a function to be called
like
­ an interrupt service routine

39
Operating Systems: IPC

­ the handler returns, control is passed back to the main process code and
when
normal execution continues

»to set up a signal handler:


#include <signal.h>
#include <unistd.h>

void (*signal(int signum, void (*handler)(int)))(int);

»signal is a call which takes two parameters


signum
­ : the signal number
­
handler : a pointer to a function which takes a single integer parameter and
returns nothing (void)
»return value is itself a pointer to a function which:
takes
­ a single integer parameter and returns nothing
–example:
»gets characters until a newline typed, then goes into an infinite loop
»uses signals to count ctrl-c’s typed at keyboard until newline typed

40
Operating Systems: IPC

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int ctrl_C_count = 0;
void (* old_handler)(int);
void ctrl_c(int);

main () {
int c;
old_handler = signal (SIGINT, ctrl_c );

while ((c = getchar()) != ‘\n’);

printf(“ctrl_c count = %d\n”, ctrl_c_count);

(void) signal (SIGINT, old_handler);

for (;;);
}

void ctrl_c(int signum) {


(void) signal (SIGINT, ctrl_c); // signals are automatically reset
++ctrl_c_count;
}

•see also the POSIX sigaction() call - more complex but better
41

You might also like