Presentation is loading. Please wait.

Presentation is loading. Please wait.

Inter-Process Communication: Intro + Pipes

Similar presentations


Presentation on theme: "Inter-Process Communication: Intro + Pipes"— Presentation transcript:

1 Inter-Process Communication: Intro + Pipes

2 Communication between processes
Processes live in different “worlds”; memory address spaces due to virtual memory. Communication between processes is needed e.g. killing a process from a shell command e.g. sending data between processes Process A’s address space Process B’s address space

3 Inter-process Communication (IPC)
Cooperating processes or threads need inter-process communication (IPC) Data transfer Sharing data Event notification Resource sharing Process control Processes may be running on one or more computers connected by a network. The method of IPC used may vary based on the bandwidth and latency of communication between the threads, and the type of data being communicated. IPC may also be referred to as inter-application communication.

4 IPC mechanisms IPC mechanisms Signals Pipes Unnamed Pipes
Named Pipes of FIFOs Message Queues Shared Memory Memory Mapped Files Semaphores (later) Remote processes, over network: Remote Procedure Calls (RPC) Sockets (in network course)

5 IPC – (Unnamed) Pipes A byte-stream among processes. Bytes written by a process is readable by another process in the other end. Applications:  in shell passing output of one program to another program e.g. cat file1 file2 | sort Limitations: Processes need to be relatives (parent-child or siblings) cannot be used for broadcasting; Data in pipe is a byte stream – has no structure No way to distinguish between several readers or write Implementation: Internal kernel buffers, socket buffers or STREAM interface.

6 Pipes Pipe is a data structure in the kernel.
18/02/08 Pipes Pipe is a data structure in the kernel.  Data is stored in kernel buffers temporarily. No random access (seek) on pipes.  A pipe is created by using the pipe system call int pipe(int* fd); fd is an array of size 2  Two file descriptors are returned fd[0] is open for reading fd[1] is open for writing Some systems implement bidirectional pipes, both ends are readable/writable.  Typical buffer size is 512 bytes (Minimum limit defined by POSIX). Reads and writes may be blocked by the buffer. 

7 Pipes Typical use: A pipe provides a one-way flow of data
18/02/08 Pipes Typical use: Pipe created by a process Process calls fork() File descriptors are inherited by child, so pipe is shared with the child. Pipe used as a communication medium between parent and child A pipe provides a one-way flow of data example: who | sort| lpr output of who is input to sort output of sort is input to lpr

8 Pipe example #include <unistd.h> #include <stdio.h>
18/02/08 Pipe example #include <unistd.h> #include <stdio.h> int main(void){   int n;                // to keep track of num bytes read int fd[2]; // to hold fds of both ends of pipe pid_t pid; // pid of child process char line[80]; // buffer to hold text read/written if (pipe(fd) < 0)                    // create the pipe         perror("pipe error"); if ((pid = fork()) < 0) { // fork off a child         perror("fork error"); } else if (pid > 0) { // parent process close(fd[0]); // close read end         write(fd[1], "hello world\n", 12); // write to  it  }else { // child process close(fd[1]); // close write end         n = read(fd[0], line, 80);     // read from  pipe         write(1, line, n);              // echo  to  screen } exit(0);

9 as a result of pipe() call
After the fork() call Descriptor table For parent stdin fd 0 stdout fd 1 stderr fd 2 fd 3 fd 4 filedes[2] gets {3, 4} as a result of pipe() call

10 After the fork() call Descriptor table For parent Descriptor table
For child stdin fd 0 fd 0 stdin stdout fd 1 fd 1 stdout stderr fd 2 fd 2 stderr fd 3 fd 3 fd 4 fd 4

11 After the close() calls
Descriptor table For parent Descriptor table For child stdin fd 0 fd 0 stdin stdout fd 1 fd 1 stdout stderr fd 2 fd 2 stderr fd 3 X fd 3 fd 4 X fd 4 This pipe allows parent to send data to the child. If two way communication is needed, then the parent needs to create two pipes before fork() and use the second pipe as a second channel. Systems with bidirectional pipes can do it in single pipe. The other end does not get EOF if at least one process is keeping one end open. Always close the end that process will not use!

12 IPC – Unnamed Pipes Unnamed pipes in shell are used with redirection
cat myfile | grep key | sort | lpr Shell setups stdout of a child to pipe write, stdin of next one as pipe read   int fd[2], c;            // to hold fds of both ends of pipe   if (pipe(fd) < 0)  perror("pipe error"); // create the pipe   if (fork()) { if (fork()) {           // parent process          close(fd[0]); close(fd[1]);     // not going to use it         wait(&c); wait(&c);             // wait for both      } else {                       // pipe reader child         close(fd[1]);               // not using write end         dup2(fd[0],0);             // redirect stdin to read end         close(fd[0]);               // it is duplicated, close         execl("/usr/bin/wc","wc","-l",NULL); // run binary      }   } else {         close(fd[0]);           // not using read end          dup2(fd[1],1);         // redirect stdout to write end          close(fd[1]);           // it is duplicated, close          execl("/bin/cat","cat","/etc/passwd",NULL);// run binary    }

13 IPC - Named Pipes or FIFOs
Pipes are restricted to processes of same family (parent/child, siblings). Relies on file descriptor inheritance. FIFOs are pipes named as a path on the file system. They can be accessed by any process that “knows the name” Pipes are temporary. They disappear when last process closes. FIFOs or named pipes, are special files that persist even after all processes have closed them A FIFO has a name and permissions just like an ordinary file and appears in a directory listing Any process with the appropriate permissions can access a FIFO A user creates a FIFO by executing the mkfifo command from a command shell or by calling the mkfifo() system call within a program

14 FIFO Creation in shell FIFO are created using the mknod or the mkfifo commands mkfifo name mkfifo –m mode name mknod name p Make sure you remove (rm) your pipes after use! >man mknod mknod - make block or character special files mknod [OPTION]... NAME TYPE [MAJOR MINOR] …. Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they must be omitted when TYPE is p. …..... p create a FIFO >man mkfifo mkfifo -- make fifos mkfifo [-m mode] fifo_name ... mkfifo creates the fifos requested, in the order specified. By default, the resulting fifos have mode 0666 (rw-rw-rw-), limited by the current umask(2).

15 Using Named Pipes First, create your pipes
mkfifo pipe1 mkfifo pipe2 mkfifo pipe3 Then, attach a data source to your pipes ls -l >> pipe1 & cat myfile >> pipe2 & who >> pipe3 & Then, read from the pipes with your reader process cat < pipe1 | lpr spell < pipe2 sort < pipe3 Finally, delete your pipes rm pipe[1-3] Note: >> to append to pipe & for background execution

16 IPC – FIFO – mkfifo() system call
int mkfifo(const char *path, mode_t mode); The mkfifo() function creates a new FIFO special file corresponding to the path name specified in the path parameter The mode parameter specifies the permissions for the newly created FIFO If successful, the function returns zero; otherwise, it returns –1 and sets errno

17 Inter-Process Communication: Signals
Slides adapted from: Randy Bryant of Carnegie Mellon University

18 Signals A signal is a small message that notifies a process that an event of some type has occurred in the system Akin to exceptions and interrupts.  Sometimes called as software interrupts.  Interrupts: Hardware to OS, Signals: OS to processes Signal type is identified by small integer ID’s (1-30) Only information in a signal is its ID and the fact that it arrived Most of them causes termination but process can block, define a "handler" or ignore them (except SIGKILL and SIGSTOP).   

19 Signals ID Name Default Action Corresponding Event Thumbnail.
1 SIGHUP Terminate Terminal line close 2 SIGINT User typed ctrl-c  3 SIGQUIT Ctrl+ \ 4 SIGILL Illegal instruction on CPU 8 SIGFPE Floating point exception 9 SIGKILL Kill program (cannot override or ignore) 11 SIGSEGV Terminate  Segmentation violation 13 SIGPIPE Write on a closed pipe 14 SIGALRM User timer 15 SIGTERM Terminate process (can be overwritten) 17 SIGCHLD Ignore Child stopped or terminated 19 SIGSTOP Suspend Suspend process execution 18 SIGCONT Continue Continue suspended proces 10 12 SIGUSR1 SIGUSR2 User defined  Thumbnail. Thumbnail.

20 Signal Concepts: Sending a Signal
Kernel sends (delivers) a signal to a destination process by updating some state in the context of the destination process Signals can be initiated by: Hardware event, interrupt: SIGFPE, SIGSEGV, SIGILL.  OS event: SIGPIPE, SIGHUP, SIGCHLD, SIGALRM, User input Process request: kill() system call PCB stores signal delivery status and setup for a process. Each is a bitmap, a bit per signal: Pending: Signal is sent to the process, waiting to be delivered Block:  Delivery of signal is to be blocked by the process

21 Signal Concepts: Sending a Signal
Process B User level Process A Process C kernel Pending for A Blocked for A Pending for B Blocked for B Pending for C Blocked for C

22 Signal Concepts: Sending a Signal
Process B User level Process A Process C kill(C,signal) kernel Pending for A Blocked for A Pending for B Blocked for B Pending for C Blocked for C

23 Signal Concepts: Sending a Signal
Process B User level Process A Process C kernel Pending for A Blocked for A Pending for B Blocked for B Pending for C 1 Blocked for C

24 Signal Concepts: Sending a Signal
Process B User level Process A Process C kernel Received by C Pending for A Blocked for A Pending for B Blocked for B Pending for C 1 Blocked for C

25 Signal Concepts: Sending a Signal
Process B User level Process A Process C kernel Pending for A Blocked for A Pending for B Blocked for B Pending for C Blocked for C

26 Signal Concepts: Receiving a Signal
A destination process receives a signal when it is forced by the kernel to react in some way to the delivery of the signal Some possible ways to react: Ignore the signal (do nothing) Terminate the process (with optional core dump) Catch the signal by executing a user-level function called signal handler Akin to a hardware exception handler being called in response to an asynchronous interrupt: (1) Signal received by process (2) Control passes to signal handler Icurr Inext (3) Signal handler runs (4) Signal handler returns to next instruction

27 Signal Concepts: Pending and Blocked Signals
A signal is pending if sent but not yet received There can be at most one pending signal of any particular type Important: Signals are not queued If a process has a pending signal of type k, then subsequent signals of type k that are sent to that process are discarded A process can block the receipt of certain signals Blocked signals can be delivered, but will not be received until the signal is unblocked A pending signal is received at most once

28 Signal Concepts: Pending/Blocked Bits
Kernel maintains pending and blocked bit vectors in the context of each process pending: represents the set of pending signals Kernel sets bit k in pending when a signal of type k is delivered Kernel clears bit k in pending when a signal of type k is received  blocked: represents the set of blocked signals Can be set and cleared by using the sigprocmask function Also referred to as the signal mask.

29 Signal Concepts: Sending a Signal
Process B User level Process A Process C Sends to C kernel Pending for A Blocked for A Pending for B Blocked for B Pending for C 1 Blocked for C

30 Sending Signals: Process Groups
Every process belongs to exactly one process group Shell pid=10 pgid=10 Fore- ground job Back- ground job #1 Back- ground job #2 pid=20 pgid=20 pid=32 pgid=32 pid=40 pgid=40 Background process group 32 Background process group 40 Child Child getpgrp() Return process group of current process setpgid() Change process group of a process (see text for details) pid=21 pgid=20 pid=22 pgid=20 Foreground process group 20

31 Sending Signals with /bin/kill Program
/bin/kill program sends arbitrary signal to a process or process group Examples /bin/kill – Send SIGKILL to process 24818 /bin/kill –9 –24817 Send SIGKILL to every process in process group 24817 linux> ./forks 16 Child1: pid=24818 pgrp=24817 Child2: pid=24819 pgrp=24817 linux> ps PID TTY TIME CMD 24788 pts/ :00:00 tcsh 24818 pts/ :00:02 forks 24819 pts/ :00:02 forks 24820 pts/ :00:00 ps linux> /bin/kill 24823 pts/ :00:00 ps linux> ./delay 100 & ps kill -9 XXX

32 Sending Signals from the Keyboard
Typing ctrl-c (ctrl-z) causes the kernel to send a SIGINT (SIGTSTP) to every job in the foreground process group. SIGINT – default action is to terminate each process SIGTSTP – default action is to stop (suspend) each process Shell pid=10 pgid=10 Fore- ground job Back- ground job #1 Back- ground job #2 pid=20 pgid=20 pid=32 pgid=32 pid=40 pgid=40 Background process group 32 Background process group 40 Child Child pid=21 pgid=20 pid=22 pgid=20 Foreground process group 20

33 Example of ctrl-c and ctrl-z
STAT (process state) Legend: First letter: S: sleeping T: stopped R: running Second letter: s: session leader +: foreground proc group See “man ps” for more details bluefish> ./forks 17 Child: pid=28108 pgrp=28107 Parent: pid=28107 pgrp=28107 <types ctrl-z> Suspended bluefish> ps w PID TTY STAT TIME COMMAND 27699 pts/8 Ss 0:00 -tcsh 28107 pts/8 T :01 ./forks 17 28108 pts/8 T :01 ./forks 17 28109 pts/8 R :00 ps w bluefish> fg ./forks 17 <types ctrl-c> 28110 pts/8 R :00 ps w Can also use kill command: ./forks 17 & kill (parent) (Only kills parent) kill (child) (Child becomes a zombie)

34 Sending Signals with kill Function
void fork12() { pid_t pid[N]; int i; int child_status; for (i = 0; i < N; i++) if ((pid[i] = fork()) == 0) { /* Child: Infinite Loop */ while(1) ; } for (i = 0; i < N; i++) { printf("Killing process %d\n", pid[i]); kill(pid[i], SIGINT); pid_t wpid = wait(&child_status); if (WIFEXITED(child_status)) printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status)); else printf("Child %d terminated abnormally\n", wpid); Interesting to use interpositioning code from previous lecture setenv LD_PRELOAD ../13-ecf-procs/myfork.so setenv CHILD ./forks 12 forks.c

35 Receiving Signals Suppose kernel is returning from an exception handler and is ready to pass control to process p Process A Process B user code kernel code context switch Time user code kernel code context switch user code

36 Receiving Signals Suppose kernel is returning from an exception handler and is ready to pass control to process p Kernel computes pnb = pending & ~blocked The set of pending nonblocked signals for process p If (pnb == 0) Pass control to next instruction in the logical flow for p Else Choose least nonzero bit k in pnb and force process p to receive signal k The receipt of the signal triggers some action by p Repeat for all nonzero k in pnb Pass control to next instruction in logical flow for p

37 Default Actions Each signal type has a predefined default action, which is one of: The process terminates The process stops until restarted by a SIGCONT signal The process ignores the signal

38 Installing Signal Handlers
The signal function modifies the default action associated with the receipt of signal signum: handler_t *signal(int signum, handler_t *handler) Different values for handler: SIG_IGN: ignore signals of type signum SIG_DFL: revert to the default action on receipt of signals of type signum Otherwise, handler is the address of a user-level signal handler Called when process receives signal of type signum Referred to as “installing” the handler Executing handler is called “catching” or “handling” the signal When the handler executes its return statement, control passes back to instruction in the control flow of the process that was interrupted by receipt of the signal

39 Signal Handling Example
void sigint_handler(int sig) /* SIGINT handler */ { printf("So you think you can stop the bomb with ctrl-c, do you?\n"); sleep(2); printf("Well..."); fflush(stdout); sleep(1); printf("OK. :-)\n"); exit(0); } int main(int argc, char** argv) /* Install the SIGINT handler */ if (signal(SIGINT, sigint_handler) == SIG_ERR) unix_error("signal error"); /* Wait for the receipt of a signal */ pause(); return 0; Try running: ./sigint ctrl-C Code not entirely reliable, if there’s a delay in pause sigint.c

40 Signal Handler Usually works in same stack. Kernel pushes handler activation on stack. User mode Kernel mode User mode locals param IPcur Process stack is modified as a call to handler function SP and IP registers are modified SP Handler Returns SP SP IP: IPcur IP: handleraddr IP: IPcur Signal raised Return

41 Nested Signal Handlers
Handlers can be interrupted by other handlers Main program Handler S Handler T (2) Control passes to handler S (1) Program catches signal s Icurr (4) Control passes to handler T (3) Program catches signal t Inext (7) Main program resumes (5) Handler T returns to handler S (6) Handler S returns to main program

42 Blocking and Unblocking Signals
Implicit blocking mechanism Kernel blocks any pending signals of type currently being handled. E.g., A SIGINT handler can’t be interrupted by another SIGINT Explicit blocking and unblocking mechanism sigprocmask function Supporting functions sigemptyset – Create empty set sigfillset – Add every signal number to set sigaddset – Add signal number to set sigdelset – Delete signal number from set

43 Safe Signal Handling Handlers are tricky because they are concurrent with main program and share the same global data structures. Shared data structures can become corrupted. Pending signals are not queued For each signal type, one bit indicates whether or not signal is pending… …thus at most one pending signal of any particular type. You can’t use signals to count events, such as children terminating. Waiting for Signals int sigsuspend(const sigset_t *mask)

44 Inter-Process Communication: Shared memory

45 IPC- Shared Memory Allows multiple processes to share virtual memory space. Fastest but not necessarily the easiest (synchronization-wise) way for processes to communicate with one another. Process A Process B Shared memory region 0x30000 0x50000 0x50000 0x70000

46 IPC- Shared Memory One process creates or allocates the shared memory segment. size and access permissions set at creation. The process then attaches the shared segment, causing it to be mapped into its current data space. If needed, the creating process then initializes the shared memory. Once created, and if permissions permit, other processes can gain access to the shared memory segment and map it into their data space. Each process accesses the shared memory relative to its attachment address. For each process involved, the mapped memory appears to be no different from any other of its memory addresses.

47 POSIX Shared Memory Process A Process B Create shared memory segment
segment id = shmget(key, size, IPC_CREAT); Attach shared memory to its address space addr= (char *) shmat(id, NULL, 0); write to the shared memory *addr = 1; Detach shared memory shmdt(addr); Process B Use existing segment (same key, no IPC_CREAT) segment id = shmget(key, size, 0666); addr = (char *) shmat(id, NULL, 0); c = *addr;

48 Example: Producer-Consumer Problem
Producer process produces information that is consumed by a consumer process e.g. print utility places data and printer fetches data to print.

49 Server code for producer
main() { char c; int shmid; key_t key=5678; char *shm, *s; /* Create the segment. */ if ((shmid = shmget(key, 27, IPC_CREAT | 0666)) < 0) { printf("server: shmget error\n"); exit(1); } /* Attach the segment to our data space. */ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { printf("server: shmat error\n"); /* Output data*/ s = shm; for (c = 'a'; c <= 'z'; c++) *s++ = c; /* Wait the client consumer to respond*/ while (*shm != '*') sleep(1); shmdt(shm); exit(0);

50 Client code for consumer
main(){ int shmid; key_t key=5678; char *shm, *s; /* Locate the segment. */ if ((shmid = shmget(key, SHMSZ, 0666)) < 0) { printf("client: shmget error\n"); exit(1); } /* attach the segment to our data space.*/ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { printf("client: shmat error\n"); exit(1); /* Read what the server put in the memory, and display them*/ for (s = shm; *s != ‘z’; s++) putchar(*s); putchar('\n'); /* Finally, change the first character of the segment to '*‘ */ *shm = '*'; exit(0);

51 Shared memory example: Currency Exchange
enum currency {DOLLAR , EURO, STERLIN, POUND}; struct Currency {double sell, buy; double stock;}; int buy(struct Currency *c, double amount, double *balance) { if (*balance < amount*c->buy) return -1; *balance -= amount*c->buy; c->stock += amount; return 0; } int sell(struct Currency *c, double amount, double *balance) { if (c->stock < amount) return -1; *balance += amount*c->sell; c->stock -= amount;

52 Shared memory example: Currency Exchange
A shared memory segment keeps currency values sell and buy, and current stock. Processes attach it and make exchange operations based on user input Shared Mem Process DOLLAR Sell 3.72 Buy 3.71 Stock 10000 EURO ….. …. Buy/Sell Buy/Sell Process Buy/Sell Process

53 Currency exchange - 1 #include "exchange.h”
struct Currency init[4] ={ {3.73, 3.72, 10000}, {3.932, 3.944, 10000}, {4.551,4.552, 10000}, {3.24, 3.25, 5000}}; struct Currency *curshared; int main() { int key, i; // create a shared memory for 4 Currency structures key = shmget(EXCHKEY, sizeof(struct Currency)*4, IPC_CREAT|0600); if (key < 0) { perror("shmget") ; return 1;} // attach it and get result in curshared pointer curshared = (struct Currency *) shmat( key, NULL, 0); for (i = 0; i < 4; i++) curshared[i] = init[i]; shmdt((void *) curshared); return 0; }

54 Currency exchange - 2 #include<exchange.h> struct Currency *curshared; double balance = 1000; // initial balance int main() { // get key for already created shmem key = shmget(EXCHKEY, sizeof(struct Currency)*4, 0); if (key < 0) { perror("shmget") ; return 1; } // attach shared memory and get address in curshared curshared = (struct Currency *) shmat( key, NULL, 0); if (curshared == NULL) return -1; while (fgets(line, 80, stdin)) { // trade loop // assume input is parsed here if (... “buy” ) buy(curshared+c , amount, &balance); if (… “sell”) sell(curshared+c , amount, &balance); } shmdt((void *) curshared); return 0;

55 Generating a common key..
key_t ftok(const char *path, int id); The ftok() function shall return a key based on path and id that is usable in subsequent calls to msgget(), semget(), and shmget(). The ftok() function shall return the same key value for all paths that name the same file, when called with the same id value. Only the low-order 8-bits of id are significant. The behavior of ftok() is unspecified if these bits are 0.

56 IPC - Shared memory Advantages Limitation Alternative
good for sharing large amount of data very fast, Limitation no synchronization provided. i.e. wait for data to be available from other process. Integrity of shared variables may be violated. i.e negative stock on a currency. (to be covered in Synchronization chapter) applications must use other synchronization mechanisms. Persistent until reboot. Needs cleanup. Alternative mmap() system call, which maps file into the address space of the caller,

57 IPC- mmap() using a File as Shared Memory
mmap() is used to map a file to a process's virtual memory address space. More flexible than shared memory, file and memory based access work together. Once a mapping has been established, file can be manipulated by updating memory instead of file system calls like open()/read()/write()/lseek()… Unlike shared memory, the contents of a file are nonvolatile and will remain available even after a system has been shut down (and rebooted).

58 Using a File as Shared Memory
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); start is the address for attachment. mostly set to 0, which directs the system to choose a valid attachment address. length: The number of bytes to be attached. File size should be less than or equal to this. prot: used to set the type of access (protection) for the segment. Flags: MAP_SHARED for a shared mapping. Otherwise isolated. fd: open file descriptor. Once the mapping is established, the file can be closed. offset: set the starting position for the mapping. If successful, returns a reference to the mapped memory object. else returns MAP_FAILED which is actually the value -1 cast to a void *. int munmap(void *start, size_t length); Called automatically when the process quits.

59 Writing to a file through mmap()
#include<exchange.h> struct Currency *curshared; double balance = 1000; // initial balance int main() { fd = open("exchange.dat", O_RDWR | O_CREAT, 0600); if (fd < 0) { perror("open") ; return 1; } // map file as part of memory as a shared segment curshared = (struct Currency *) mmap(NULL, 4*sizeof(struct Currency), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (curshared == 0) { perror("mmap"); return -1;} close(fd); // you can close the file afterwards if (curshared == NULL) return -1; while (fgets(line, 80, stdin)) { // trade loop // assume input is parsed here if (... “buy” ) buy(curshared+c , amount, &balance); if (… “sell”) sell(curshared+c , amount, &balance); } // delete the mapping munmap(curshared, 4*sizeof(struct Currency)); return 0;

60 Reading from a file through mmap()
#define NUMINTS (1000) #define FILESIZE (NUMINTS * sizeof(int)) int main(int argc, char *argv[]) { int i,fd, result; int *map; /* mmapped array of int's */ fd = open("/tmp/j", O_RDONLY); map = mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fd, 0); /* Read the file int-by-int from the mmap */ for (i = 1; i <=NUMINTS; ++i) printf("%d: %d\n", i, map[i]); result = munmap(map, FILESIZE) close(fd); return 0; }

61 Inter-Process Communication: Message queues, sockets, remote procedure calls

62 Message sending with named pipes
#include <stdio.h> #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> void child(char *path) {     int fd;     char buf[] = " ";     fd = open(path, O_WRONLY);     write(fd, buf, sizeof(buf));     printf("Child send: %s\n", buf);     close(fd); } void parent(char *path)     char buf[512];     fd = open(path, O_RDONLY);     read(fd, buf, sizeof(buf));     printf("Parent receive: %s\n", buf); int main() {     char *path = "/tmp/fifo";     pid_t pid;     setlinebuf(stdout);     unlink(path);     mkfifo(path, 0600);     pid = fork();     if (pid == 0) {         child(path);     } else {         parent(path);     }     return 0; } Parent receive: Child send:

63 IPC - Message Queues The sending process places via some (OS) message-passing module a message onto a queue which can be read by another process. Each message is given an identification or type so that processes can select the appropriate message. Process must share a common key in order to gain access to the queue in the first place Sender Process Receiver Process msgsnd(0xa01, *msgp, 0) msgrcv(0xa01, *buf, 0, 0) KERNEL Queue 0xa01 msgsnd msgrcv insert remove Messages: explicit length, different types.

64 IPC - Message Queues Before a process can send or receive a message, the queue must be initialized through the msgget(). Operations to send and receive messages are performed by the msgsnd() and msgrcv() functions, respectively. In non-blocking message passing allow for asynchronous message transfer the process is not suspended as a result of sending or receiving a message. In blocking or synchronous message passing the sending process blocks until the message has been transferred or has even been acknowledged by a receiver.

65 Message sending #define MSGSZ 128
typedef struct msgbuf { /*msg structure */ long mtype; char mtext[MSGSZ]; } message_buf; main(){ int result, msgid, msgflg = IPC_CREAT | 0666; key_t key; message_buf sbuf; size_t buf_length; key = 1234; msqid = msgget(key, msgflg); sbuf.mtype = 1; /*send a msg of type 1 */ strcpy(sbuf.mtext, "Did you get this?"); buf_length = strlen(sbuf.mtext) + 1 ; /* send msg */ result = msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT); printf("Message: \"%s\" Sent\n", sbuf.mtext); exit(0); }

66 Message receiving #define MSGSZ typedef struct msgbuf { /* msg struct */ long mtype; char mtext[MSGSZ]; } message_buf; main(){ int msqid; key_t key; message_buf rbuf; key = 1234; msqid = msgget(key, 0666); /* receive msg */ result = msgrcv(msqid, &rbuf, MSGSZ, 1, 0); /* print msg */ printf("%s\n", rbuf.mtext); exit(0); } The Message queue is opened with msgget (message flag 0666) and the same key as message_send.c. A message of the same type 1 is received from the queue with the message ``Did you get this?'' stored in rbuf.mtext.

67 Discussion of message queues
Msgq are more versatile than pipes and address some of their limitations, Can transmit msgs as structured entities You don’t have to worry about a partial message being sent/received. The transfer is atomic. 3 basic modes in msgrcv() defining type parameter: Any type (FIFO) if type parameter is 0 Specific message type, type parametter > 0 Minimum typed message (like priority), a negative value as absolute value as the upper limit Msg type can be used to specify e.g. priorities, urgency, designate recipient, Kernel does not help with recipient specification, Cannot broadcast msg’s,

68 IPC - Sockets Sockets provide point-to-point, two-way communication between two processes. A socket is an endpoint of communication to which a name can be bound. It has a type and one or more associated processes. Sockets exist in communication domains. A socket domain is an abstraction that provides an addressing structure and standard interface for communication Socket domains define and implement underlying complex protocol where socket interface is simple and uniform. Some common domains: UNIX, INET, INET6, IPX, NETLINK, X25, AX25, APPLETALK, ATMPVC The UNIX domain provides a socket address space on a single system. UNIX domain sockets are named with UNIX paths. can be used to communicate between processes on a single system. Sockets can also be used to communicate between processes on different systems. The socket address space between connected systems is called the Internet domain. Internet domain communication uses the TCP/IP internet protocol suite.

69 Socket types Define the communication properties visible to the application. A stream socket (similar to making a phone call) Phone. Delivery in a networked environment is guaranteed. If you send through the stream socket three items "A, B, C", they will arrive in the same order − "A, B, C". These sockets use TCP for data transmission. A datagram socket (similar to sending a mail) Delivery in a networked environment is not guaranteed. They're connectionless because you don't need to have an open connection as in Stream Sockets − you build a packet with the destination information and send it out. They use UDP. Delivery and order of delivery is not guaranteed. A sequential packet socket They are similar to a stream socket, with the exception that record boundaries are preserved. A raw socket provides access to the underlying communication protocols.

70 Some system calls in the socket interface:
More to come in Ceng 445 Computer Networking System Call Description socket(family, type, flags) Create a socket with given family and type bind(socket, sockaddr, addrlen) Bind socket to an address listen(socket, queuelen) Listen requests coming from socket accept(socket, peeraddr, addrlen) Accept next connection on listened socket connect(socket, destaddr, addrlen) Connect to a socket given in address send(socket, buffer, size, flags) Send data to a socket recv(socket, buffer, bufsize, flags) Receive data from socket

71 Socket creation and naming
int socket(int domain, int type, int protocol) Domain: AF_INET | AF_UNIX | … Type: SOCK_STREAM | SOCK_DGRA | … In the UNIX domain, a connection is usually composed of one or two path names. In the Internet domain, a connection is composed of local and remote addresses and local and remote ports.

72 Server steps Create a socket with the socket() system call.
Bind the socket to an address using the bind() system call. For a server socket on the Internet, an address consists of a port number on the host machine. Listen for connections with the listen() system call, which specifies how many connection requests can be queued Accept a connection with the accept() system call. This call typically blocks until a client connects with the server. Send and receive data using the read() and write() system calls. snd() and rcv() system calls.

73 Client steps Create a socket with the socket() system call.
Connect the socket to the address of the server using the connect() system call. Send and receive data. There are a number of ways to do this, but the simplest way is to use the read() and write() system calls.

74 Socket server - UNIX #define ADDRESS "mysocket" /* addr to connect */
char *strs = "This is the string from the server.\n"; main(){ char c; FILE *fp;int fromlen; register int i, s, ns, len; struct sockaddr_un saun, fsaun; /* create a UNIX domain stream socket */ s = socket(AF_UNIX, SOCK_STREAM, 0)) saun.sun_family = AF_UNIX; strcpy(saun.sun_path, ADDRESS); unlink(ADDRESS); /*unlink (rm) ADDRESS to bind won’t fail */ len = sizeof(saun.sun_family) + strlen(saun.sun_path); result = bind(s, &saun, len);/*bind the address to the socket */ result = listen(s, 5); /* listen on the socket */ ns = accept(s, &fsaun, &fromlen)) /* Accept a connection */ fp = fdopen(ns, "r"); /* open the connection */ /* send the string to the client */ send(ns, strs, strlen(strs), 0); /* read from the server */ while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == '\n’) break; } close(s); exit(0);

75 Socket client - UNIX #define ADDRESS "mysocket" /* addr to connect */
char *strs = "This is the first string from the client.\n"; main(){ char c; FILE *fp; register int i, s, len; struct sockaddr_un saun; /* create a UNIX domain stream socket */ s = socket(AF_UNIX, SOCK_STREAM, 0); saun.sun_family = AF_UNIX; strcpy(saun.sun_path, ADDRESS); len = sizeof(saun.sun_family) + strlen(saun.sun_path); result= connect(s, &saun, len); fp = fdopen(s, "r"); /* read from the server */ while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == '\n') break; } /* Now we send some strings to the server.*/ send(s, strs, strlen(strs), 0); close(s); exit(0);

76 IPC Summary Signal: Signal sends an integer to another process. Doesn't mix well with multi-threads. Pipe: Useful only among processes related as parent/child. Unidirectional. FIFO, or named pipe: Two unrelated processes can use FIFO unlike plain pipe. Unidirectional. Shared memory: Do your own concurrency control. Message Queue: OS maintains discrete message. Sockets: Bidirectional. Meant for network communication, but can be used locally too. Can be used for different protocol. There's no message boundary for TCP. Semaphore: A synchronization mechanism for multi processes or threads, similar to a queue of people waiting for bathroom.

77 Other issues.. Message boundary issue: Performance
Byte streams (e.g. Pipes and TCP sockets) the client sends "Hello", "Hello", and "How about an answer?” The server can receive as "Hell", "oHelloHow", and " about an answer?"; or more realistically "HelloHelloHow about an answer?". No clue where the message boundary is. Fix: Limit the message length Performance Pipe I/O: fastest Msg queues: slower Sockets: slowest [at most half as slow in latency and bandwidth] Portability. Can also be used for communication with processes on the same machine.

78 IPC support provided by OS or other envs.

79 IPC - Remote Procedure Calls (RPCs)
Host A Host B An RPC is analogous to a function call. Caller and process executing the instruction are separate processes, possibly on different computers. Various applications like: A desktop server providing interaction of various components of a desktop A file system server providing file system services over network. A cluster of computers working in parallel for a computation. When an RPC is made, the calling arguments are passed to the remote procedure and the caller waits for a response to be returned from the remote procedure. Mostly implemented by user space libraries and services. Examples: Sun RPC, DBUS, CORBA, DCOM, WCF, JRMI, MPI, XMLRPC, JSONRPC, SOAP,..... Client call int f(int a[]) RPC library packing, marshalling Send request over Network Accept requests RPC library unmarshall, unpack Server native f() call returns val packing, marshalling return value Send result Get result unmarshall, unpack f() returns to caller

80 Sequence of events during a RPC
The client calls the client stub. The call is a local procedure call, with parameters pushed on to the stack in the normal way. The client stub packs the parameters into a message and makes a system call to send the message. Packing the parameters is called marshalling. The client's local operating system sends the message from the client machine to the server machine. The local operating system on the server machine passes the incoming packets to the server stub. The server stub unpacks the parameters from the message . Unpacking the parameters is called unmarshalling. Finally, the server stub calls the server procedure. The reply traces the same steps in the reverse direction.

81 Differences between using local and remote procedure calls
Remote calls can fail because of unpredictable network problems. Also, callers generally must deal with such failures without knowing whether the remote procedure was actually invoked. Idempotent procedures (those that have no additional effects if called more than once) are easily handled, but enough difficulties remain that code to call remote procedures is often confined to carefully written low-level subsystems.

82 Interface Description Language
To let different clients access servers, a number of standardized RPC systems have been created. Most of these use an interface description language (IDL) to let various platforms call the RPC. The IDL files can then be used to generate code to interface between the client and server. The most common tool used for this is RPCGEN.

83 More info and details available at
Programming in C UNIX System Calls and Subroutines using C. A. D. Marshall The Linux Programmer's Guide by Sven Goldt, Sven van der Meer, Scott Burkett, Matt Welsh

84 Pipes Process A’s address space Process B’s address User Space Kernel

85 Signals Process A’s address space Process B’s address User Space
Kernel Space 1 2 3 4 5 6 7 8

86 Shared memory Process B’s address space Process A’s address space User
Kernel Space

87


Download ppt "Inter-Process Communication: Intro + Pipes"

Similar presentations


Ads by Google