Nov. 3, 2015 Kyu Ho Park Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Schedule of Lectures, Projects and Homeworks Lecture 9 HW#3 Lecture 10 HW#3 Due Lecture 11 Project 4 Lecture 12 HW#4 Project 3 Due Day Schedule of Lectures, Projects and Homeworks Lecture 13 Project 4 Due Day Project 5 HW#4 Due Day Tutorial for Project5 final exam. week Project 5 Due Day IPC in Linux Pipe(FIFO File) Signal Semaphore Shared memory Message queues $command1 | command2 Standard output Keyboard pipe command 1 Standard input command 2 screen Pipe #include <unistd.h> int pipe(int filedes[2]); - filedes: file descriptors, filedes[0] for reading , filedes[1] for writing. - return value: 0 when successful, -1 when failed. Characteristics of PIPE If the pipe is empty, the reading process is blocked to sleep. If there is a blocked process for read, writing to the pipe wakes up the reader process. Therefore pipe has two functions, ( ?) and ( ?). pipe #include <stdio.h> #include <unistd.h> #include <stdlib.h> close(fd_in); close(fd[1]); exit(0); } void error_exit(char * message); else { close(fd[1]); fd_out = creat("output",0666); if(fd_out ==-1) error_exit("creat"); int main(void) { int fd[2]; int fd_in, fd_out; int n; char buf[10]="message"; while((n=read(fd[0], buf, 10)) !=0) write(fd_out, buf,n); close(fd_out); close(fd[0]); wait(); if( pipe(fd) == -1) exit(1); } if( fork()==0) { fd_in=open("input",0); if(fd_in ==-1) exit(1); close(fd[0]); while( (n=read(fd_in,buf, 10)) !=0) write(fd[1], buf, n); return 0; } void error_exit(char *message) { fprintf(stderr, "%s\n", message); exit(-1); } root@ubuntu:~/Test/FIFO# ./pipecopy < input >output root@ubuntu:~/Test/FIFO# more output HelloAgain! fd[1] input buf Child process fd[0] Pipe buf Parent process output Named Pipe: FIFO #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); - pathname: FIFO path name, - mode: FIFO file access permission, - return value: 0 if successul, -1 if failed. FIFO is a special file and its function is nearly the same as the pipe. The pipe is a communication channel without any name but FIFO is registered special file by mkfifo systemcall. FIFO example #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> int main() { int res = mkfifo(“/home/kpark/my_fifo”, 0777); if( res ==0) printf( “FIFO is created\n”); exit(1); } Read and write using FIFO read_fifo.c #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #define MSGSIZE 64 main() { char msg[MSGSIZE]; int filedes; int nread, cnt; if(mkfifo("./fifo", 0666) == -1) { printf("fail to call fifo()\n"); exit(1); } if((filedes = open("./fifo", O_RDWR)) < 0) { printf("fail to call fifo()\n"); exit(1); } for(cnt = 0; cnt < 3; cnt++) { if((nread = read(filedes, msg, MSGSIZE)) < 0) { printf("fail to call read()\n"); exit(1); } printf("recv: %s\n", msg); } unlink("./fifo"); } write_fifo.c #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #define MSGSIZE 64 main() { char msg[MSGSIZE]; int filedes; int cnt; if((filedes = open("./fifo", O_WRONLY)) < 0) { printf("fail to call open()\n"); exit(1); } for(cnt = 0; cnt < 3; cnt++) { printf("input a message: "); scanf("%s", msg); if(write(filedes, msg, MSGSIZE) == -1) { printf("fail to call write()\n"); exit(1); } sleep(1); } } Embedded Software 2015. 9.1 Kyu Ho Park CORE Lab. Signals SIGNALS 14 signals Signals are software interrupt and provide a basic method of interprocess communication. The generation of a signal is occurred by some error conditions(memory segment violations, floating-point processor errors) and illegal instructions. 15 Signal sending Two functions for raising signals: #include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); int raise(int sig); kill( ) can send any signal to any process group or process. raise() is used for a process to send a signal to itself. It is equivalent to kill(getpid(), sig). 16 kill() process selection When 17 pid > 0 :signal sent to process with proc_id = pid. pid = 0 :sent to all processes whose process group id is the same as the sender for whom the sender has permission. pid < -1 : sent to all processes whose process group id is the absoluter value of pid and for whom the sender has permission. pid = -1: sent to every process except for the first one , from higher numbers in the process table to lower. 18 Alarm, pause and sleep #include <unistd.h> unsigned int alarm(unsigned int seconds); /*After the expiration of an assigned time, it sends SIGALARM to itself */ #include <unistd.h> int pause(void); /*pause until a signal received, return value is always -1 */ unsigned int sleep(unsigned int seconds); 19 sigPause.c 20 Signal handler #include <signal.h> (void) signal(SIGINT, handler ); The signal handler is set to handler() which may be a user specified function or one of {SIG_IGN, SIG_DFL}. 21 22 Typical Signal Handling 1. 2. 3. 4. 5. #include <signal.h> #include <stdio.h> #include <unistd.h> void handler(int sig) { printf(“I received a signal %d\n”, sig);} 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. int main() { struct sigaction act; sigemptyset(&act.sa_mask); act.sa_handler=handler; sigaction(SIGINT,&act,0); while(1) { printf(“Hello EE516!\n”); sleep(1); } } 23 struct sigaction{ void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; } sigfillset(),sigemptyset() ,sigaddset(), sigdelset(),and sigismember() #include <signal.h> int sigfillset(sigset_t *set); //fill the set with all signals. int sigemptyset(sigset_t *set); //empty the set. int sigaddset(sigset_t *set, int signum);//signum is the signal number sigaction( ) #include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); /* act: action to do for the signal . oldact: previously determined action for the signal, normally set to */ struct sigaction{ void (*sa_handler)(int);//function, SIG_DFL, or SIG_IGN void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; //signals to block in sa_handler int sa_flags; //signal action modifiers } NULL. sigprocmask( ) #include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); /* how={SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK} */ Semaphore Synchronization with semaphores Two set of functions for sepaphore: - POSIX semaphore functions for threads, - System V semaphore functions for processes. POSIX semaphore #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); - sem: points to a semaphore object, pshared: if 0, the semaphore is local to the current process, else the semaphore may be shared between processes(Linux does not support it). value: initial value of the semaphore. int sem_wait(sem_t *sem); -This function waits until the semaphore is nonzero, and decreases the value of semaphore by 1. int sem_post(sem_t *sem); -This function increases the value of the semaphore by 1. int sem_destroy(sem_t *sem); 30 System V semaphore Semaphore Definition: P(sem) : If sem is greater than 0, decrement sem, If sem is zero, suspend execution of this process. V(sem) : If some other process has been suspended waiting for sem, make it resume execution. If no process is suspended waiting for sem, increment sem. // sem = semmaphore variable. semget( ) #include <sys/sem.h> int semget(key_t key, int num_sems, int sem_flags); key: an integer value used to allow unrelated processes to access the same semaphore. The key is used only with semget. All other semaphore functions use the semaphore identifier(sem_id) returned from semget. num_sems: the number of semaphores. sem_flags: IPC_CREAT | IPC_EXCL return value: positive integer which is the semaphore identifier, -1 on error. semop() int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops); This function is used for changing the value of the semaphore. sem_id: the value returned from semget. sem_ops: a pointer to an array of structure sembuf as below struct sembuf { short sem_num; // 0 usually short sem_op; // -1 for P operation, +1 for V // operation. short sem_flg; //usually SEM_UNDO } semctl( ) int semctl(int sem_id, int sem_num, int command, ..); This function allows direct control of semaphore information. command: To remove the semaphore set, cmd should be set to IPC_RMID. In this case sem_num and arg have no meaning. To initialize a semaphore to a known value, cmd should be set to SETVAL. semctl(semid, 0, IPC_RMID, dummy); set_semaphore example /* The function set_semvalue initializes the semaphore using the SETVAL command in a semctl call. We need to do this before we can use the semaphore. */ static int set_semvalue(void) { union semun sem_union; sem_union.val = 1; if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0); return(1); } del_semaphre example /* The del_semvalue function has almost the same form, except the call to semctl uses the command IPC_RMID to remove the semaphore's ID. */ static void del_semvalue(void) { union semun sem_union; if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1) fprintf(stderr, "Failed to delete semaphore\n"); } semaphore_p example /* semaphore_p changes the semaphore by -1 (waiting). */ static int semaphore_p(void) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; /* P() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_p failed\n"); return(0); } return(1); } semaphore_v example /* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1, so that the semaphore becomes available. */ static int semaphore_v(void) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; /* V() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_v failed\n"); return(0); } return(1); } semun.h #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including <sys/sem.h> */ #else /* according to X/OPEN we have to define it ourselves */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ }; #endif Homework #3 At the last part of the printed handout ‘System V IPC(Semaphore), there are three sample programs seminit.c, semdemo.c, and semrm.c. Task 1: analyze those three programs and explain the behavior of each program and their expected output of each programs. Task 2: make run those programs suggested at the section ‘Sample programs’ and show each output of those programs. Due: Nov.10, 23:59. Other guidelines are the same as the previous homeworks. Submit it to Joo Kyung Ro, eu8198@kaist.ac.kr) Supplement to IPC: 41 Interprocess Communication Processes: Independent Processes or Cooperating Processes IPC issues: 1. How one process can pass information to another. 2. Mutual Exclusion. 3. Proper sequencing when dependencies are present. 42 42 Interprocess Communication(IPC) Message Passing process A Shared Memory M process A 1 process B shared M process B 2 kernel M 1 kernel 2 Producer-Consumer Problem Paradigm for cooperating processes, producer process produces information that is consumed by a consumer process unbounded-buffer places no practical limit on the size of the buffer bounded-buffer assumes that there is a fixed buffer size 44 Message Passing (1) Figure 2-17. The producer-consumer problem with N messages. ... ... Message Passing (2) Figure 2-17. The producer-consumer problem with N messages. Message Passing Message system – processes communicate with each other without resorting to shared variables Message passing 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) 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? 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 bi-directional 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 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 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. Synchronization Message passing may be either blocking or non-blocking 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 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 Bounded-Buffer – Message Passing Solution The Producer Channel mailBox; while (true) { Date message = new Date(); mailBox.send(message); } Bounded-Buffer – Message Passing Solution The Consumer Channel mainBox; while (true) { Date message = (Date) mailBox.receive(); if(message != NULL) /*consume the message */ } Monitors A high-level abstraction that provides a convenient and effective mechanism for process synchronization Only one process may be active within the monitor at a time Schematic view of a Monitor Fence P1 P2 Entry E Entry F P4 Entry G P5 Condition C Critical Data Condition D Waiting Signalers P3 P6 Condition Variables Condition c, d; Two operations on a condition variable: c.wait () – a process that invokes the operation is suspended. c.signal () – resumes one of processes (if any) that invoked c.wait () Monitor with Condition Variables Fence P1 P2 Entry E Entry F P4 Entry G P5 Condition C Critical Data Condition D Waiting Signalers P3 P6 Monitor with Condition Variables Fence P1 P2 Condition C Entry E Critical Data Entry F Condition D Waiting Signalers P4 Entry G P3 P6 P5 Monitors (1) Monitors (2) Monitors (3)