Professional Documents
Culture Documents
2015/09
Materials can be found:
2
Prerequisite
Linux +
gcc env.
Lecture +
Hands-on
3
Agenda
1. Introduction
2. Pipe
3. Message Queue
4. Semaphore
5. Shared Memory
6. Socket
4
Introduction
5
Introduction
Pipe
Message
Queue
Local host
System V IPC
Semaphore
IPC – Inter Process POSIX IPC
Communication
Shared
Memory
Unix domain
socket
Socket
Different host
STREAMS
6
Pipe
Pipe – system call
#include <unistd.h>
int pipe(int filedes[2]);
8
Pipe
Pipe Pipe
Kernel Kernel
9
Pipe
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6
7
#include <sys/wait.h>
Take a look at
8 main()
9
10
{
pid_t pid;
fork()
11 int rv;
12
13 switch(pid=fork()) {
14 case -1:
15 perror("fork"); /* something went wrong */
16 exit(1); /* parent exits */
17
18 case 0:
19 printf(" CHILD: This is the child process!\n");
20 printf(" CHILD: My PID is %d\n", getpid());
21 printf(" CHILD: My parent's PID is %d\n", getppid());
22 printf(" CHILD: Enter my exit status (make it small): ");
23 scanf(" %d", &rv);
24 printf(" CHILD: I'm outta here!\n");
25 exit(rv);
26
10
Pipe – In-Class Practice
pipe.c
11
Pipe – Usage in Shell
• ls | more
12
Pipe – popen and pclose function
#include <stdio.h>
FILE *popen(const char *cmdstring, const char *type);
Returns: file pointer if OK, NULL on error
Type: ‘r’ means the returned file pointer is readalbe; ‘w’ means the returned file pointer is
writeable.
Create a pipe, forking a child, closing the unused ends of the pipe, executing a shell to run
the command, and waiting for the command to terminate.
13
Pipe – In-Class Practice
14
Pipe – FIFO
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
Returns: 0 if OK, -1 on error
15
Pipe – In-Class Practice
16
Pipe - Summary
What is pipe
Pipe usage in C
17
System V IPC - Overview
System V IPC - Introduction
19
System V IPC - History
Late 70s they first appear together in Columbus UNIX, a Bell UNIX for database and
efficient transaction processing
1983 they land together in System V that made them popular in mainstream UNIX-
es, hence the name
2001 SUSv3 is published and require implementation of all of them for XSI
conformance, hence they are also called XSI IPC
20
System V IPC - API
21
System V IPC - Concepts
Date
(French)
object instance of the IPC mechanism that can be used for communication
• e.g. a specific message queue, (set of) semaphores, shared memory region
• each object defines a communication context
22
System V IPC - Protocol
The usage of all System V IPC mechanisms goes through a common “protocol”:
1. Obtain a key - mechanism-independent
2. Get an object - passing the key to a mechanism-specific syscall
3. Store its identifier - mechanism-independent
4. Communicate through the object - passing the identifier to mechanism-specific
syscalls
Steps (1) and (2) are optional: object identifiers are stable integers
that can be stored and passed around as processes see fit.
23
System V IPC - Getting IPC object
24
System V IPC – Example on getting IPC object
int id ;
/* . . . */
/* get message queue for key */
i f ( ( id = msgget ( key , IPC_CREAT | S_IRUSR | S_IWUSR ) ) < 0)
err_sys ( "msgget error " ) ;
Notes:
• the message queue will be created if it doesn’t exist, otherwise
the existing one corresponding to key will be returned
• if created, the message queue will be readable and writable only
by processes belonging to the owner of the current process
25
System V IPC - object persistence
System V IPC objects have kernel persistence: they remain available, no matter the
number of “users” they have, until kernel shutdown or explicit deletion.
Advantage
• processes can access the object, change its state, and then exit without having to
wait; other processes can come up later and check the (modified) state i.e. System
V IPC objects are stateful and connectionless
Disadvantage
• IPC objects consume system resources and cannot be automatically garbage
collected, hence the need of enforcing limits on their quantity
• it’s hard to determine when it is safe to delete an object
26
System V IPC - Object deletion
Each System V IPC offers a control syscall for generic object manipulation
• msgctl, semctl, shmctl
Among other things, IPC control syscalls are used to delete IPC objects:
• passing the IPC_RMID command
• and no extra arguments (i.e. a trailing NULL)
27
System V IPC – Shell manipulation
ipcs: lists available System V IPC objects, ipcs –l show system limits on IPC object counts
ipcrm: allows to delete IPC objects (we own)
ipcmk: (non portable) allows to create IPC objects
28
System V IPC – Assigning keys
1. Choose an arbitrary key value once and for all and distribute it via a common header file
2. Pass the special constant IPC_PRIVATE as key to get syscalls, which always result in the creation
of a fresh IPC object
e.g. id = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR);
the creating process will then need to transmit the object identifier to collaborating processes by other
means
29
System V IPC - Assigning keys
3. Use the ftok syscall to generate a unique key from the name of an existing file and an arbitrary
integer
i.e. delegate uniqueness guarantees to the filesystem namespace
#include <sys/ipc.h>
key_t ftok(char *pathname, int proj);
Returns: key value if OK, -1 on error
• pathname points to a file that will be subject to stat
• proj allows to have different contexts for the same file
Behind the scenes, the 8 least significant bits of proj and of the file
i-node will be used to build a unique key.
30
Message Queue
Message Queue
System V message queues are IPC objects used for data transfer
among unrelated processes.
communication granularity are individual messages, no need to handle message
boundaries explicitly as it happened with byte stream
communication discipline is first-in, first-out . . .
. . . but messages are typed with integer values and can be extracted using type predicates
i.e. a queue can be seen as multiple independent queues, one per message type, as well as a
priority queue
each message carries a payload of arbitrary data
32
Message Queue - msgget
An existing message queue can be opened or a new one created using the message queue get syscall
msgget:
#include <sys/msg.h>
int msgget(key_t key, int flags);
Returns: message queue ID if OK, -1 on error
33
Message Queue - msgsnd
Once you have a message msgp, you can send it through a given message queue msqid
using msgsnd:
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
Returns: 0 if OK, -1 on error
• msgsz is the size of the payload (i.e. what follows mtype)
it will depend on your specific instantiation of the msg. struct
• msgflg supports a single flag: IPC_NOWAIT | non-blocking send
if given, IPC_NOWAIT will have msgsnd fail with EAGAIN if the target queue
is full, instead of blocking
34
Message Queue - msgrcv
#include <sys/msg.h>
int msgrcv(int msqid, void *msgp, size_t maxmsgsz, long msgtyp, int msgflg);
Returns: 0 if OK, -1 on error
35
Message Queue - msgctl
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
Returns: 0 if OK, -1 on error
36
Message Queue – In-Class Practice
writeQ.c readQ.c
37
Message Queue - In-Class Practice
Open 2 terminals:
run readQ from terminal 1
run writeQ from terminal 2
Write something on terminal 2, what you get?
38
Semaphore
Semaphore
A semaphore is an abstract data type whose instances can be used by processes that want to
coordinate access to shared resources. A semaphore is equipped with operations that allow
coordination without race conditions between testing the value of the semaphore and changing it.
In its general form, a semaphore is an integer variable that can never descend below 0.
Intuitively, such a semaphore counts the number of available units of a shared resource.
A special, yet very common, case is that of a binary semaphore used to guarantee mutual exclusion
when accessing a single shared resource. A binary semaphore has only two possible values:
1 the resource is available
0 the resource is taken
Stefano
40
Semaphore - Operations
41
Semaphore - Example
You want to coordinate access to a shared memory area among multiple processes
ensuring memory coherence.
More precisely, each process wants to perform an increment action on the int counter
variable stored into shared memory. The increment operation is defined as: read counter
and write it back incremented by one (i.e. counter++). The desired property is that if
n processes perform a total of k increment operations, the counter is incremented exactly
by k.
Due to the race condition between reading counter value and writing it back
incremented, it is not enough for each process to simply do counter++ with more complex
data structure, the race condition can also cause data corruption that makes impossible
to read the value.
42
Semaphore – Example (cont.)
With a binary semaphore S we can solve the problem and avoid race conditions. We
assume that the semaphore is initialized with S <-1.
Each process will implement increment as follows:
1 P(S)
2 counter++
3 V(S)
The P call would block if someone else is incrementing counter. Within the P … V window a
process knows that—as long as all other processes follow the same protocol—he will
execute its critical section without interference from others.
For semaphores to work, it is essential that P(S) atomically test & decrement
(if possible) the semaphore value. Only the kernel can guarantee that.
43
Semaphore – Example (cont.)
In the example, there is a single resource available (the counter global variable), hence a
binary semaphore is enough.
the scheme can be generalized to n available resources using
S <- n as semaphore initialization
We then generalize P and V to take arbitrary integer parameters
V(S, m) increment semaphore value by m (1 … n)
P(S, m) try to decrease semaphore value by m and block if that is not possible
NOTE: until the decrease is possible, semaphore value remains unchanged, i.e. no partial
decrease is possible
44
Semaphore – System V Semaphore
45
Overview of System V semaphore API
control semctl
46
Semaphore - semget
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
Returns: semaphore set ID if OK, -1 on error
47
Semaphore - semop
All semaphore operations are requested via the semop syscall. The fact that the object
granularity is the semaphore set, makes it rather cumbersome to use. . .
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned int nsops);
Returns: 0 if OK, -1 on error
• semid is the semaphore set identifier
• sops points to a (non-empty) array of operations to be performed on individual semaphores
struct sembuf {
unsigned short sem_num; /* semaphore number, 0based */
short sem_op; /* operation to be performed */
short sem_flg ; /* operation f lags */
};
• nsops is the number of operations in the sops array
48
Semaphore – semop (cont.)
struct sembuf {
unsigned short sem_num; /* semaphore number, 0 based */
short sem_op; /* operation to be performed */
short sem_flg ; /* operation f lags */
};
49
Semaphore - semctl
The semaphore set control syscall is semctl. Contrary to other control syscalls, semctl is
overloaded for two different purposes:
1 generic control operations (access to semid_ds, deletion)
2 semaphore initialization & reset
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ... /*union semun arg */);
Returns: non-negative integer if OK, -1 on error
50
Semaphore – semctl (cont.)
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ... /*union semun arg */);
Returns: non-negative integer if OK, -1 on error
Semaphore initialization / reset uses the following cmd-s:
• GETVAL/SETVAL: get/set the value of the setnum-th semaphore
• GETALL/SETALL: as above, but for all semaphores at once
Arguments and return values for all semctl commands are conveyed by semun, that must be defined by
your programs as follows:
union semun {
int val ; /* individual semaphore value */
struct semid_ds *buf ; /* semaphore data structure */
unsigned short * array ; /* multiple semaphore values */
};
51
Semaphore Initialization
according to SUSv3, semaphores are not initialized to any specific value when created with
semget+IPC_CREAT
Linux initializes semaphores to 0, but it’s not portable
therefore, semaphores must be explicitly initialized after creation with semctl
If multiple processes attempt to create & initialize a common
semaphore you get a race condition for semaphore initialization.
Solutions:
1. avoidance: ensure that a single process is in charge of creating& initializing the semaphore,
e.g.:
creation at (application) boot time, possibly using ipcmk
have a parent create & initialize before spawning children
2 the sem_otime trick based on the historical (and now standard) fact that the field is set to 0 upon
creation
52
Semaphore - In-Class Practice
• mkdir semaphore
• Copy contents attached file into new files accordingly
• gcc –o semaphore semaphore.c
• gcc –o semaphoreInit semaphoreInit.c
semaphore.c semaphoreInit.c
53
Semaphore - In-Class Practice
• run semaphoreInit
• run semaphore in process one
• Press return to lock
• Stop here
• run samaphore in process two
• In process two can you get the resource? Why?
• Release the resource in process one.
• Can you get the resource in process two now?
54
Semaphore - In-Class Practice
55
System V semaphores - Disadvantages
Semaphore-specific issues:
• initialization race condition
• overly complex API, “thanks” to the set granularity
56
Shared Memory
System V Shared Memory
58
Shared memory protocol
The “protocol” to use shared memory segments, unlike other System V mechanisms, require
more than one step before actual IPC.
59
Shared memory protocol (cont.)
4. once a process is done using shared memory, it should detach the segment from its
address space
• once detached, access to the memory corresponding to the (now detached) segment will cause SIGSEGV
5. once all processes are done using shared memory, a process should delete the segment
using the control syscall with IPC_RMID
• until this step is done, the shared memory segment will continue to exist (and to occupy system resources)
60
Overview of System V Shared Memory API
control shmctl
61
shmget
shmget is the get syscall for shared memory segments:
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Returns: shared memory segment id if OK, -1 on error
62
shmat
Once a process has obtained a segment identifier, it should use it to attach the segment
to its address space using shmat.
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
Returns: base address of the attached segment if OK, -1 on error
• shmid is the identifier of the segment to attach
• shmaddr is the address where to attach the segment
it is optional, if omitted the kernel will choose a suitable address
• Flags is a bitwise OR of flags that include:
SHM_RDONLY: attach segment read-only
SHM_REMAP: replace already existing mapping at shmaddr
• on success, shmat will return the starting address of the attached segment
63
shmat (cont.)
Attaching segments at fixed addresses using shmaddr comes with its own problems
• at compile time, when we write the program, we often don’t know if shmaddr will be available at
runtime for attaching the segment; in particular:
we don’t know if another segment will be attached at shmaddr
we don’t know if at shmaddr there will be enough available contiguous memory to fit the
segment+roundup
• it reduces portability, as an address valid on some UNIX machine will not necessarily be valid on
different UNIX-es
As a best practice, never use shmaddr and rely on the kernel to find
a suitable address for you.
64
shmdt
Once done working on a shared memory segment, a process can detach it from its
address space using shmdt:
#include <sys/shm.h>
int shmdt(const void *shmaddr);
Returns: 0 if OK, -1 on error
Note that detaching is different than deleting. Once detached, the memory segment (and
its content) will still exist in kernel space until explicitly deleted.
65
Segment inheritance
66
shmctl
#include <sys/shm.h>
shmctl(int shmid, int cmd, struct shmid_ds *buf);
Returns: 0 if OK, -1 on error
67
Shared Memory - In-Class Practice
mkdir sharedMem
Copy the contents in attached file to sharedMemRC.c
gcc –o sharedMemRC sharedMemRC.c sharedMemRC.c
./sharedMemRC w&
./sharedMemRC
What do you see?
run it again: ./sharedMemRC
What go you see?
68
Shared Memory - In-Class Practice
69
System V IPC vs. POSIX IPC
POSIX IPC API Summary
71
Comparison of System V IPC and POSIX IPC
Advantages
• The POSIX IPC interface is simpler than the System V IPC interface.
• The POSIX IPC model—the use of names instead of keys, and the open, close, and unlink
functions—is more consistent with the traditional UNIX file model.
• POSIX IPC objects are reference counted. This simplifies object deletion, because we can
unlink a POSIX IPC object, knowing that it will be destroyed only when all processes have
closed it.
Disadvantage
• POSIX IPC is not portable than System V IPC
72
POSIX IPC – check tool
• cat /dev/mqueue/mqxxxx
• cat /dev/shm/shmxxxx
• cat /dev/shm/sem.xxx
73
System V IPC - Summary
Overview
Message Queue
Semaphore
Shared Memory
POSIX IPC
74
Socket
Socket – What is it?
Sockets are IPC objects that allow to exchange data between processes running:
either on the same machine (host), or
on different ones over a network.
History:
The UNIX socket API first appeared in 1983 with BSD 4.2. It has been finally
standardized for the first time in POSIX.1g (2000), but has been ubiquitous to every
UNIX implementation since the 80s.
76
Socket - Unix vs. Internet sockets
77
Socket - Internet Sockets Types
Connectionless
Diagram Unreliable
e.g. UDP
Connection Oriented
Reliable
Stream Byte stream
e.g. TCP
78
Socket – OSI Reference Model and TCP/IP Model Layers
79
Socket – Data Flow
81
Socket – Data Encapsulation
82
Socket – Create Socket
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
Returns: file (socket) descriptor if OK, –1 on error
83
Socket – Socket Descriptor
84
Socket – Byte Order
85
Socket – Byte Order
86
Socket - In-Class Practice
mkdir socket/1
Copy the contents in attached file to
address.c address.c
87
Socket – Address Format
88
Socket – Address Format
New generic socket address structure, to cover IPv6
/* Structure large enough to hold any socket address (with the historical
exception of AF_UNIX). We reserve 128 bytes. */
#if ULONG_MAX > 0xffffffff
# define __ss_aligntype __uint64_t
#else
# define __ss_aligntype __uint32_t
#endif
#define _SS_SIZE 128
#define _SS_PADSIZE (_SS_SIZE - (2 * sizeof (__ss_aligntype)))
struct sockaddr_storage
{
__SOCKADDR_COMMON (ss_); /* Address family, etc. */
__ss_aligntype __ss_align; /* Force desired alignment. */
char __ss_padding[_SS_PADSIZE];
};
89
Socket - Address Format
A problem arises in how to declare the type of pointer that is passed. With ANSI C, the
solution is simple: void * is the generic pointer type. But, the socket functions predate ANSI C
and the solution chosen in 1982 was to define a generic socket address structure in the
<sys/socket.h> header.
90
Socket - Address Format Internet addresses – IPv6
1 struct sockaddr_in6 {
2 sa_family_t sin6_family; /* AF_INET6 */
Internet addresses – IPv4 3 in_port_t sin6_port; /* Transport layer port # */
1 struct sockaddr_in { 4 uint32_t sin6_flowinfo; /* IPv6 flow information */
2 sa_family_t sin_family; /* AF_INET */ 5 struct in6_addr sin6_addr; /* IPv6 address */
3 in_port_t sin_port; /* Port number. */ 6 uint32_t sin6_scope_id; /* IPv6 scope-id */
4 struct in_addr sin_addr; /* Internet address. */ 7 };
5
8 struct in6_addr {
6 /* Pad to size of `struct sockaddr'. */
9 union {
7 unsigned char sin_zero[sizeof (struct sockaddr) -
10 uint8_t u6_addr8[16];
8 sizeof (sa_family_t) -
9 sizeof (in_port_t) - 11 uint16_t u6_addr16[8];
10 sizeof (struct in_addr)]; 12 uint32_t u6_addr32[4];
11 }; 13 } in6_u;
12 typedef uint32_t in_addr_t; 14
13 struct in_addr { 15 #define s6_addr in6_u.u6_addr8
14 in_addr_t s_addr; /* IPv4 address */ 16 #define s6_addr16 in6_u.u6_addr16
15 };
17 #define s6_addr32 in6_u.u6_addr32
18 };
91
Socket – Programming Model
TCP Client-Server
Stream socket / phone analogy
To communicate one application—which we call “client”—
must call the other—the “server”—over the phone. Once
the connection is established, each peer can talk to the
other for the duration of the phone call.
96
Socket – Programming Model
UPD Client-Server
Datagram socket / mail analogy
To communicate applications send (snail)
mail messages to their peer mailboxes.
bind();
associate the IP address and port to socket descriptor
listen();
waiting for clients to connect to me
accept()
accepts connection from client
98
Socket – Server side API
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
Returns: 0 if OK, –1 on error
• The address we specify must be valid for the machine on which the process is running; we can't
specify an address belonging to some other machine.
• The address must match the format supported by the address family we used to create the socket.
• The port number in the address cannot be less than 1,024 unless the process has the appropriate
privilege (i.e., is the superuser).
• Usually, only one socket endpoint can be bound to a given address, although some protocols allow
duplicate bindings.
99
Socket – Server side API
#include <sys/socket.h>
int listen(int sockfd, int backlog);
Returns: 0 if OK, –1 on error
100
Socket – Server side API
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
Returns: file (socket) descriptor if OK, –1 on error
The newly created socket is no longer in the listening state. The original socket sockfd is unaffected by
this call and it remains available to receive additional connect requests.
101
Socket – Client side API
102
Socket – Client side API
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
Returns: 0 if OK, –1 on error
103
Socket – Common API
close connection
close();
shutdown();
104
Socket – In-Class Practice
mkdir socket/2
Copy the contents in attached file to
client.c and server.c
gcc –o server server.c client.c server.c
gcc –o client client.c
105
Socket – TCP state
closestudy1.pcap
106
Socket – I/O multiplexing
107
Socket – I/O multiplexing
int select (int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval
*timeout);
int pselect (int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct
timespec *timeout, const sigset_t *sigmask); //(POSIX select)
int poll (struct pollfd *fdarray, unsigned long ndfs, int timeout);
epoll
108
Socket – Summary
What is socket
Programming model
Socket API
I/O Multiplexing
109