A, message

advertisement
CSCE 313
Introduction to Computer Systems
Instructor: Amin Hassanzadeh
Fall 2013
http://people.tamu.edu/~hassanzadeh/csce
313.htm
Inter-Process Communication (IPC)
• IPC concept & principle
• POSIX IPC
– Message Queues
– Shared Memory
– Semaphore sets
• Accessing IPC resources from shell
• Reading: Unix Systems Programming, Ch 15
2
Interprocess Communication
• Processes within a system may be independent or
cooperating
• Cooperating process can affect or be affected by other
processes, including sharing data
• Reasons for cooperating processes:
– Information sharing
– Computation speedup
– Modularity
– Convenience
• Cooperating processes need interprocess
communication (IPC)
3
Fundamental Communication Models
4
Interprocess Communication – Message Passing
• A mechanism for processes to communicate and to
synchronize their actions
• Message system – processes communicate with each other
without resorting to shared variables
• IPC facility provides two operations:
– send(message) – message size fixed or variable
– receive(message)
• If P and Q wish to communicate, they need to:
– establish a communication link between them
– exchange messages via send/receive
• Implementation of communication link
– physical (e.g., shared memory, hardware bus)
– logical (e.g., logical properties)
5
Implementation Questions
• How are links established?
• Can a link be associated with more than two processes?
• How many links can there be between every pair of
communicating processes?
• What is the capacity of a link?
• Is the size of a message that the link can accommodate
fixed or variable?
• Is a link unidirectional or bi-directional?
6
Direct Communication
• Processes must name each other explicitly:
– send (P, message) – send a message to process P
– receive(Q, message) – receive a message from process Q
• Properties of communication link
– Links are established automatically
– A link is associated with exactly one pair of
communicating processes
– Between each pair there exists exactly one link
– The link may be unidirectional, but is usually bidirectional
7
Indirect Communication
• Messages are directed and received from mailboxes
(also referred to as ports)
– Each mailbox has a unique id
– Processes can communicate only if they share a
mailbox
• Properties of communication link
– Link established only if processes share a common
mailbox
– A link may be associated with many processes
– Each pair of processes may share several
communication links
– Link may be unidirectional or bi-directional
8
Indirect Communication
• Operations
– create a new mailbox
– send and receive messages through mailbox
– destroy a mailbox
• Primitives are defined as:
send(A, message) – send a message to mailbox A
receive(A, message) – receive a message from
mailbox A
9
Indirect Communication
• Mailbox sharing
– P1, P2, and P3 share mailbox A
– P1, sends; P2 and P3 receive
– Who gets the message?
• Solutions
– 1…
– 2…
– 3…
10
Indirect Communication
• Mailbox sharing
– P1, P2, and P3 share mailbox A
– P1, sends; P2 and P3 receive
– Who gets the message?
• Solutions
– Allow a link to be associated with at most two
processes
– Allow only one process at a time to execute a receive
operation
– Allow the system to select arbitrarily the receiver.
Sender is notified who the receiver was.
11
Synchronization
• Message passing may be either blocking or nonblocking
• Blocking is considered synchronous
– Blocking send has the sender block until the
message is received
– Blocking receive has the receiver block until a
message is available
• Non-blocking is considered asynchronous
– Non-blocking send has the sender send the
message and continue
– Non-blocking receive has the receiver receive a
valid message or null
12
Buffering
• Queue of messages attached to the link;
implemented in one of three ways
1. Zero capacity – 0 messages
Sender must wait for receiver (rendezvous)
2. Bounded capacity – finite length of n messages
Sender must wait if link full
3. Unbounded capacity – infinite length
Sender never waits
13
POSIX IPC: Overview
primitive
POSIX function
description
message queues
msgget
msgctl
msgsnd/msgrcv
create or access
control
send/receive message
semaphores
semget
semctl
semop
create or access
control
wait or post operation
shared memory
shmget
shmctl
shmat/shmdt
create and init or access
control
attach to / detach from
process
Accessing IPC resources from the shell: ipcs [-a]
14
xxGET: It’s all about Naming!
• Condition variables, mutex locks:
– Based on a memory variable concept.
– Does not work across memory spaces!!
• Pipes
– Uses file descriptors
– Works across memory spaces.
– Relies on inheritance of file descriptors -> does not work for
unrelated processes.
• Named Pipes
– Uses file system as name space for pipe.
– Works for unrelated processes.
– Carry the overhead of the file system.
• IPC Objects
– Use system-global integer keys to refer to objects.
15
IPC Object Creation: Message Queues
Object key identifies object across processes. Can be assigned
as follows:
-- Create some unknown key (IPC_PRIVATE) by the system
-- Pass explicit key (beware of collisions!)
-- Use file system to consistently hash key (using ftok)
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
/* create a message queue with given key and flags. */
Object id is similar to file descriptor.
-- It can be inherited across fork() calls.
16
ftok()
• ftok - generate an IPC key
• The ftok()function shall return a key based on path and
id that is usable in subsequent calls to msgget(), semget(),
and shmget(). The application shall ensure that the path
argument is the pathname of an existing file that the
process is able to stat().
• Upon successful completion, ftok() shall return a key.
Otherwise, ftok() shall return (key_t)-1 and set errno to
indicate the error.
17
Operations on Message Queues
#define PERMS (S_IRUSR | S_IWUSR)
int msqid;
if ((msqid = msgget(IPC_PRIVATE, PERMS)) == -1)
perror(“msgget failed);
struct mymsg { /* user defined! */
long msgtype; /* first field must be a long identifier */
char mtext[1]; /* placeholder for message content */
} mymsg_t;
int msgsnd(int msqid, const void *msgp,
size_t msgsz, int msgflg)
msgtyp
0
action
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz,
long msgtyp, int msgflg);
remove first message from queue
>0
remove first message of type msgtyp from the queue
<0
remove first message of lowest type that is less than or
equal to absolute value of msgtyp
18
Operations on Message Queues - Send
19
Operations on Message Queues (cont.)
int msgctl(int msqid, int cmd, struct msgid_ds *buf)
Cmd
IPC_RMID
IPC_SET
IPC_STAT
description
remove the message queue msqid and destroy the
corresponding msqid_ds
Set members of the msqid_ds data structure from buf
Copy members of the msqid_ds data structure into buf
20
POSIX Message Queues Example
#define MSGSZ 128
#define MSGKY 1234
typedef struct the_msg {
long mtype;
char mtext[MSGSZ];
} message_buf;
21
POSIX Message Queues Example
main () {
int msqid;
int msgflg = IPC_CREAT | 0666;
message_buf sbuf;
memset(&sbuf.mtext, 0, (size_t) MSGSZ);
if((msqid = msgget((key_t) MSGKY, msgflg)) < 0) {
perror("msgget");
exit(1);
}
sbuf.mtype = 1;
strcpy(sbuf.mtext, "Did you get this?\n\0");
if(msgsnd(msqid, &sbuf, (size_t)(strlen(sbuf.mtext)), 0) < 0) {
perror("msgsnd");
exit(1);
}
printf("Message sent...\n");
exit(0);
}
22
POSIX Message Queues Example
main () {
int msqid;
message_buf rbuf;
memset(&rbuf.mtext, 0, (size_t) MSGSZ);
if((msqid = msgget((key_t) MSGKY, 0666)) < 0) {
perror("msgget");
exit(1);
}
if (msgrcv(msqid, &rbuf, MSGSZ, 1, 0) < 0) {
perror("msgrcv");
exit(1);
}
printf("%s\n", rbuf.mtext);
exit(0);
}
23
Message Queue Program Example
• Program 15.9 msgqueuelog.c (ch15)
– Utility functions that access and output to a message
queue
• Program 15.10 msgqueuesave.c (ch15)
– A program that copies messages from a message
queue to standard output
24
POSIX Shared Memory
• A range of addresses created by the IPC facility for one process
• Other processes can “attach” the same shared memory segment into
their own address space.
• Applications use this memory just as if it had been allocated by malloc
• When one application writes to shared memory in this range, the
change is immediately available to any other process that has access
to the same shared memory
• Shared memory doesn’t provide any synchronization facilities.
• It is up to the programmer to synchronize access.
25
POSIX Shared Memory
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Ok, we have created a shared-memory segment. Now what?
address space of
calling process
P1
shared-memory
segment mapped by
shmat
void *shmat(int shmid, const void *shmaddr,
int shmflg);
system memory
shared-memory
segment created by
shmget
address space of
calling process
P2
shared-memory
segment mapped by
shmat
26
Use POSIX Shared Memory
– Process first creates shared memory segment
segment id = shmget(IPC PRIVATE, size, S IRUSR | S IWUSR);
– Process wanting access to that shared memory must
attach to it
shared memory = (char *) shmat(id, NULL, 0);
– Now the process could write to the shared memory
sprintf(shared memory, "Writing to shared memory");
– When done a process can detach the shared memory
from its address space
shmdt(shared memory);
27
1. shmget()
this function is used to create a shared memory segment
the amount of memory required, in bytes
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
returns a shared
memory identifier
or -1
a programmer defined key
permission bits
and IPC_CREAT
28
2. shmctl()
#include <sys/shm.h>
int shmctl(int shm_id, int command, struct shmid_ds *buf);
returns 0 if successful
or -1 if fails
the shared memory
segment’s identifier
struct shmid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
}
IPC_STAT
Sets the data in the shmid structure to reflect
the values associated with the shared memory.
IPC_SET
Sets the values associated with the shared
memory to those provided in the data structure.
IPC_RMID
Delete the shared memory
29
3. shmat()
this function attaches the shared memory segment to the process’s
address space.
#include <sys/shm.h>
void *shmat(int shm_id, const void *shm_addr, int shmflg);
returns a pointer to
the shared memory.
the shared memory identifier
gotten from shmget()
if non-zero, the segment is
attached for read-only. If 0,
it is attached read/write.
address in the process’s address
space where the shared memory
is to be attached. Normally this
is a NULL pointer, allowing the
system to determine where.
This is the recommended form.
30
3. shmdt()
this function detaches the shared memory segment
#include <sys/shm.h>
int shmdt(const void *shm_addr);
returns 0 if successful
or -1 if not
pointer to the shared memory
segment to be detached.
31
POSIX Shared Memory Example
a
b
c
d
e
.
.
.
Producer
\n
\0
Consumer
shared
memory
32
POSIX Shared Memory - Producer
#define SHMSZ 27
// the size of the shared memory segment
#define SHMKY 5678
// the key of the shared memory segment
main ()
{
char c;
int shm_id;
char *shm, *s;
// create a shared memory segment.
if ((shm_id = shmget((key_t)SHMKY, SHMSZ, IPC_CREAT | 0666)) < 0 )
{
perror("shmget");
exit(1);
}
// attach the shared memory segment, shm points to it
if ((shm = shmat(shm_id, NULL, 0)) == (char *)-1)
{
perror("shmat");
exit(1);
}
33
POSIX Shared Memory - Producer
// Now write out a string of characters
// Add a line feed and Null terminate the string.
s = shm;
for (c = 'a'; c <= 'z'; c++)
{
*s++ = c;
}
*s++ = '\n';
*s = '\0';
// Finally, wait until the consumer writes a '*'
// in the first character position to signal that
// it is done.
while(*shm != '*')
{
sleep(1);
}
printf("All done ... data has been read!\n");
exit(0);
}
34
POSIX Shared Memory - Consumer
#define SHMSZ 27 // the size of the shared memory block
#define SHMKY 5678
// the key of the shared memory block
main ()
{
int shm_id;
char *shm, *s;
if ((shm_id = shmget((key_t)SHMKY, SHMSZ, 0666)) < 0 ) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shm_id, NULL, 0)) == (char *)-1)
{
perror("shmat");
exit(1);
}
for (s = shm; *s != '\0'; s++)
{
getchar(*s);
}
*shm = '*';
exit(0);
}
35
Accessing IPC Resources From the Shell
• POSIX:XSI defines shell extensions for examining and
deleting IPC resources.
ipcs [-qms] [ a | -bcot ]
• With no parameters, the ipcs command displays an
abbreviated set of information about all message queues,
shared memory, and semaphore sets .
ipcrm [ -q msgid | -Q msgkey | -s semid | -S semkey |
-m shmid | -M shmkey ]
removes an individual IPC object.
36
Shared Memory Program Example
• Program 15.5 monitorshared.c
– Monitor two file descriptors and keep information in
shared memory. The parent waits for the child, to
ensure mutual exclusion
• Program 15.6 sharedmemsum.c
– A function that keeps a synchronized sum and count
in shared memory
• Program 15.7 showshared.c
– Display the shared count and sum when it receives a
SIGUSR1 signal
37
POSIX:XSI Semaphores
• POSIX:XSI semaphores are part of the general
POSIX interprocess communication facility
• A POSIX:XSI semaphore is created by executing a
semget() system call
• The semget() creates a semaphore data structure in
the kernel and returns an integer handle to the
semaphore
• Processes cannot access semaphore data
structures directly –only through system calls
• Semaphore ids or handles are analogous to file
descriptors
38
POSIX:SEM vs POSIX:XSI Semaphores
• POSIX:XSI data structures are created and kept in the
kernel and are referenced through integer handles
• In POSIX:SEM, a program declares a variable of type
sem_t and passes a pointer to that variable
39
Semaphore Sets
• A semaphore set is an array of semaphore elements
• A process can perform operations on the entire set in a
single system call
• The internal representation of semaphore sets and
semaphore elements is not directly accessible
• Each semaphore includes at least the following:
– A nonnegative integer representing semaphore value
– Process ID of the last process to manipulate the
semaphore element
– Number of processes waiting for the semaphore
element to increase
– Number of processes waiting for the semaphore
element value to equal 0
40
1. semget( )
the key is like a file name. Processes can cooperate
using a shared semaphore if they agree on a
common key.
int semget ( key_t key, int num_sems, int sem_flags);
semget creates a new semaphore or
obtains the key of an existing semaphore.
The semaphore identifier is returned. The
identifier is like a file descriptor, and is
used within the process to access the
semaphore. Returns -1 if the call fails.
the number of semaphores
required.
like the open flags on a file:
IPC_PRIVATE: only this process can use the semaphore
IPC_CREAT: create a new semaphore if one doesn’t exist
IPC_EXCL: make sure semaphore is unique
If a process attempts to create a semaphore that already exists,
it receives a handle to the existing semaphore, unless sem_flags
specifies both IPC_CREAT and IPC_EXCL.
41
POSIX Semaphore Sets
#include <sys/sem.h>
int semget(key_t key, int nsems, int
semflg);
/* Create semaphore set with nsems
semaphores. If set exists, nsems can be
#include <sys/sem.h> zero. */
#define PERMS
(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
#define SET_SIZE 2
int main (int argc, char * argv[]) {
key_t mykey;
int
semid;
mykey = ftok(argv[1], atoi(argv[2]));
semid = semget(mykey, SET_SIZE, PERMS | IPC_CREAT)
return 0;
}
42
semget() example
#include <sys/sem.h>
#define PERMS S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define SET_SIZE 1
#define KEY ((key_t) 99887)
void main(void) {
int semid;
if ((semid=semget(KEY, SET_SIZE, PERMS | IPC_CREAT)) < 0)
fprintf(stderr, "Error creating semaphore with key %d:
%s\n“,(int)KEY,strerror(errno));
else
printf("Semaphore with ID %d created for key
%d\n",semid,(int)KEY);
}
43
semget() example
#include <sys/sem.h>
#define PERMS S_IRUSR|S_IWUSR
#define SET_SIZE 3
int semid;
void main(void) {
int semid;
if ((semid = semget(IPC_PRIVATE, SET_SIZE, PERMS)) < 0)
perror("Could not create new private semaphore");
else
printf("Semaphore created with ID %d\n",semid);
}
44
Semaphore Set Control semctl()
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, …);
command
description
SETVAL
set value of a specific semaphore element to arg.val
SETALL
set values of semaphore set from arg.array
GETVAL
return value of specific semaphore element
GETALL
return values of the semaphore set in arg.array
GETPID
return process id of last process to manipulate element
GETNCNT
return number of processes waiting for element to increment
GETZCNT
return number of processes waiting for element to become 0
etc….
45
2. semctl()
Each element in a semaphore set must be initialized with semctl before it is used.
int semctl ( int sem_id, int sem_num, int command, union semun arg);
the semaphore set
identifier from semget
The Semaphore to
set
union semun
{
int val; // value for SETVAL
struct semid_ds *buf; // buffer for IPC_STAT, I
unsigned short int *array; // array for GETALL,
struct seminfo * _buf; // buffer for IPC_INFO
};
Commonly Used comands:
GETVAL – return the value of the semaphore
GETPID – return last process ID that manipulated semaphore
GETNCNT – return number of processes waiting for an element to increase
GETZCNT – return number of processes waiting for element to become 0
SETVAL – initialize a semaphore to a known value
IPC_RMID – delete a semaphore ID
IPC_STAT – copy info from the semaphore set data structure into _buf
IPC_SET – write values from _buf into the semaphore set data structure
46
semctl() example
#include <sys/sem.h>
int initelement(int semid, int semnum, int semvalue)
{
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
arg.val = semvalue;
return semctl(semid, semnum, SETVAL, arg);
}
sets the value of the specified semaphore element to semvalue
47
semctl() example
#include <sys/sem.h>
int removesem(int semid) {
return semctl(semid, 0, IPC_RMID);
}
deletes the semaphore specified by semid
48
3. semop()
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
/* The operations are defined in the array pointed to
by ‘sops’. */
struct sembuf contains approximately the following members:
short sem_num
number of semaphore element
short sem_op
operation to be performed
IPC_NOWAIT
short sem_flg
specific options for the operation SEM_UNDO.
sem_op > 0
add the value to the semaphore element and awaken
all processes that are waiting for element to increase
(sem_op == 0)
block calling process (waiting for 0) and increment
&& (semval != 0) count of processes waiting for 0.
sem_op < 0
add sem_op value to semaphore element value
provided that result would not be negative.
If result negative, block process on event that
semaphore value increases.
If result == 0, wake processes waiting for 0.
49
3. semop()
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
/* The operations are defined in the array pointed to
by ‘sops’. */
struct
short
short
short
sembuf contains approximately the following members:
sem_num
number of semaphore element
sem_op
operation to be performed
IPC_NOWAIT
sem_flg
specific options for the operation SEM_UNDO.
IPC_NOWAIT -- Can be set for any operations in the array. Makes the
function return without changing any semaphore value if any operation for
which IPC_NOWAIT is set cannot be performed. The function fails if it tries
to decrement a semaphore more than its current value, or tests a nonzero
semaphore to be equal to zero.
SEM_UNDO -- Allows individual operations in the array to be undone when
the process exits.
50
Semaphore Set Operations: Example
Consider the following function written to set up the semop
structure sembuf:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
void setsembuf (struct sembuf *s, int num, int op, int flg)
{
s->sem_num = (short)num;
s->sem_op = op;
s->sem_flg = flg;
return;
}
51
Semaphore Operations: Example
Mutually-Exclusive Access to Two Tapes:
/* pseudo code */
struct sembuf get_tapes[2];
struct sembuf release_tapes[2];
setsembuf(&(get_tapes[0]),
setsembuf(&(get_tapes[1]),
setsembuf(&(release_tapes[0]),
setsembuf(&(release_tapes[1]),
0,
1,
0,
1,
-1,
-1,
+1,
+1,
0);
0);
0);
0);
/* Process 1: */
semop(S, get_tapes, 1);
<use Tape 0>
semop(S, release_tapes, 1);
/* Process 2: */
semop(S, get_tapes, 2);
<use both tapes 0 and 1>
semop(S, release_tapes, 2);
52
Semaphore Operations: Another Example
Semaphore to control access to critical section:
int main(int argc, char * argv[]) {
int semid;
struct sembuf sem_signal[1];
struct sembuf sem_wait[1];
semid = semget(IPC_PRIVATE, 1, PERMS);
setsembuf(sem_wait, 0, -1, 0);
setsembuf(sem_signal, 0, 1, 0);
if(-1 == initelement(semid, 0, 1) /* Set value of element 0 to 1 */
removesem(semid);
for (int i = 1; i < n; i++) if fork() break;
semop(semid, sem_wait, 1); /* enter critical section */
/* in critical section */
semop(semid, sem_signal, 1); /* leave critical section */
/* in remainder section */
return 0;
}
53
Download