TDC368 UNIX and Network Programming - PowerPoint PPT Presentation

About This Presentation
Title:

TDC368 UNIX and Network Programming

Description:

cat PIPE. UNIX Network Programming TDC368-901. Page 5 ... Systems Calls/Commands (Common UNIX signals (pp.266-270 textbook Stevens) kill system call ... – PowerPoint PPT presentation

Number of Views:178
Avg rating:3.0/5.0
Slides: 40
Provided by: condor2
Category:

less

Transcript and Presenter's Notes

Title: TDC368 UNIX and Network Programming


1
TDC368UNIX and Network Programming
  • Week 5-6
  • Named Pipe
  • Asynchronous Events UNIX Signals
  • Camelia Zlatea, PhD
  • Email czlatea_at_cs.depaul.edu

2
Overview Pipe Inter Process Communication (IPC )
  • Pipes
  • internally are called FIFO files
  • can be read or written only sequentially
  • comparing with regular files FIFO files (or
    pipes) use only directly addressable blocks (for
    this reason there is a limit for the maximum size
    of the pipe PIPE_BUF (defined in ltlimits.hgt)
  • at a given time only one process can access a
    FIFO file for reading or writing
  • Operations On Pipes
  • open, read, write, close
  • a read operation always succeeds on pipe (FIFO
    file). If the pipe is empty then
    the process sleeps until the pipe is written by
    another process. Otherwise the read function will
    return the actual number of bytes read.
  • a write operation on pipe will succeed if there
    is enough space to write into the FIFO file.
    Otherwise, the process that called write will
    sleep until the pipe is read from by another
    process, thus more space is created
  • if there are processes sleeping on read request
    and the last writer process closes the pipe, then
    the sleeping processes are wake-up and return 0
    bytes.
  • if there are processes sleeping on write request
    and the last reader process closes the pipe, then
    the sleeping processes are sent an error signal.

3
Unamed Pipe ( see also TDC368_week3_4.ppt)
  • A template to implement communication via unnamed
    pipes
  • 1.      create the pipe(s) necessaries
  • 2.      generate the child process(es)
  • 3.      close/duplicate file descriptors to
    associate correctly the ends of the
  • pipe
  • 4.      close the unneeded file descriptors (ends
    of the pipe)
  • 5.      execute necessaries operations
  • 6.      close the remaining file descriptors for
    more accuracy, wait for child
  • process to terminate

4
Named Pipes
  • Concept
  • special file of type FIFO
  • an inod is associated with the named pipe
  • named pipe has a directory entry
  • difference between ordinary files and named pipes
    is in how read and write operations are
    synchronized when accessing the file. Kernel
    ensures that a read does not wait on an empty
    pipe, nor a write wait on a full pipe. In these
    cases the processes will sleep, and they will be
    wake-up when the required event take place.
  • can be shared by unrelated processes
  • Create a named pipe at the shell level
  • mknod file_pipe p
  • - argument file_pipe is the name of the pipe
  • argument p notifies mknod to create a named
    pipe
  • file type for file_pipe is p (see ls -l
    file_pipe)
  • mkfifo p file_pipe ( use this on hawk )
  • Example
  • mkfifo p PIPE
  • ls - l gt PIPE
  • cat lt PIPE

5
Named Pipes
  • System call to generate a named pipe - mknod
  • include ltsys/types.hgt
  • include ltsys/stat.hgt
  • int mknod(const char path, mode_t, 0) / for
    non-privileged users /
  • UNIX I/O function - mkfifo
  • include ltsys/types.hgt
  • include ltsys/stat.hgt
  • int mkfifo(const char path, mode_t mode)

6
Asynchronous Events
  • Examples of process events
  • a signal from another process
  • an interrupt from a device
  • completion of a I/O request
  • Signals are events delivered to a process via
    UNIX. The process has no control over when they
    arrive. Signals are understood as software
    version of hardware interrupts.
  • Signals can be generated by
  • hardware ex division by zero, illegal address
    access
  • kernel ex completion of a I/O request issued by
    the waiting process
  • user processes ex communication among processes
    related to relevant events, child termination
    notified to parent
  • user actions ex pressing the keyboard sequence
    for quit, interrupt
  • To find the current mapping of the key sequences
    for various signals, call shell command stty -a
  • Example SIGINT is mapped to "ctrl c" (or DEL)

7
Some important signals
  • Signal SigNr Default Meaning
  • SIGALARM 14 EXit Setting an allarm clock
  • SIGCHLD 18 Ignore Child status changed
  • SIGFPF 8 Exit,core Arithmetic exception
  • SIGHUP 1 Exit Hangup
  • SIGINT 2 Exit Interrupt
  • SIGKILL 9 Exit Killed
  • SIGQUIT 3 Exit,core Quit
  • SIGSTOP 23 Stop Stopped (signal)
  • SIGTERM 15 Exit Terminated
  • SIGUSR1 16 Exit User signal 1
  • SIGUSR2 17 Exit User signal 2

8
Systems Calls/Commands (Common UNIX signals
(pp.266-270 textbook Stevens)
  • kill system call
  • sends a signal to a process
  • include ltsys/types.hgt
  • include ltsignal.hgt
  • int kill(pid_t pid, int signo)
  • the argument pid determines how the signal is
    handled and to which process it applies.
  • if pid gt 0 then the signal applies to process
    with ID pid
  • if pid 0 then the signal applies to all
    processes from the Process Group
  • if pid -1 then the signal applies to all
    processes with UID EUID of sender
  • UNIX exploits the power of the superuser in a
    clever manner. For example to execute command
    df (display disk free blocks) the process need
    to red bloc 0, where this information resides.
    Superuser is able to read bloc 0, but not a
    non-privileged user. In this case executable df
    has setuid bit set on. This bit is part of the
    protectiin mode word, whose protection part uses
    only 9bits (the other being left for other
    purposes). Thus, when a user calls df , the
    effective EUID of process df becomes equal with
    UID of the superuser.
  • if pid lt -1 then the signal applies to all
    processes in the process group with GID pid
    the argument signo - the signal number.
  • kill command kill -signal pid1 pid2 .
  • kill -l list all signals known by kill

9
More about kill
  • kill 0 pid --- test to see of process pid is
    still in the system
  • kill(pid, 0) --- test to see of process pid is
    still in the system

10
Unix System Calls to handle signals
  • Signal system call is used to install signal
    handlers.
  • / legacy UNIX API /
  • include ltsignal.hgt
  • void (signal(int signo, void
    (handler)(int)))(int)
  • include ltsignal.hgt
  • void (sigset (int sig_no, void
    (handler)(int)))(int)
  • The second parameter of the signal system call
    is a pointer to a function that returns void and
    takes a single integer as its argument, and the
    return value of signal itself is a pointer to a
    function that returns void and takes a single
    integer argument.
  • The second parameter to signal is a pointer to
    the function to call whenever the signal is
    delivered.
  • The return value is the previous signal handler
    that was installed before the new one was added.

11
Calling prototype for signal() and sigset()
  • signal() and sigset() take two arguments, an
    integer sig and a pointer to a function,
    catcher() that returns nothing, to be called when
    sig occurs
  • if invocation of signal() is successful it
    returns a pointer to the previous disposition of
    catcher() function
  • if invocation of sigset() is successful and sig
    is not blocked it returns a pointer to the
    previous disposition of catcher()
  • if invocation of sigset() is successful and sig
    is blocked it returns SIG HOLD
  • (int) at the end of prototype indicate that
    catcher() takes an integer (sig number) as
    argument

12
Signal management
  • A process can associate a signal catching
    function with every signal by either signal() or
    sigset() system calls
  • Upon the receipt of a signal for which a
    catcher() is installed the system calls catcher()
    to process the signal
  • the catcher() must be reinstalled in order to
    catch other signals however, race conditions may
    occur in this way
  • ONLY when using signal() system call

13
Signal Acceptance
  • Signals can be generated by outside events.
  • When a process receives a signal then the
    following actions can be taken
  • ignore the signal
  • terminate the process (the default action
    SIG_DFL)
  • process the signal - take a particular action

14
Signal Acceptance
  • Ignore the signal
  • Program that ignores control-C. When an INT
    signal (control-C) is
  • Received, the process ignores it (SIG_IGN is the
    handler)
  • include ltstdio.hgt
  • include ltsys/types.hgt
  • include ltsignal.hgt
  • int main (void)
  • signal (SIGINT, SIG_IGN)
  • while(1)
  • printf("Hello\n")

15
Signal Acceptance
  • 2. Terminate the process (the default action
    SIG_DFL)
  • Default action (see manual pages man signal) is
    the action executed if nothing else
  • include ltiostream.hgt
  • include ltsignal.hgt
  • int main()
  • signal(SIGINT, SIG_DFL) / catch signal
    SIGINT2 /
  • pause()
  • / wait for a signal interruption
    /

16
Terminate the process (the default action SIG_DFL)
  • Default action (see manual pages man signal) is
    the action executed if nothing else is specified
    related to a particular signal
  • exit - executes all actions associated with exit
    system call
  • include ltunistd.hgt
  • void _exit(int status)
  • When terminating a process the following actions
    are performed
  • all open file descriptors are closed
  • child notifies termination to his parent by
    signaling SIGCHLD
  • if parent is waiting for the child to terminate,
    then status information is returned to it.
  • all children of the terminating process will have
    their PPID set to 1 (init process adopts them)
  • if terminating process is a group leader, then al
    the group members will be sent SIGHUP or SIGCONT
    signals
  • core - generate a file - core image and then
    exit
  • stop - suspend the execution of the process
    (SIGSTOP cannot be caught or ignored)
  • ignore - the signal has no effect on the process

17
Signal Acceptance
  • 3. Handle the signal - Take a particular action
  • The target process executes the action associated
    with the signal.
  • Processing the signal depends also on the state
    of the process and level of priority. Signals can
    be caught by specifying a signal catching
    routine.
  • The signals SIGKILL and SIGSTOP are never caught
    and they always terminate a process.
  • include ltstdio.hgt
  • include ltsys/types.hgt
  • include ltsignal.hgt
  • void action (int sig)
  • signal (SIGINT, action)
  • printf ("control-C won't
    stop this
  • process!\n")

int main (void) signal (SIGINT,
action) while(1) printf("Hello\n")
18
Handle the signal - Take a particular action
(cont)
  • The action taken when a signal is generated
    depends on
  •         signal handler
  •         process signal mask
  • Process signal mask (data structure part of the
    process table managed by the kernel) shows which
    signals are being ignored, which are being
    caught, which are being temporarily blocked and
    which are in the process of being delivered.
  • A blocked signal is not the same as an ignored
    signal. Its action is delayed until the process
    unblocks the pending signal.

19
Signal Handling Example
  • include ltstdio.hgt
  • include ltsignal.hgt
  • / signal handler function /
  • void action(int sig_no)
  • signal(sig_no, action)
  • fprintf(stderr,"Catch signal
    d\n", sig_no)
  • int main()
  • signal(SIGINT, action)
  • signal(SIGALRM, SIG_DFL)
  • signal(SIGTERM, SIG_IGN)
  • pause()
  • / wait for a signal interruption
    /

20
Delay execution
  • Pause system calll 
  • pause system call suspends the calling process
    until a signal (which is not ignored) will be
    received
  • by invoking pause the process will no longer use
    CPU , while waiting for the event thus busy
    waiting is avoided
  • include ltunistd.hgt
  • unsigned pause()

21
Alarm Handling
  • Alarm system function
  • Sets a timer for the caller process and generates
    SIGALRM (signal number 14) after the specified
    number of seconds have passed.
  • include ltunistd.hgt
  • unsigned alarm(unsigned
    nosec)

22
Alarm Handling
  • Example, alarm system calls cannot be stacked

alarm(10) alarm(20) // when this system call
is invoked // the previous pending // alarm
signal is canceled // the timer is set to 20sec
alarm(0) // this system call reset the timer,
// any pending alarm system
call is canceled
int main(void) alarm(20) while (1)
fprintf(stderr,"Hello\n")
23
Simulating sleep by using alarm and pause
  • //
  • // Simulating sleep by using alarm and
    pause
  • //
  • include ltstdio.hgt
  • include ltsignal.hgt
  • include ltunistd.hgt
  •  
  • void wakeup()
  • unsigned int sleep ( unsigned int timer )
  •  
  • if (sigset(SIGALRM, wakeup)-1)
  • perror("sigset") return 1
  •  
  • (void)alarm( timer )
  • (void)pause()
  • return 0

24
Example of Handling Time-out Situations
  • include ltstdio.hgt
  • include ltunistd.hgt
  • include ltsignal.hgt
  • int main(void)
  • char buf256
  • int n
  • signal(SIGALRM, timeout)
  • alarm(30) // set timer
  • while ((nread(0,buf,sizeof(bu
    f))lt0)
  • alarm(0) // reset timer
  • exit(0)

void timeout() fprintf(stderr,"Timeout
error\n") exit(0)
25
Example
  • A parent forks 10 children processes, each child
    sleep a random number of seconds . Parent process
    waits for child processes to terminate. Once a
    child process has terminated, then the parent
    will terminate all the remaining child processes,
    by signaling SIGTERM to each of them.
  • include ltstdio.hgt
  • include ltsys/types.hgt
  • include ltunistd.hgt
  • include ltsys/wait.hgt
  • include ltsignal.hgt
  • include ltstdlib.hgt
  • int main()
  • pid_t p, q
  • int i, n, status
  • for (i0 ilt10 i)
  • if ((pfork())lt0) fprintf(stderr, "cannot
    fork\n") exit(1)
  • if (pid 0) break

26
Example variant 1
  • if (p0) / child code /
  • n (int)(getpid()256)
  • srand((unsigned)pid)
  • sleep(rand() 5)
  • else / parent code /
  • if ((qwaitpid(0,status,0))gt0)
  • kill(0,SIGTERM)
  • while ((qwait(status)) q !-1)
  • if (q!-1)
  • if (WIFSIGNALED(status))
  • fprintf(stderr, "Child with PID d
    has received signal 04X\n",q,WTERMSIG(status)
  • exit(0)

27
Examplevariant 2
  • if (p0) / child code /
  • signal(SIGTERM, action)
  • n (int)(getpid()256)
  • srand((unsigned)pid)
  • sleep(rand() 5)
  • else / parent code /
  • if ((qwaitpid(0,status,0))gt0)
  • kill(0,SIGTERM)
  • while ((qwait(status)) q !-1)
  • if (q!-1)
  • if (WIFSIGNALED(status))
  • fprintf(stderr, "Child with PID d
    has received signal 04X\n",q,WTERMSIG(status)
  • exit(0)

void action() pid_t pid pidgetpid()
fprintf(stderr, "Child with PID d is
terminating with SIGTERM\n",pid) kill(pid,
SIGTERM) / raise(SIGTERM) /
28
Solutions for Concurrency and I/O Non-determinism
  • Use nonblocking I/O
  • use fcntl() to set O_NONBLOCK
  • Use alarm and signal handler to interrupt slow
    system calls.
  • Use multiple processes/threads.
  • Use functions that support checking of multiple
    input sources at the same time.

29
Non blocking I/O
  • use fcntl() to set O_NONBLOCK
  • include ltsys/types.hgt
  • include ltfcntl.hgt
  • int flags
  • int pipe_fd2
  • .
  • flags fcntl(pipe_fd,F_GETFL,0)
  • fcntl(pipe_fd,F_SETFL,flags O_NONBLOCK)
  • Now calls to read() (and other system calls) will
    return an error and set errno to EWOULDBLOCK.

30
  • while (! done)
  • if ( (nread(STDIN_FILENO,)lt0))
  • if (errno ! EWOULDBLOCK)
  • / ERROR /
  • else write(pipe_fd1,)
  • if ( (nread(pipe_fd0,)lt0))
  • if (errno ! EWOULDBLOCK)
  • / ERROR /
  • else write(STDOUT_FILENO,)

31
The problem with nonblocking I/O
  • Using blocking I/O allows the Operating System to
    put the process to sleep when nothing is
    happening (no input). Once input arrives the OS
    will wake up the process and read() (or write()
    ) will return.
  • With nonblocking I/O the process will
    busy-wait, using inefficiently the CPU time

32
Using alarms
  • Time-out handling with alarms
  • signal(SIGALRM, sig_alrm)
  • alarm(MAX_TIME)
  • read(STDIN_FILENO,)
  • ...
  • signal(SIGALRM, sig_alrm)
  • alarm(MAX_TIME)
  • read(fd_pipe,)
  • ...
  • Issues
  • How to assess the impact on response time ?
  • How to choose the value for MAX_TIME?

33
Using sigset()
  • sigset() makes use of a signal mask of type
    sigset t (array of long integers) where signals
    to be blocked are recorded
  • when sigset() is called the system add the sig
    value to the process's current signal mask before
    executing the catcher.
  • when catcher() finishes the system restores the
    signal mask hence, unlike signal(), sigset()
    installed catcher() remain installed after the
    call.
  • when successful, sigset() returns either SIG
    HOLD, indicating that signal was previously
    blocked, or the disposition previously associated
    with the signal.

34
Example using sigset()
  • / Catching signals with sigset() /
  • include ltstdio.hgt
  • include ltsignal.hgt
  • include ltunistd.hgt
  • include ltstdlib.hgt
  • extern int errno
  • int main(void)
  • int i
  • void SigCatcher(int)
  • if (sigset(SIGINT, SigCatcher) SIG_ERR)
  • perror(''Sigset cannot set SIGINT'')
  • exit(SIGINT)
  • if (sigset(SIGQUIT, SigCatcher) SIG_ERR)
  • perror(''Sigset cannot set SIGQUIT'')
  • exit(SIGQUIT)

35
Example using sigset()
  • for (i 0 i) / loop forever /
  • printf(''i dn'', i)
  • sleep(1)
  • void SigCatcher( int signum)
  • printf(''\nSignal d received.\n'', signum)
  • if (signum SIGQUIT)
  • exit(1)

36
Manipulating signal mask
  • a call to int sighold( int sig ) will add sig to
    the calling process signal mask
  • a call to int sigrelse( int sig ) will remove
    sig from the calling process signal mask
  • a call to int sigpause( int sig ) will remove
    sig from the signal mask and will suspend process
    until sig is received
  • a call to int sigignore( int sig ) will cause
    sig to be ignored (achievable by signal(sig,
    SIG_IGN))

37
Example Demonstration of sighold() and sigset()
  • Example
  • / Demonstration of sighold() and sigset() /
  • / Execute with a.out then type ''kill USR1
    pid'' and ''kill USR2 pid'' /
  • include ltstdio.hgt
  • include ltsignal.hgt
  • include ltunistd.hgt
  • void SigCatcher( int n )
  • printf(''Received signal d will release SIGUSR1
    \n'', n)
  • sigrelse(SIGUSR1)
  • printf(''SIGUSR1 released! \n'')
  • int main(void)
  • sighold(SIGUSR1) / block signals SIGUSR1 /
  • sigset (SIGUSR2, SigCatcher) / catch signals
    SIGUSR2 /
  • printf(''Waiting for signals\n'')

38
Using sigpause() system call
  • / Pausing with sigpause() /
  • / Run with a.out then type ''kill USR1 pid
    /
  • / Try to kill process by ''kill INT pid'' after
    ''Beginning ...'' /
  • include ltstdio.hgt
  • include ltsignal.hgt
  • include ltunistd.hgt
  • void main(void)
  • void SigCatcher(int)
  • sigset(SIGUSR1, SigCatcher)
  • while ( 1 ) / repeat forever /
  • printf(''Waiting for signal d \n'', SIGUSR1)
  • sigpause (SIGUSR1)

void SigCatcher(int n) sighold(SIGINT)
sighold(SIGTERM) printf(''Beginning important
stuff\n'') sleep(10) printf(''Ending
important stuff\n'') sigrelse(SIGTERM)
sigrelse(SIGINT)
39
Observations
  • When SIGUSR1 is received the signal catching
    function is executed during this time SIGINT and
    SIGTERM are blocked
  • A set of messages indicating the beginning and
    the end of an important section of code are
    displayed
  • SIGINT and SIGTERM are then released
  • hence typing ''kill INT pid'' will terminate
    the process.
Write a Comment
User Comments (0)
About PowerShow.com