1 / 49

UNIX Process

UNIX Process. Process is any program which is executed by computer’s operation system. Kernel is Operation System, that interacts with hardware and provides services like Memory Management, CPU scheduling, Filesystem, I/O Device access, etc. System Call

taya
Download Presentation

UNIX Process

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. UNIX Process • Process • is any program which is executed by computer’s operation system. • Kernel • is Operation System, that interacts with hardware and provides services like • Memory Management, CPU scheduling, Filesystem, I/O Device access, etc. • System Call • is direct entry point, provided by Kernel, through which active Process can obtain the service Process Representation in Memory User Context Kernel Context Stack • Text • Actual machine instructions to be executed by hardware • Data • Program’s data, declared during program start • Heap • Data space, dynamically allocated by the Process • Stack • Dynamically allocated Stack Frames, containing return address linkage and data elements for each function call Heap Uninitialized Data Initialized Read-Write Data read from program file when program is executed Initialized Read-Only Data Text Introduction to Network Programming in UNIX & LINUX

  2. File Access Mode Word Octal Value Meaning ls -l r w x r w x r w x s s t Process Attributes • Process ID • Parent Process ID • Real User ID (RUID = UID of user, who launched the program) • Real Group ID (RGID = GID of user, who launched the program) • Saved User ID (SUID = UID of program file owner) • Saved Group ID (SGID = GID of program file owner) • Effective User ID (EUID = SUID if ‘Set user ID on execution’ bit is set • = RUID else) • Effective Group ID (EGID = SGID if ‘Set group ID on execution’ bit is set • = RGID else) • Process Group ID (PGID = PID of session leader process) • Terminal Group ID • Root Directory • Current Working Directory • Initial Argument Vector • Initial Environment Vector • Signal Handling Settings • File Mode Creation Mask • List of open File Descriptors • Time left until scheduled alarm signal Introduction to Network Programming in UNIX & LINUX

  3. Fork System Call #include <unistd.h> pid_t fork (); parent fork • The fork() system call creates the copy of process that is executing. • It is an only way in which a new process is created in UNIX. • Returns: child PID >0 - for Parent process, • 0 - for Child process, • -1 - in case of error (errno indicates the error). • Fork reasons: • Make a copy of itself to do another task simultaneously • Execute another program (See exec system call) child Parent:PID1 Child:PID2 pid_t childPID; /* typedef int pid_t */ … childPID = fork(); if (childPID < 0) { perror(“fork failed”); exit(1); } else if (childPID > 0) /* This is Parent */ { /* Parent processing */ … exit(0); } else /* childPID == 0 */ /* This is Child */ { /* Child processing */ … exit(0); } Stack Stack Heap Heap Data Data pointer to Text pointer to Text PID2 0 Text … childPID = fork(); … • Child Process has Shared Text and Copied Data. • It differs from Parent Process by following attributes: • PID (new) • Parent PID (= PID of Parent Process) • Own copies of Parent file descriptors • Time left until alarm signal reset to 0 Introduction to Network Programming in UNIX & LINUX

  4. CHILD Running Terminated PARENT Parent fork Child Running, calls WAIT Parent accepts Child’s PID and termination status immediately. Child is deleted from Process Table. Parent blocks waiting for Child Termination Kernel wait exit Running, WAIT is not called yet ------------ Child becomes Zombie, Child remains in Process Table until WAIT will be called Process Status: 2 low-order bytes Exit Status: 1 low-order byte Terminated, WAIT was not called PPID of Child is set to 1 PPID of Child is set to 1, INIT process will call WAIT. Exit and Wait System Calls Exit System Call #include <stdlib.h> void exit (int status); • Terminates process execution. • Exit status is passed to the Kernel • and then available to the Parent Process (with wait() call) • Only low-order 1 byte used to specify the exit status • (0 - success, 1-255 – error) Wait System Call #include <sys/wait.h> pid_t wait (int *p_status); • Waits for one of the children process to finish. • Returns: child PID > 0 - PID of child process terminated with exit system call or with signal, • -1 - if there aren’t child processes or if wait interrupted with signal (errno=EINTR). • If p_status is not NULL, the 2 low-order bytes will be filled with process status information Zombie Process Child process terminated with exit(), but yet not wait()-ed by Parent process, becomes Zombie or Defunct. Its main resources are released by Kernel, but it still present in Process Table until Parent will read its status. If a parent process terminated without wait()-ing for its children, the parent PID of each child process is set to 1. Introduction to Network Programming in UNIX & LINUX

  5. #include <sys/wait.h> pid_t waitpid (pid_t pid, int *p_status, int options); Waitpid System Call • Waits for one of the children process to finish (performs functionality of wait with additional options). • The pid argument may be: • > 0 - PID of particular process • = 0 - sender’s process group • =-1 - all sender’s processes • <-1 - process group ID = abs(pid) • The options argument may be: • WNOHANG - check status of terminated processes in non-blocking mode • WUNTRACED - report also the status of stopped child processes • If p_status is not NULL, the 2 low-order bytes will be filled with Process Status information. • Returns: child PID > 0 of child process terminated with exit system call or with signal, • -1 - if there aren’t child processes, • -1 (errno=EINTR) - if wait interrupted with signal, • -1 (errno=ECHILD) - if argument pid is invalid, • -1 (errno=EINVAL) - if argument options is invalid, • 0 - if WNOHANG option is specified and child process(es) still running Process Status Evaluation To evaluate process status the following MACROs are used: int * p_status Logical (0/1) Arithmetical: ( Exit Status / Signal Number ) WIFEXITED(status), WEXITSTATUS(status), WIFSIGNALED(status), WTERMSIG(status), WIFSTOPPED(status), WSTOPSIG(status) Introduction to Network Programming in UNIX & LINUX

  6. Example: Starting two new programs from Shell prog2 exec sh fork fork exec prog1 Example: execute “ls ./” execl(“/bin/ls”, “ls”, “./”, NULL); Exec System Call #include <unistd.h> int execl (const char *path, const char *arg0, ..., const char *argn, char * /*NULL*/); int execv (const char *path, char *const argv[ ]); int execlp (const char *file, const char *arg0, ..., const char *argn, char * /*NULL*/); int execvp (const char *file, char *const argv[ ]); int execle (const char *path, const char *arg0, ..., const char *argn, char * /*NULL*/,char *constenvp[ ]); int execve (const char *path, char *const argv[ ],char *constenvp[ ]); • Executes the program as existing process, replacing current process image with new one. • Program arguments could be passed as NULL-terminated list (arg0,…,argN) or vector (argv[ ]), • argument 0 would specify program name, arguments 1-N specify parameters. • Target program file could be specified by path or as file name to be used with PATH variable. • In form with envp argument, also replaces new image environment. • It is an only way in which a program is executed in UNIX. • As result of exec…() system call the following process • attributes could be changed: • Effective User ID • Effective Group ID • Initial Environment Vector • The signals, which were set to be caught by caller, • are changed to terminate the new program • (because code of old signal handlers became unavailable) • In case of error exec() returns -1, errno indicates the error. init PID=1 How user session is started. fork exec exec exec /bin/sh getty login init ask credentials check password, load user configuration Introduction to Network Programming in UNIX & LINUX

  7. N 4 stdout stdin stderr FileA File exists O_CREAT and O_EXCL Flags Combination: Example. Open File fd=open(“FileA”, O_RDWR); /* As result, fd equal 3 */ Yes No O_... open error O_...|O_CREAT (mode used) open create O_...|O_CREAT|O_EXCL (mode used) error create Process 0 1 2 3 file descriptors … File System Management (Input/Output) System Calls With each File, open by specific Process, the Kernel associates the unique integer value in the scope of this process. This integer key is named File Descriptor. It is used as file identifier for all subsequent read and write operations. By default, the File Descriptors 0, 1 and 2 are associated with Standard Input, Output and Error correspondently. #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *path, int oflag, …/*mode_t mode*/); • Opens file specified by path-name • Argument oflag specifies one of following open modes: • O_RDONLY (=0) read-only, O_WRONLY (=1) write-only, O_RDWR (=2) read & write • The following bit flag values could be added with bitwise-OR operator (see also man): • O_APPEND - all writes append data to the end of file • O_TRUNC - if open for write, the file is truncated to 0 bytes length • O_CREAT - file will be created if it does not exist yet • O_EXCL - used with O_CREAT for exclusive creation • Argument mode is used with O_CREAT flag and specifies • the permissions of creating file as octal constant. • Returns File Descriptor (>=0) in case of success. • Returns -1 in case of error, errno value specifies the error (see man). #include <unistd.h> int close (int fd); • Deallocates File Descriptor specified by fd. • This File Descriptor could be reused by subsequent open() calls. • Returns 0 on success. Returns -1 in case of error, errno value specifies the error. Introduction to Network Programming in UNIX & LINUX

  8. I/O System Calls (continuation) #include <unistd.h> ssize_t read (int fd, void *buf, size_t nbyte); • Reads no more than nbyte-s from file associated with descriptor fd into buffer buf. • Returns non-negative number of read bytes. Returns -1 in case of error, errno value specifies the error. #include <unistd.h> ssize_t write (int fd, void *buf, size_t nbyte); • Writes nbyte-s from buffer buf to the file associated with descriptor fd . • Returns non-negative number of written bytes. Returns -1 in case of error, errno value specifies the error. #include <sys/types.h> #include <unistd.h> off_t lseek (int fd, off_t offset, int whence); • Sets the file pointer associated with the open file descriptor fd as follows: • - if whence == SEEK_SET, the pointer is set to offset bytes from file beginning. • - if whence == SEEK_CUR, the pointer is set to its current location plus offset. • - if whence == SEEK_END, the pointer is set to the size of the file plus offset. • Returns the resulting offset calculated from file beginning. Returns -1 in case of error, errno specifies the error. Buffered Input / Output The Standard C Library provides the data type FILE representing Buffered Stream Object and set of functions providing Buffered Input / Output: fopen(), fclose(), fread(), fwrite(), fseek(), fflush(). Actually, the object of type FILE is buffered wrapper of File Descriptor, associated with corresponded file. The following utility function associates the buffered stream object of type FILE with already open File Descriptor: #include <stdio.h> FILE *fdopen (int fd, const char *mode); • Associates Buffered Stream with already open File Descriptor. • Argument mode could have the same values (“r”, “w”, “a”, “r+”, “w+”, “a+”) as for fopen() function. • Returns FILE* pointer to Buffered Stream object or NULL in case of error. Introduction to Network Programming in UNIX & LINUX

  9. Example. Redirection of STDOUT to File Process fd=open(“FileA”…); /* fd equal 3 */ file descriptors 4 N 1 4 N N 4 N 3 4 … stdout stderr stdin stdin stdout File A stderr stdout stdin stdout File A stderr stdin stderr File A File A close(1); Process … dup(fd)); Process … 1 0 3 2 0 2 3 0 1 2 2 1 0 3 close(fd)); Process … Example. dup2() via dup() close(1); dup(fd); dup2(fd, 1); Dup System Calls and Redirection #include <unistd.h> int dup (int fd); • Duplicates an open file descriptor • Returns a new file descriptor pointing to the same file • or -1 in case of failure (errno indicates the error) • The file descriptor returned is the lowest one available. • The new file descriptor is set to remain open across exec • functions. int dup2(int fd1, int fd2); • Duplicates an open file descriptor • Causes the file descriptor fd2 to refer to the same file as fd1. • If fd2 already refers to an open file, not fd1, it is closed first. • If fd2 already refers to fd1, or if fd1 is not valid, fd2 will not be • closed first. • Returns non-negative value of fd2 in case of success • or -1 in case of failure (errno indicates the error) Introduction to Network Programming in UNIX & LINUX

  10. Inter Process and Inter-Host Communication • Inter Process Communication (IPC) • is sharing of information and resources by two or • more different processes. host • IPC includes • Data Exchange • Synchronization Process 1 Process 2 • UNIX (Linux) provides different methods of IPC: • Pipes • FIFOs • Signals • Message Queues • Shared Memory • Semaphores Kernel host 1 host 2 • Inter-Host Communication (IHC) • is IPC between two or more processes, running on different hosts in the network. Process 1 Process 2 • UNIX (Linux) provides the following methods for IHC: • Berkeley Socket API • System V Transport Library Interface (TLI) Kernel Kernel Introduction to Network Programming in UNIX & LINUX

  11. W W W W R R R R Unnamed Pipe #include <unistd.h> int pipe (int *fd); • Creates input / output mechanism called the Pipe. The Pipe is unidirectional bite stream • Through fd[0] the read descriptor is returned. • Through fd[1] the write descriptor is returned. • The Pipe is usually used for communication between Parent and Child Processes. • The pipe() call returns 0 in case of success. In case of failure -1 is returned, errno indicates the error. childpid=fork(); int fd[2]; pipe(fd); close(fd[0]); close(fd[1]); Process 2 Process 2 Process 1 Process 1 Process 1 W R pipe pipe pipe kernel kernel kernel Introduction to Network Programming in UNIX & LINUX

  12. R W W W W R R Unnamed Pipe Usage Scenarios Bidirectional flow 2 Processes write to 1 fork fork fork Process 1 Process 2 Process 3 Process 1 Process 2 pipe2 pipe1 pipe1 kernel • Bidirectional flow needs 2 pipes • If a process writes less than Capacity of Pipe • (which is at least 4096), the write operation is • guaranteed to be atomic. • In Special cases: • - read & no data • - write & pipe is full • the behavior depends on blocking / non-blocking mode (flag O_NONBLOCK or O_NDELAY) • If one end closed while second is writing, the SIGPIPE signal is sent to writing peer. Introduction to Network Programming in UNIX & LINUX

  13. fork Parent-”Client” Child-”Server” read file name STDIN open file read file contents File F STDOUT print file contents or error response pipe2 request pipe1 kernel 0 W W 1 R R Example of Pipe Usage Child-”Server” /* close descriptors unused by server: P1[0] - P1 read, P1[1] - close P2[0] - close, P2[1] - P2 write */ close(pipe1[1]); close(pipe2[0]); … do Server functionality… /* close descriptors used by server */ close(pipe1[0]); close(pipe2[1]); exit(0); Parent – “Client” pipe(pipe1); pipe(pipe2); fork(); /* close descriptors unused by client: P1[0] - close, P1[1] - P1 write P2[0] - P2 read, P2[1] - close */ close(pipe1[0]); close(pipe2[1]); … do Client functionality… /* close descriptors used by client */ close(pipe1[1]); close(pipe2[0]); exit(0); Introduction to Network Programming in UNIX & LINUX

  14. #include <stdio.h> FILE *popen(const char *command, const char *mode); int pclose(FILE *stream); Example: Using popen() to run “ls *.c” #include <stdio.h> #include <stdlib.h> int main() { char *cmd = "/usr/bin/ls *.c"; char buf[BUFSIZ]; FILE *ptr; if ((ptr = popen(cmd, "r")) != NULL) { while (fgets(buf, BUFSIZ, ptr) != NULL) printf("%s", buf); pclose(ptr); } } #include <stdlib.h> int system(const char *string) Pipe-related Library Functions • Function popen() creates a pipe between the calling program and the command to be executed. • The command argument consists of a shell command line, that is invoked as follows: • execl("/usr/xpg4/bin/sh", "sh", "-c", command, NULL); • The mode argument is either “r” for reading or “w” for writing. • Depending on mode, calling program could read from STDIN or write to STDOUT of the command. • Function pclose() closes a pipe, waits for the associated process and returns its termination status. • Function system() invokes string as shell command, waits until the shell completion and return its status. • This function could be used only if single-threaded process. • In multi-threaded process the following code could replace functionality of system(): • pclose(popen(string,”w”)); Introduction to Network Programming in UNIX & LINUX

  15. #include <sys/stat.h> int mknod(const char *path, mode_t mode, dev_t dev); W R Process 1 Process 2 FIFO <FifoName> kernel FIFO or Named Pipe • The system call mknod() creates a filesystem node (file, device special file or named pipe) • The FIFO (First In, First Out) is unidirectional bite stream with persistent name. • FIFO (Named Pipe) is created by the command mknod or by system call mknod() with • mode=(S_IFIFO | permissions) • Upon successful completion, mknod() returns 0.Otherwise, it returns -1, and errno is set to indicate the error. • FIFO is opened for writing / reading as regular file by its name (open(), close(), fopen(), fclose()). • Process, opening FIFO for writing, waits (is blocking) until the second process opens FIFO for reading. • To communicate through FIFO the processes don’t have to be in Parent-Child relation. • In Special cases ( read & no data, write & pipe is full ) the behavior depends on blocking / non-blocking mode • (flag O_NONBLOCK or O_NDELAY) #include <unistd.h> int unlink(const char *path); Process 1 mknod(FifoName, S_IFIFO | perms, 0); open(FifoName, O_WRONLY); Process 2 open(FifoName, O_RDONLY); • The unlink() function removes a link to a file. • When the file's link count becomes 0 and no process has the file open, the file is deleted Introduction to Network Programming in UNIX & LINUX

  16. On some UNIX systems flag O_NDELAY specifies different behavior, than O_NONBLOCK On some UNIX systems if flag O_NDELAY is specified instead of O_NONBLOCK, the value 0 is returned. #include <unistd.h> #include <fcntl.h> int fcntl(int fildes, int cmd, /*arg*/ ...); Blocking Mode and Special Conditionsof I/O operations on Pipes and FIFOs • Flag O_NONBLOCK or O_NDELAY could be specified • during open()-ing of FIFO descriptor • with function fcntl() on already open Pipe or FIFO descriptor • Function fcntl() provides miscellaneous operations on file descriptors • To set non-blocking I/O mode, the following form is used: • int flags = fcntl (fd, F_GETFL, 0); /* get current flags */ • fcntl (fd, F_SETFL, flags | O_NONBLOCK); /* add non-blocking flag */ Introduction to Network Programming in UNIX & LINUX

  17. W W w R R Example: FIFO-based Client-Server Model Client Server Server FIFO uses well-known SERVER_FIFO Name Client FIFO uses temporary Client FIFO Name kernel • Client: • Creates Client FIFO with unique temporary name • Opens Server FIFO for write • Writes Request, containing Client FIFO name • Closes Server FIFO. • Opens Client FIFO for read • Reads the Reply • Closes and deletes Client FIFO. • Server: • Creates Server FIFO with well-known name • Opens Server FIFO for read (blocking) • Opens Server FIFO for write to avoid read unblocking • Waits (blocking read) for incoming client request • Reads Client FIFO Name from Client Request • Opens Client FIFO to write • Writes the Reply • Closes Client FIFO. • - (repeat for each client) • - (On termination) Closes and deletes Server FIFO Introduction to Network Programming in UNIX & LINUX

  18. Iterative Server Concurrent Server Client Start-up Start-up Start-up Bind to well-known address Bind to ephemeral address Bind to well-known address Wait for Clients Connect to Server by well-known address Wait for Clients Read Client Request Send Request Read Client Request Sub-Server Connect to Client Address Wait for Reply Connect to Client Address Fork Sub-Server Continue? Send Reply to Client Read Reply Send Reply to Client yes no Disconnect From Client Disconnect from Server Disconnect From Client release defuncts Continue? Disconnect from ephemeral address yes no Disconnect from well-known address Disconnect from well-known address Iterative and Concurrent Server Introduction to Network Programming in UNIX & LINUX

  19. Name Value Default Event =========================================================== SIGHUP 1 Exit Hangup on controlling terminal SIGINT 2 Exit Interrupt (Ctrl-C) SIGQUIT 3 Core Quit – interactive termination SIGILL 4 Core Illegal Instruction SIGTRAP 5 Core Trace or Breakpoint Trap SIGABRT 6 Core Abort – abnormal termination SIGEMT 7 Core Emulation Trap SIGFPE 8 Core Arithmetic Exception SIGKILL 9 Exit Killed (can’t be changed) SIGBUS 10 Core Bus Error (undefined memory access) SIGSEGV 11 Core Segmentation Fault (invalid memory reference) SIGSYS 12 Core Bad System Call SIGPIPE 13 Exit Broken Pipe SIGALRM 14 Exit Alarm Clock (timeout signal) SIGTERM 15 Exit Terminated SIGUSR1 16 Exit User Signal 1 SIGUSR2 17 Exit User Signal 2 SIGCHLD 18 Ignore Child Status Changed SIGPWR 19 Ignore Power Fail or Restart SIGWINCH 20 Ignore Window Size Change SIGURG 21 Ignore Urgent Socket Condition SIGPOLL 22 Exit Pollable Event SIGSTOP 23 Stop Stopped (can’t be changed) SIGTSTP 24 Stop Stopped (user) (Ctrl-Z) SIGCONT 25 Ignore Continued (command fg) SIGTTIN 26 Stop Stopped (tty input) SIGTTOU 27 Stop Stopped (tty output) SIGVTALRM 28 Exit Virtual Timer Expired SIGPROF 29 Exit Profiling Timer Expired SIGXCPU 30 Core CPU time limit exceeded SIGXFSZ 31 Core File size limit exceeded UNIX utility kill /usr/bin/kill -s signal_name pid... [-signal_name] pid... [-signal_number] pid... -l Example: Send SIGINT to process with PID=12345 # kill -s INT 12345 # kill -INT 12345 # kill -2 12345 Signal • Signal is software interruptused as notification to process about some event. • Process accepts a signals: • sent by Kernel • sent by another process • Sends a signal to the process(es) • specified by each pid operand. • The pid argument may be: • >0 - PID of particular process • =0 - sender’s process group • -1 - all sender’s processes • <-1 - process group ID = abs(pid) • With -l parameter writes all supported • signal names Introduction to Network Programming in UNIX & LINUX

  20. int raise(int sig); #include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); #include <unistd.h> int pause(void); #include <signal.h> void (*signal (int sig, void (*sig_handler)(int) ) ) (int); this is equivalent of typedef void( *sig_handler) (int sig); sig_handler signal(int sig, sig_handler handler); Sending and Handling the Signal • Sends the signal sig to executing program. • Is equivalent to kill(getpid(), sig) • System call kill() sends a signal to a process or a group of processes. • The sender and receiver must have the same effective user ID or sender must be superuser. • Sending sig = 0 used to check process existence. • The pid argument could have the following values: • >0 - PID of particular process • =0 - sender’s process group • -1 - all sender’s processes • <-1 - process group ID = abs(pid) • The kill() call returns 0 in case of success. In case of failure -1 is returned, errno indicates the error. • System call pause() suspends the calling • process until it receives a signal. • If process is not terminated by signal, returns • value -1 and sets errno=EINTR • System call signal() modifies signal disposition. • The sig specifies any signal, excepting SIGKILL and SIGSTOP. • The sig_handler argument specifies the signal's disposition, which may be: • - SIG_DFL - to provide default signal handling • - SIG_IGN - to ignore the signal • - user-defined handler name - to provide specific signal handling with specific handler • The signal() call returns the previous handler (disposition) of the signal. Introduction to Network Programming in UNIX & LINUX

  21. Example 2. Using alarm() System Call to provide operation timeout. #include <stdio.h> #include <unistd.h> #include <signal.h> char userName[MAXBUFF]; /* --- Alarm signal handler. --- */ void catch_alarm(int sig_num) { perror("Operation timed out."); exit(0); } … /* --- Reads user name --- */ int main(int argc, char* argv[]) { /* subscribe for ALRM signals */ signal(SIGALRM, catch_alarm); /* prompt the user for input */ printf("Username: "); fflush(stdout); /* start a 30 seconds alarm */ alarm(30); /* wait for user input */ fgets(userName, MAXBUFF, stdin); /* remove the timer*/ alarm(0); printf("User name: '%s'\n", userName); return 0; } Example 1. Suspend / Resume application output with SIGINT signal (sent with Ctrl-C). #include <signal.h> int flag=0; /*--- Signal SIGINT handler--- */ void sigreact (int sig) { /* OS-depended re-subscription*/ /* signal(SIGINT,sigreact); */ flag = ! flag; } … /*--- Prints application data ---*/ void printInfo(…) { … /* subscribe to signal */ signal (SIGINT, sigreact); while(…/*has more data */) { while(flag) { /* wait for signal */ pause ( ); } printf(…/*print the data*/); } /* unsubscribe from signal */ signal (SIGINT, SIG_DFL); … } #include <unistd.h> unsigned int alarm (unsigned int sec); • Causes the system to • generate a SIGALRM • signal for the process • after the number of sec • real-time seconds. • If sec = 0, a pending • alarm request, if any, • is cancelled. • Alarm requests are not • stacked. Each alarm() • call reschedules the • alarm time. • The fork() call clears • pending alarms in the • child process. Signal Handling Examples Introduction to Network Programming in UNIX & LINUX

  22. Race Condition Example • Two “racing” events are: • Flag testing by procedure • Flag setting by signal handler void sigreact (int sig) { flag = ! flag; } void someProcedure() {… flag = 1; /* subscribe to signal */ signal(SIGINT, sigreact); … … /* wait for signal */ while(flag) { pause ( ); } /* continue execution */ … If signal arrives here, flag will be changed to 0, pause() call will not be performed, process execution will continue If signal arrives after check of flag flag will be changed to 0, but pause() call will be performed, process will be “stuck” This is Critical Region If signal arrives here, flag will be changed to 0, pause() call will be interrupted, and process execution will continue Race Condition • Race Condition or Race Hazard • This is a defect of Process functionality, when behavior of the process • is unexpectedly and critically depends on the sequence or timing of occurring events. • Most common scenario: two events (or signals) are racing each other to affect the Process. • Critical Region • This is the region of code, where occuring of event (or signal) causes Race Condition. Introduction to Network Programming in UNIX & LINUX

  23. Note: In most the cases the Race Condition occurs between testand setoperations. To avoid “racing” of testand set, the Kernel provides number of tools (system calls), performing test-and-setas one impartible operation. Avoiding of Race Condition There are two ways to avoid Race Condition : 1) To perform the Polling - repeatable check of the resource state with limited time period In previous example this means to replace system call pause( ) with call to function sleep(int seconds). Advantage: This is the simplest way to avoid process forever “sticking”. Disadvantage: In certain condition, process will be able to recognize state update only after delay . In previous example, if signal will occur after flag check, but before sleep() call, the process will be able to recognize flag update only after expiration of next sleep timeout 2) To provide Blocking of event (signal) delivery in the Critical Region. In previous examplethis means to prohibit delivery of specific signal SIGINT between flag check and system call pause( ). Advantage: The event (signal) delivery delay will be minimized. Event (signal) will be delivered as soon as Critical Region will be passed. Disadvantage: Requires more complicated blocking mechanism to be provided by Kernel Introduction to Network Programming in UNIX & LINUX

  24. Signal Delivery Diagram process flow signal blocking signal unblocking Process Flow Block the Signal (add to Signal Mask) Start the Process (init Signal Mask) Unblock the Signal (remove from Signal Mask) Is Signal pending ? no Remove occurrence from Pending Signal Mask yes Event occurred Signal Generation Add occurrence to Pending Signal Mask Is Signal blocked ? yes no Deliver the Signal (take proper action) yes no Is Signal ignored ? Discard the Signal Signal Blocking Signal Blockingis temporary prevention of signal delivery. Each process has Process Signal Mask,specifying the set of signals, which currently blocked by the process. Blocked signals (unlike ignored signals) do not get lost. If generated signal is specified as blocked, the process holds the occurrence of this signal in Pending Signal Maskuntil signal is unblocked. After unblocking, the pending signal is delivered (the specified action is performed). Introduction to Network Programming in UNIX & LINUX

  25. POSIX Signal Set Utilities POSIX Signal Set To provide system calls on set of signals, POSIX standard provides data type sigset_t, representing the Signal Set. This type contains the set of bit flags. Each bit flag corresponds to specific signal. For manipulation with POSIX Signal Set the following service functions are used : #include <signal.h> int sigemptyset(sigset_t *set); - removes all signals from the Signal Set int sigfillset(sigset_t *set); - fills the Signal Set with all the signals int sigaddset(sigset_t *set, int signum); - adds the specified signal to the Signal Set int sigdelset(sigset_t *set, int signum); - deletes the specified signal from the Signal Set int sigismember(const sigset_t *set, int signum); - checks if a specified signal is in the Signal Set • All these functions return 0 on success, -1 on error. • The sigismember() function returns 1(=true) / 0(=false) / -1 (error). Introduction to Network Programming in UNIX & LINUX

  26. #include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); #include <signal.h> int sigsuspend(const sigset_t *set); #include <signal.h> int sigpending (sigset_t *set); Commonly the sigprocmask() call is used to block Signal delivery in Critical Region. The sigsuspend() call is used to wait for the signal out of Critical Region. POSIX System Calls for Signal Blocking • System call sigprocmask() is used to change / examine the Signal Mask (set of blocked signals) • of the calling process • Parameter how may have the following values • SIG_BLOCK - the Signal Set, specified by set, is added to process Signal Mask • SIG_UNBLOCK - the Signal Set, specified by set, is removed from process Signal Mask • SIG_SETMASK - the Signal Set, specified by set, replaces the process Signal Mask • If oldset is not NULL, the old Signal Mask value is returned • If set is NULL, the process Signal Mask is not modified. • If any pendingsignals became unblockedduring the call, at least oneof those signals will be delivered • before the call to sigprocmask()returns. • Attempts to block signals SIGKILL, SIGTOP are silently ignored. • Return values: 0-success, -1 failure (errno will specify the error). • System call sigpending() function retrieves • those signals that have been sent to the • process but are being blocked from delivery • by the calling process's signal mask. • The result stored in set argument. • Returns 0 on success, -1 on failure. • System call sigsuspend() performs the following operations: • - temporaryreplaces Signal Mask; • - suspends the calling process until it receives a signal; • - restoresthe Signal Mask , • if process is not terminated by signal. • If process is not terminated, returns -1 and sets errno = EINTR Introduction to Network Programming in UNIX & LINUX

  27. Race Condition Resolution Example void sigreact (int sig) { flag = ! flag; } void someProcedure() {… sigset_t blockMask, unblockMask; /* prepare masks */ sigemptyset ( &blockMask); sigaddset ( &blockMask, SIGINT); sigprocmask( SIG_SETMASK, NULL, &unblockMask); sigdelset(&unblockMask, SIGINT); flag = 1; /* subscribe to signal */ signal(SIGINT, sigreact); … /* block the signal */ sigprocmask(SIG_BLOCK, &blockMask, NULL); … /* wait for signal */ while(flag) { sigsuspend( &unblockMask); } /* continue execution */ … If signal arrives here, flag will be changed to 0, then sigsuspend () will not be called, process execution will continue Critical Region Is covered. Here signal is blocked. If it will arrive, Pending Signal Mask Will be updated, but signal will not be delivered. Here the signal (pending or generated) is safely handled Race Condition Resolution Introduction to Network Programming in UNIX & LINUX

  28. #include <signal.h> • int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); • where: • struct sigaction { • void (*sa_handler)(int); • sigset_t sa_mask; • int sa_flags; • }; Example: Signal handling with sigaction() void handler(int sig) {…} … struct sigaction newAction;newAction.sa_handler=handler; /* set the handler*/ sigfillset(&newAction.sa_mask); /* block other signals during the handling */ newAction.sa_flags = 0; /* no flags */ if (sigaction(SIGUSR1, &newAction, NULL) < 0) {…} POSIX Advanced Signal Handling • The sigaction() system call provides POSIX advanced (relatively to signal() ) interface, • used to change the action taken by aprocess on receipt of a specific signal. • Parameter signum specifies the signal number. Parameters act and oldact specify the pointers to the structures, • describing old and new action to be taken on specified signal delivery. • The structure sigaction specifies the following fields: • sa_handler - the signal handling function • sa_mask - a mask of signals which should be blocked during execution of the signal handler. • (the signal which triggeredthe handler will also be blocked, • unless the SA_NODEFER flag is used) • sa_flags - specifies a set of flags used to modify the delivery of the signal • (flags are combined with logical OR) • Some of sa_flags values: • SA_RESETHAND - Restore the signal action to • the default state once the signal • handler has been called. • SA_RESTART - Provide restart of “slow” system • calls, interrupted by signal . • SA_NODEFER - Do not prevent the signal from • being received from within • its own signal handler. • Returns 0 – success, • -1 – failure (errno specifies the error). Introduction to Network Programming in UNIX & LINUX

  29. UNIX IPC-related Utilities ipcs Report IPC facilities status ipcrm [-m id] [-q id] [-s id] [-M key] [-Q key] [-S key] Removes IPC object by ID or by KEY. #ipcs IPC status from <running system> as of Thu Feb 1 12:11:56 IST 2007 T ID KEY MODE OWNER GROUP Message Queues: q 0 0xd9019340 --ra-r--r-- root root q 1 0xd9719343 --ra-r--r-- root root q 2 0xd9089388 --ra-r--r-- root root Shared Memory: m 0 0x1e34 --rw-rw-rw- root other m 257 0x79ebc2ac --rw-r----- oracle dba m 258 0x17220c --rw-r----- oracle dba m 259 0x4d0190d2 --rw-rw-rw- temip temip_us m 260 0x300192ed --rw-rw-rw- temip temip_us m 261 0x300192d0 --rw-rw-rw- temip temip_us Semaphores: s 0 0xf9019340 --ra-r--r-- root root s 65539 0xf9019349 --ra-r--r-- root root s 65540 0xf901934a --ra-r--r-- root root #include <sys/ipc.h> typedef int key_t; key_t ftok(const char *path, int prm_char); KEY ftok System V IPC • System V IPC provides three methods: • Shared Memory Segments • Message queues • Semaphores • All these IPC methods have similar access interface: • persistent integer KEY name and integer system ID. How to build the KEY for System V IPC object • The ftok() function returns a key based on path • and additional prm_char (only 8 bits used) • Returns the same values for the different path • names of the same existing file • and same prm_char • Returns -1 if path does not exist or is not • accessible #include <sys/ipc.h> #define IPC_PRIVATE (key_t)0 /* private key */ • May be used by process as ephemeral KEY Predefined (well-known) value Ephemeral (IPC_PRIVATE) value Path Prm_char Introduction to Network Programming in UNIX & LINUX

  30. W W W R R R Note: Access to Shared Memory from different processes must be synchronized System V Shared Memory Shared Memory is the fastest form of IPC available. Once the Shared Memory region is mapped into the address space of the processes, no kernel involvement occurs in passing data between the processes. Data copied 4 times Data copied 2 times Shared Memory Client Client Server Server memory memory write() write() read() read() write() read() pipe Input File Output File Output File Input File kernel kernel Introduction to Network Programming in UNIX & LINUX

  31. #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int flags); Segment exists Flags Combination: Yes No perms open error perms | IPC_CREAT open create perms | IPC_CREAT | IPC_EXCL error create Access and Control Shared Memory flags: 0400 Read by owner 0200 Write by owner 0040 Read by group Access 0020 Write by group Permissions • Creates new Shared Memory segment with specified size if: • - key = IPC_PRIVATE or • - key does not refer to existing segment • and IPC_CREAT flag specified • If segment was created or already exist, returns segment ID. • Returns -1 in case of error, errno specifies the error. 0004 Read by others 0002 Write by others IPC_CREAT Create if does not exist In combination with IPC_CREAT – return an error, if segment already exists IPC_EXCL #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> struct shmid_ds {…/* see man */…}; int shmctl(int shmid, int cmd, struct shmid_ds *buf); • Performs control operations on Shared Memory. • The cmd may be: IPC_STAT, IPC_SET, IPC_RMID, IPC_LOCK, IPC_UNLOCK • To remove Shared Memory segment, used in following form: • shmctl(shmid, IPC_RMID, NULL); • Returns 0 in success, -1 in case of error (errno specifies the error) Introduction to Network Programming in UNIX & LINUX

  32. #include <sys/types.h> #include <sys/shm.h> void *shmat(int shmid, const void *addr, int flags); #include <sys/types.h> #include <sys/shm.h> int shmdt(const void *shmaddr); Attach / Detach Shared Memory • Attaches Shared Memory segment, specified by ID, to the Data Segment of the calling process: • addr = NULL – attached to address selected by system • addr != NULL – attached to specified address (see flags) • Specific flags value: • SHM_RDONLY – read only access • Returns: • the segment starting address on success, • -1 in case of failure (errno specifies the error) • Detaches Shared Memory segment from the calling process. • Returns 0 (success) / -1 (failure) Introduction to Network Programming in UNIX & LINUX

  33. /*-- common.h --*/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define THE_KEY 5678 #define THE_SIZE 100 #define PERMS 0666 Shared Memory Example /* -- server main -- */ include “common.h” main() { int shmid; key_t key; char *shm; /* Create the segment. */ shmid = shmget(THE_KEY, THE_SIZE, PERMS | IPC_CREAT | IPC_EXCL); if (shmid < 0) { … /*handle error*/ } /* Attach the segment to server data space. */ shm = shmat(shmid, NULL, 0); if (shm == (char *) -1) { … /*handle error */ } /* Put some data to be read by another process. For example: */ strcpy(shm, “Any Data”); /* Notify the client and wait until read finish */ ... /* Detach the segment */ if (shmdt(shm) == -1){ …/*handle error*/ } /* Remove the segment */ if (shmctl(shmid, IPC_RMID, NULL) == -1 ){ …/*hanlde error*/ } } /*-- client main -- */ #include “common.h” main() { int shmid; key_t key; char *shm, buf [THE_SIZE]; /* Get the segment ID */ shmid = shmget(THE_KEY, THE_SIZE, PERMS); if (shmid < 0) { …/*handle error*/ } /* Attach the segment to client data space. */ shm = shmat(shmid, NULL, 0); if (shm == (char *) -1) { …/*handle error*/ } /* Wait notification from server to begin read */ … /* Read the data from server. For example:*/ strcpy(buf, shm); /* Notify the server about read finish */ … /* Detach the segment */ if (shmdt(shm) == -1){ …/*handle error*/ } } Introduction to Network Programming in UNIX & LINUX

  34. Client Server PID Client PID Data Length Data Buffer Server 4 bytes 4 bytes 4 bytes N bytes Shared Memory Example: Shared Memory - based Client-Server Modelwith Signal Synchronization • Client: • Gets Shared Memory ID by well-known KET_T name • Attaches Shared Memory • Reads Server PID from “Server PID” field” • Subscribes for signal notification from Server • Checks if “Client PID” is 0 and writes there own PID • Writes null-terminated File Name to “Data Buffer” • field and its length to “Data Length” field • Sends notification signal to Server by PID • Waits for signal from Server • Reads reply portion from “Data Buffer” • Sends notification signal to Server by PID • (repeats until empty portion was read) • Detaches Shared Memory • Server: • Creates Shared Memory with well-known KEY_T name • Attaches Shared Memory • Writes own PID to “Server PID” field • Subscribes for signal notification from Client • Writes 0 to “Client PID” field • Waits for signal from new Client • Reads from “Client PID”, “Data Length”, “Data Buffer” • Opens requested File for read • Writes data portion to “Data Buffer”, fills “Data Length” • Sends notification signal to Client by PID • Waits for signal from Client • (repeats until empty portion is written) • (repeats for each client) • Detaches Shared Memory • Removes Shared Memory Introduction to Network Programming in UNIX & LINUX

  35. kernel struct msqid_ds msqid link link NULL msg_perm structure type = 100 type = 200 type = 300 length = 1 length = 2 length = 3 msg_first data msg_last data data . . . msg_ctime - time of last change System V Message Queue • Message Queue is persistent queue of messages stored in Kernel. • As any other System V IPC objects, Message Queue is identified by KEY_T name and ID. • Processes read and write messages to arbitrary queues. • Sender process can write the message and exit. Receiver process can read the message later. • Every message in queue has the following attributes: • Type – long integer type value • Length – the length of data portion of the message ( >=0 ) • Data – any data ( if Length > 0 ) • The Message Queue could be considered as linked list of messages . • For each Message Queue the Kernel maintains the structuremsqid_ds, holding the current state of this Queue. Introduction to Network Programming in UNIX & LINUX

  36. #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int flags); Queue exists Flags Combination: Yes No perms open error perms | IPC_CREAT open create perms | IPC_CREAT | IPC_EXCL error create Message Queue Access and Control flags: 0400 Read by owner 0200 Write by owner 0040 Read by group Access 0020 Write by group Permissions • Creates new Message Queue with specified size if: • - key = IPC_PRIVATE or • - key does not refer to existing segment • and IPC_CREAT flag specified • If queue was created or already exist, returns queue ID. • Returns -1 in case of error, errno specifies the error. 0004 Read by others 0002 Write by others IPC_CREAT Create if does not exist In combination with IPC_CREAT – return an error, if queue already exists IPC_EXCL #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct msqid_ds {…/* see man */…}; int msgctl(int msqid, int cmd, struct msqid_ds *buf); • Performs control operations on Message Queue. • The cmd may be: IPC_STAT, IPC_SET, IPC_RMID • To remove Message Queue, used in following form: • msgctl(msqid, IPC_RMID, NULL); • Returns 0 in success, -1 in case of error (errno specifies the error) Introduction to Network Programming in UNIX & LINUX

  37. Send Message to Message Queue #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data of any type and size, may be empty */ }; int msgsnd(int msqid, struct msgbuf *ptr, int length, int flag); • Sends message to Queue with specified ID. • Parameter msqid specifies ID of existing Message Queue • Parameter ptr must point to any structure with positive long first field. • Parameter length specifies real size of message data in pointed structure (excluding 1st field) • Parameter flag could be 0 or IPC_NOWAIT. • Without IPC_NOWAIT flag, the system call blocks, when Message Queue has no room for the new message • (occurs if too many messages in Queue or system-wide) • Returns 0 on success, -1 on error (errno specifies the error) Introduction to Network Programming in UNIX & LINUX

  38. Receive Message from Message Queue #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgrcv(int msqid, struct msgbuf *ptr, int length, long msgtype, int flags); • Receives message from Queue with specified ID. • Parameter msqid specifies ID of existing Message Queue • Parameter ptr points to buffer for message storage. • Parameter length specifies maximal length of message data to be received. • Parameter msgtype: • 0 - receive message of any type • >0 - receive message of specific msgtype • <0 - receive message with lowest type that <=abs(msgtype) • Parameter flag could have bits: • MSG_NOERROR - no error if message data exceeds specified length (data is truncated) • IPC_NOWAIT - non-blocking mode • If IPC_NOWAIT flag is not specified, the system call blocks if Message of specified msgtype does not exist • System call unblocks in following cases: • - message appeared in Queue • - Queue removed • - signal interrupt • Returns number of bytes stored into the buffer ptr, -1 on error (errno specifies the error) Introduction to Network Programming in UNIX & LINUX

  39. client 1 pid = 123 client 2 pid = 456 client 3 pid = 789 type = 1 type = 123 type = 1 type = 789 type = 1 type = 456 message queue type = 1 type = 123 or 456 or 789 server Message Queue usage Scenariosin Client – Server Model • Server and Client use separate Message Queues • Server and Client use the same Message Queue with different Message types • Multiplexing of messages for Server and number of Clients, using different • Message types for different Clients in the same Queue Example: Message Multiplexing for 1 Server and 3 Clients 4) Prioritizing of Messages by Message type (use msgrcv() with msgtype <0) Introduction to Network Programming in UNIX & LINUX

  40. What is Semaphore System V Semaphore Semaphores are synchronization construct. Designed by E. W. Dijkstra in the late 1960s. Original model : Railroad with single track section, guarded by semaphore. Before entering the track train must wait for permitted (unlocked) state of semaphore. The semaphore changes its state when train enters the track (locked) and when the train leaves the track (unlocked). In programming: Semaphore used to provide resource access synchronization between different processes. Simplified Model Legend: semaphore=0 – resource locked, semaphore=1 – resource unlocked. Problems: 1) Critical region between Testing of “semaphore” value and its Setting (decrement) leads to Race Condition. 2) Waiting process continues to use CPU /* wait for resource to be unlocked*/ while(semaphore<1) ; /* lock resource */ semaphore--; … /* unlock resource */ semaphore++; System V Semaphore is not a single value, but set of nonnegative integer counters. Kernel provides group of operations on semaphore, executed in “atomic” mode. Introduction to Network Programming in UNIX & LINUX

  41. #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nSems, int flags); Queue exists Flags Combination: Yes No perms open error perms | IPC_CREAT open create perms | IPC_CREAT | IPC_EXCL error create Semaphore Access flags: 0400 Read by owner 0200 Write by owner 0040 Read by group Access 0020 Write by group Permissions • Creates new Semaphore set with nSems semaphoresif: • - key = IPC_PRIVATE or • - key does not refer to existing Semaphore set • and IPC_CREAT flag specified • If Semaphore set was created or already exist, returns its ID. • Returns -1 in case of error, errno specifies the error. 0004 Read by others 0002 Write by others IPC_CREAT Create if does not exist In combination with IPC_CREAT – return an error, if set already exists IPC_EXCL #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semctl(int semid, int semNum, int cmd, …); • Performs control operations on specified element in Semaphore set. • To remove Semaphore set, used in following form: • semctl(msqid, 0, IPC_RMID); • Returns 0 in success, -1 in case of error (errno specifies the error) • (Other possible operations will be described later) Introduction to Network Programming in UNIX & LINUX

  42. #include <sys/types.h> • #include <sys/ipc.h> • #include <sys/sem.h> • struct sembuf { • ushort_t sem_num; /* semaphore number, beginning from 0 */ • short sem_op; /* semaphore operation */ • short sem_flg; /* operation flags */ • }; • int semop(int semid, struct sembuf * pOps, size_t nOps); Semaphore Operations • Performs set of operations on Semaphore set with specified ID. • Parameter pOps is array of structures, one structure per operation. • Parameter nOps is array length. • Operation type is specified by sem_op field and has the following meaning: • sem_op > 0 : Semaphore[sem_num] += sem_op; • sem_op = 0 : wait while (Semaphore[sem_num] != 0); • sem_op < 0 : wait while (Semaphore[sem_num] < abs(sem_op)); • Semaphore[sem_num] += sem_op; • Field sem_flg could contain the following bit flags: • IPC_NOWAIT – operation to be performed in non-blocking mode • SEM_UNDO – individual operation in the array to be rolled back when the process exits • All set of operations, specified by array, is performed by Kernel as one impartible “atomic” operation. • The execution rule is “all or nothing”: if one of operation fails, all other operations in array are not performed. • The system call semop() blocks (unless the IPC_NOWAIT flag is set), and remains blocked until: • - the semaphore operations can all finish, so the call succeeds, • - the process receives a signal, or • - the semaphore set is removed. • Returns 0 on success, -1 on error (errno specifies the error). Introduction to Network Programming in UNIX & LINUX

  43. Note: • “Eternal” waiting for never arrived “signal” could be avoided by replacing semop() system call with: • int semtimedop( • int semid, • struct sembuf * pOps, • size_t nOps, • struct timespec *timeout); • where: • #include “time.h” • struct timespec { • time_t tv_sec; /* seconds */ • long tv_nsec;/*nanoseconds*/ • }; Example 1: Binary Semaphore as Signal Emulation Device • The Scenario: • We need stateful device with operations: non-blocking “send signal”, and impartible blocking “wait for signal”. • To avoid race condition (signal loss), the initial state of the device would be “waiting for signal” . • The Solution: • “Waiting” state will correspond to 0 value of semaphore, “signal sending” will correspond to ++ operation. /*--- COMMON ---*/ #define THE_SEM_KEY 1357 #define SEM_CLIENT 0 #define SEM_SERVER 1 … int semSigSend(int semID, int semN) /* Semaphore[semN]+=1 */ { struct sembuf pOps[1]; pOps[0].sem_num = semN; pOps[0].sem_op = 1; pOps[0].sem_flg = 0; return semop(semID,pOps,1); } int semSigWait(int semID, int semN) /* wait while (Semaphore[semN] < 1); */ { /* Semaphore[semN] --; // reset to 0 */ struct sembuf pOps[1]; pOps[0].sem_num = semN; pOps[0].sem_op = -1; pOps[0].sem_flg = 0; return semop(semID,pOps,1); } /*--- CLIENT ---*/ … int semID; semID=semget(THE_SEM_KEY, 0, 0666); … semSigSend(semID, SEM_SERVER); semSigWait(semID, SEM_CLIENT); /*-- SERVER ---*/ … int semID; semID=semget(THE_SEM_KEY, 2, 0666|IPC_CREAT); /* initially Semaphore[i] = 0 */ semSigWait(semID, SEM_SERVER); … semSigSend(semID, SEM_CLIENT); Introduction to Network Programming in UNIX & LINUX

  44. int semLock(int semID, int semN) /* wait while (Semaphore[semN] !=0 ); */ { /* Semaphore[semN]++; // i.e. = 1 */ struct sembuf pOps[2]; pOps[0].sem_num = semN; pOps[0].sem_op = 0; pOps[0].sem_flg = 0; /* IPC_NOWAIT to be used for non-blocking mode*/ pOps[1].sem_num = semN; pOps[1].sem_op = 1; pOps[1].sem_flg = SEM_UNDO; /* roll-back the operation on process exit */ return semop(semID, pOps, 2); } int semUnlock(int semID, int semN) /* Semaphore[semN] --; // i.e. = 0 */ { /* would not require blocking */ struct sembuf pOps[1]; pOps[0].sem_num = semN; pOps[0].sem_op = -1; pOps[0].sem_flg = IPC_NOWAIT|SEM_UNDO; /* no block + roll-back on exit */ return semop(semID, pOps, 1); } Note: Locking “forever” by unexpectedly terminated process is avoided by usage of SEM_UNDO flag Example 2: Binary Semaphore as Resource Locking Device • The Scenario: • We need device with 2 states (locked / unlocked) and operations “lock” and “unlock”. • Operation “lock” would be impartible, working in blocking mode, if device already “lock”-ed by another process. • Initial state of device to be “unlocked” to avoid deadlocking forever in case of initialization failure. • The Solution: • “Unlocked” state will correspond to 0 value of semaphore, “locked” state will correspond to value 1. Introduction to Network Programming in UNIX & LINUX

  45. kernel struct semid_ds semid struct sem sem_perm structure semval • - semaphore value • pid of last operation • # awaiting value > x • # awaiting value = 0 sempid semncnt sem_base semzcnt sem_nsems time of last semop - time of last change - sem_otime sem_ctime Control Operations on Semaphore Set #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> union semun { int val; /* for SETVAL */ struct semid_ds *buf; /* for IPC_STAT, IPC_SET */ unsigned short *array; /* for GETALL, SETALL */ }; int semctl (int semid, int semNum, int cmd, … /*union semun arg*/); • Performs control operations on Semaphore set • Parameter cmd could have the following values: • IPC_STAT - copy Semaphore set info to arg.buf • IPC_SET - update Semaphore set permissions and ownership from arg.buf • GETALL,SETALL - get / set semaphore semval values using arg.array (on set adjustment roll-back values • are cleared in all processes, blocked processes are unblocked) • SETVAL - set semval value of semaphore number semNum to be equal val. • (adjustment roll-back value is cleared in all processes, blocked processes are unblocked) • GETVAL,GETPID,GETNCNT, GETZCNT - return correspondedvalues for semaphore number semNum • IPC_RMID - remove Semaphore set (unblocking any blocked processes) • Returns actual value for getter methods, 0 on success for others, -1 on error (errno specifies the error) Example: Unlock method implementation int semUnlock(int semID, int semN) { union semun {int val; struct semid_ds *buff; ushort *array;} arg; arg.val=0; return semctl(semID, semN, SETVAL, arg); } Introduction to Network Programming in UNIX & LINUX

  46. Client Data Length Data Buffer Server Shared Memory Work with Server: semSigSend(); Work with Client: semSigSend(); kernel Start: semTryLock(); Stop: semUnlock(); Start: semLock(); Stop: semUnlock(); Work with Client: semSigWait(); Work with Server: semSigWait(); SEM_CLI_LOCK SEM_CLI_SIG SEM_SER_SIG SEM_SER_LOCK Semaphore Set Example: Shared Memory - based Client-Server Modelwith Semaphore Synchronization Introduction to Network Programming in UNIX & LINUX

  47. Safe Usage of Semaphore • The Problem: • After unexpected termination (for example, with SIGKILL) of process, responsible for Semaphore set deletion, • this unused set could remain until system reboot. • The Proposed Solution: • One of possible solutions (See [1]) is to provide user-defined locking utilities, maintaining the Semaphore • set of 3 semaphores instead of single semaphore, as follows: • The First semaphore is used for lock/unlock operations (as in previous examples) • The Second semaphore is initialized to sufficiently big value and then used as counter of processes, currently • using the Semaphore set. For this purpose user-defiled methods open/close provide decrementing and • incrementing of this counter correspondently. • Knowing the number of processes, which use the Semaphore set, this set may be deleted by the last process, • closing it. • The Third semaphore is used to avoid race condition during Semaphore set (re)creation / closing. • Note: • The problem with unexpectedly terminated last process, responsible to delete Semaphore set, still exists. • But, with implementation described above, it could occur with significantly lower probability. Introduction to Network Programming in UNIX & LINUX

  48. POSIX Semaphores • POSIX provides it’s own standard of Semaphore as Inter-Process or Inter-Thread synchronization device. • POSIX Semaphore is single non-negative integer counter with only 2 possible operations: • Post – Semaphore+=1 (analog of System 5 sem_op=1) • Wait – wait while (Semaphore == 0); Semaphore-=1; (analog of System 5 sem_op=-1) • POSIX defines 2 forms of Semaphores: Named and Unnamed. Named Semaphore– identified by pathname, visible by multiple processes int sem_close(sem_t *sem); #include <semaphore.h> sem_t *sem_open(const char *name, int oflag, …/*mode_t permissions, unsigned int value*/); • Closes the Named Semaphore. • Returns 0 on success, -1 on failure. • Creates new or opens already existing Named Semaphore, • identified by Full Path name , beginning from “/”. • Parameter oflagcould be combined from binary flags • O_CREAT, O_EXCL (see call open() ). • For newly-created Semaphore octal permissions • and initial valueare required. • Returns pointer to Semaphore on success, • SEM_FAILED constant on failure (errno specifies error). int sem_unlink(const char *name); • Removes Named Semaphore. • The name is removed immediatelly. • Semaphore object is destroyed when • sem_close()-d by all processes. • Returns 0 on success, -1 on failure. Unnamed Semaphore – memory-based semaphore allocated in memory shared by multiple processes or threads. int sem_destroy(sem_t *sem); int sem_init(sem_t *sem, int pshared, unsigned int value); • Destroys the Unnamed Semaphore • pointed by sem. • Returns 0 on success, -1 on failure. • Initializes new Unnamed Semaphore in address sem with initial value • for Inter-Process (pshared =1, sem points to shared memory) or • for Inter-Thread (pshared =0)synchronization. • Returns 0 on success, -1 on failure. Semaphore Operations: Post and Wait int sem_post(sem_t *sem); int sem_wait(sem_t *sem); • Increments (unlocks) the Semaphore sem. • Returns 0 on success, -1 on failure. • Waits until Value of Semaphore sem becomes positive, • then decrements (locks) the semaphore. • Returns 0 on success, -1 on failure. Introduction to Network Programming in UNIX & LINUX

  49. BSD Shared Memory #include <unistd.h> #include <sys/mman.h> void *mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset); • Maps a file of specified length, pointed by open descriptor fd, • into the current process memory, pointed by start (may be NULL),beginning from specified offset. • The memory divided into pages (4K). Each page loaded from file once, when was accessed at first time. • Parameter prot specifies the permissions (protection mode - what could be done with segment), • and could have the following values: • PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE • Parameter flags describes the memory sharing modes and visibility: • MAP_FIXED, MAP_SHARED, MAP_PRIVATE, MAP_ANONYMOUS • When map is shared, it could be attached by multiple processes in the same time. • Returns pointer to mapped memory or -1 in case of problem (errno specifies the error) int msync(const void *start, size_t length, int flags); • Synchronizes memory with source file. When shared segment is modified, • the changes do not appear in the file until msync() is called. Example of mmap() usage: int fd; char* pBuff; fd = open("/dev/zero", O_RDWR)); pBuff = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); (void) close(fd); int mprotect(const void *addr, size_t len, int prot); • Modifies the protection mode of the shared memory int munmap(void *start, size_t length); • Unmaps the attached segment. Introduction to Network Programming in UNIX & LINUX

More Related