Advanced Programming in the UNIX Environment: Second Edition [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Advanced Programming in the UNIX Environment: Second Edition [Electronic resources] - نسخه متنی

W. Richard Stevens; Stephen A. Rago

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید






  • Chapter 15


    15.1

    15.2

    The parent terminates right after writing the last line to the pipe. The read end of the pipe is automatically closed when the parent terminates. But the parent is probably running ahead of the child by one pipe buffer, since the child (the pager program) is waiting for us to look at a page of output. If we're running a shell, such as the Korn shell, with interactive command-line editing enabled, the shell probably changes the terminal mode when our parent terminates and the shell prints a prompt. This undoubtedly interferes with the pager program, which has also modified the terminal mode. (Most pager programs set the terminal to noncanonical mode when awaiting input to proceed to the next page.)

    15.3

    The popen function returns a file pointer because the shell is executed. But the shell can't execute the nonexistent command, so it prints


    sh: line 1: ./a.out: No such file or directory

    on the standard error and terminates with an exit status of 127. pclose returns the termination status of the command as it is returned by waitpid.

    15.4

    When the parent terminates, look at its termination status with the shell. For the Bourne shell, Bourne-again shell, and Korn shell, the command is echo $?. The number printed is 128 plus the signal number.

    15.5

    First add the declaration


    FILE *fpin, *fpout;

    Then use fdopen to associate the pipe descriptors with a standard I/O stream, and set the streams to be line buffered. Do this before the while loop that reads from standard input:


    if ((fpin = fdopen(fd2[0], "r")) == NULL)
    err_sys("fdopen error");
    if ((fpout = fdopen(fd1[1], "w")) == NULL)
    err_sys("fdopen error");
    if (setvbuf(fpin, NULL, _IOLBF, 0) < 0)
    err_sys("setvbuf error");
    if (setvbuf(fpout, NULL, _IOLBF, 0) < 0)
    err_sys("setvbuf error");

    The write and read in the while loop are replaced with


    if (fputs(line, fpout) == EOF)
    err_sys("fputs error to pipe");
    if (fgets(line, MAXLINE, fpin) == NULL) {
    err_msg("child closed pipe");
    break;
    }

    15.6

    15.7

    The select function indicates that the descriptor is readable. When we call read after all the data has been read, it returns 0 to indicate the end of file. But with poll (assuming a STREAMS-based pipe), the POLLHUP event is returned, and this event may be returned while there is still data to be read. Once we have read all the data, however, read returns 0 to indicate the end of file. After all the data has been read, the POLLIN event is not returned, even though we need to issue a read to receive the end-of-file notification (the return of 0).

    With an output descriptor that refers to a pipe that has been closed by the reader, select indicates that the descriptor is writable. But when we call write, the SIGPIPE signal is generated. If we either ignore this signal or return from its signal handler, write returns an error of EPIPE. With poll, however, if the pipe is STREAMS based, poll returns with a POLLHUP event for the descriptor.

    15.8

    Anything written by the child to standard error appears wherever the parent's standard error would appear. To send standard error back to the parent, include the shell redirection 2>&1 in the

    cmdstring .

    15.9

    The popen function forks a child, and the child executes the shell. The shell in turn calls fork, and the child of the shell executes the command string. When

    cmdstring terminates, the shell is waiting for this to happen. The shell then exits, which is what the waitpid in pclose is waiting for.

    15.10

    The trick is to open the FIFO twice: once for reading and once for writing. We never use the descriptor that is opened for writing, but leaving that descriptor open prevents an end of file from being generated when the number of clients goes from 1 to 0. Opening the FIFO twice requires some care, as a nonblocking open is required. We have to do a nonblocking, read-only open first, followed by a blocking open for write-only. (If we tried a nonblocking open for write-only first, it would return an error.) We then turn off nonblocking for the read descriptor. Figure C.18 shows the code for this.


    Figure C.18. Opening a FIFO for reading and writing, without blocking


    #include "apue.h"
    #include <fcntl.h>
    #define FIFO "temp.fifo"
    int
    main(void)
    {
    int fdread, fdwrite;
    unlink(FIFO);
    if (mkfifo(FIFO, FILE_MODE) < 0)
    err_sys("mkfifo error");
    if ((fdread = open(FIFO, O_RDONLY | O_NONBLOCK)) < 0)
    err_sys("open error for reading");
    if ((fdwrite = open(FIFO, O_WRONLY)) < 0)
    err_sys("open error for writing");
    clr_fl(fdread, O_NONBLOCK);
    exit(0);
    }

    15.11

    Randomly reading a message from an active queue would interfere with the clientserver protocol, as either a client request or a server's response would be lost. To read the queue, all that is needed is for the process to know the identifier for the queue and for the queue to allow world-read access.

    15.13

    We never store actual addresses in a shared memory segment, since it's possible for the server and all the clients to attach the segment at different addresses. Instead, when a linked list is built in a shared memory segment, the list pointers should be stored as offsets to other objects in the shared memory segment. These offsets are formed by subtracting the start of the shared memory segment from the actual address of the object.

    15.14

    Figure 15.33

    Parent i set to

    Child i set to

    Shared value set to

    update returns

    Comment

    0

    initialized by mmap

    1

    child runs first, then is blocked 0 parent runs

    0

    parent runs

    1

    0

    then parent is blocked

    2

    child resumes

    1

    3

    then child is blocked

    2

    parent resumes

    3

    2

    then parent is blocked

    4

    3

    5

    then child is blocked

    4

    parent resumes

  • / 369