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 14


    14.1

    The test program is shown in Figure C.14


    Figure C.14. Determine record-locking behavior


    #include "apue.h"
    #include <fcntl.h>
    #include <errno.h>
    void
    sigint(int signo)
    {
    }
    int
    main(void)
    {
    pid_t pid1, pid2, pid3;
    int fd;
    setbuf(stdout, NULL);
    signal_intr(SIGINT, sigint);
    /*
    * Create a file.
    */
    if ((fd = open("lockfile", O_RDWR|O_CREAT, 0666)) < 0)
    err_sys("can't open/create lockfile");
    /*
    * Read-lock the file.
    */
    if ((pid1 = fork()) < 0) {
    err_sys("fork failed");
    } else if (pid1 == 0) { /* child */
    if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
    err_sys("child 1: can't read-lock file");
    printf("child 1: obtained read lock on file\n");
    pause();
    printf("child 1: exit after pause\n");
    exit(0);
    } else { /* parent */
    sleep(2);
    }
    /*
    * Parent continues ... read-lock the file again.
    */
    if ((pid2 = fork()) < 0) {
    err_sys("fork failed");
    } else if (pid2 == 0) { /* child */
    if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
    err_sys("child 2: can't read-lock file");
    printf("child 2: obtained read lock on file\n");
    pause();
    printf("child 2: exit after pause\n");
    exit(0);
    } else { /* parent */
    sleep(2);
    }
    /*
    * Parent continues ... block while trying to write-lock
    * the file.
    */
    if ((pid3 = fork()) < 0) {
    err_sys("fork failed");
    } else if (pid3 == 0) { /* child */
    if (lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0)
    printf("child 3: can't set write lock: %s\n",
    strerror(errno));
    printf("child 3 about to block in write-lock...\n");
    if (lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0)
    err_sys("child 3: can't write-lock file");
    printf("child 3 returned and got write lock????\n");
    pause();
    printf("child 3: exit after pause\n");
    exit(0);
    } else { /* parent */
    sleep(2);
    }
    /*
    * See if a pending write lock will block the next
    * read-lock attempt.
    */
    if (lock_reg(fd, F_SETLK, F_RDLCK, 0, SEEK_SET, 0) < 0)
    printf("parent: can't set read lock: %s\n",
    strerror(errno));
    else
    printf("parent: obtained additional read lock while"
    " write lock is pending\n");
    printf("killing child 1...\n");
    kill(pid1, SIGINT);
    printf("killing child 2...\n");
    kill(pid2, SIGINT);
    printf("killing child 3...\n");
    kill(pid3, SIGINT);
    exit(0);
    }

    On all four systems described in this book, the behavior is the same: additional readers can starve pending writers. Running the program gives us


    child 1: obtained read lock on file
    child 2: obtained read lock on file
    child 3: can't set write lock: Resource temporarily unavailable
    child 3 about to block in write-lock...
    parent: obtained additional read lock while write lock is pending
    killing child 1...
    child 1: exit after pause
    killing child 2...
    child 2: exit after pause
    killing child 3...
    child 3: can't write-lock file: Interrupted system call

    14.2

    Most systems define the fd_set data type to be a structure that contains a single member: an array of long integers. One bit in this array corresponds to each descriptor. The four FD_ macros then manipulate this array of longs, turning specific bits on and off and testing specific bits.

    One reason that the data type is defined to be a structure containing an array and not simply an array is to allow variables of type fd_set to be assigned to one another with the C assignment statement.

    14.3

    Most systems allow us to define the constant FD_SETSIZE before including the header <sys/select.h>. For example, we can write


    #define FD_SETSIZE 2048
    #include <sys/select.h>

    to define the fd_set data type to accommodate 2,048 descriptors. This works on FreeBSD 5.2.1, Mac OS X 10.3, and Solaris 9. Linux 2.4.22 implements things differently.

    14.4

    14.5

    Up to five types of information are returned by getmsg: the data itself, the length of the data, the control information, the length of the control information, and the flags.

    14.6

    Figure C.15 shows an implementation using select.


    Figure C.15. Implementation of sleep_us using select


    #include "apue.h"
    #include <sys/select.h>
    void
    sleep_us(unsigned int nusecs)
    {
    struct timeval tval;
    tval.tv_sec = nusecs / 1000000;
    tval.tv_usec = nusecs % 1000000;
    select(0, NULL, NULL, NULL, &tval);
    }

    Figure C.16 shows an implementation using poll.


    Example C.16. Implementation of sleep_us using poll


    #include <poll.h>
    void
    sleep_us(unsigned int nusecs)
    {
    struct pollfd dummy;
    int timeout;
    if ((timeout = nusecs / 1000) <= 0)
    timeout = 1;
    poll(&dummy, 0, timeout);
    }

    As the BSD usleep(3) manual page states, usleep uses the setitimer interval timer and performs eight system calls each time it's called. It correctly interacts with other timers set by the calling process, and it is not interrupted if a signal is caught.

    14.7

    14.8

    A solution is shown in Figure C.17.


    Figure C.17. Calculation of pipe capacity using nonlocking writes


    #include "apue.h"
    #include <fcntl.h>
    int
    main(void)
    {
    int i, n;
    int fd[2];
    if (pipe(fd) < 0)
    err_sys("pipe error");
    set_fl(fd[1], O_NONBLOCK);
    /*
    * Write 1 byte at a time until pipe is full.
    */
    for (n = 0; ; n++) {
    if ((i = write(fd[1], "a", 1)) != 1) {
    printf("write ret %d, ", i);
    break;
    }
    }
    printf("pipe capacity = %d\n", n);
    exit(0);
    }

    The following table shows the values calculated for our four platforms.

    Platform

    Pipe Capacity (bytes)

    FreeBSD 5.2.1

    16,384

    Linux 2.4.22

    4,096

    Mac OS X 10.3

    8,192

    Solaris 9

    9,216

    These values can differ from the corresponding PIPE_BUF values, because PIPE_BUF is defined to be the maximum amount of data that can be written to a pipe

    atomically . Here, we calculate the amount of data that a pipe can hold independent of any atomicity constraints.

    14.10

    Whether the program in Figure 14.32 updates the last-access time for the input file depends on the operating system and the type of file system on which the file resides.


  • / 369