APUE函数笔记十二: 高级IO

58 篇文章 0 订阅
49 篇文章 0 订阅

第十四章  高级IO:

#include <fcntl.h>
int fcntl(int filedes, int cmd, ... /* struct flock * flockptr */);
    if error return -1
    cmd: F_GETLK, F_SETLK, F_SETLKW
    struct flock {
        short   l_type;   /* F_RDLCK, F_WRLCK, F_UNLCK */
        off_t   l_start;  /* offset in bytes, relative to l_whence */
        short   l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
        off_t   l_len;    /* length, in bytes, 0 means lock to EOF */
        pid_t   l_pid;    /* returned with F_GETLK */
    };
    errno: EACCES, EAGAIN

#include <stropts.h>
int putmsg(int filedes, const struct strbuf * ctlptr, 
           const struct strbuf * dataptr, int flag);
    if success return 0, if error return -1
int putmsg(int filedes, const struct strbuf * ctlptr, 
           const struct strbuf * dataptr, int band, int flag);
    if success return 0, if error return -1
    struct strbuf {
        int     maxlen;
        int     len;
        char  * buf;
    };

#include <stropts.h>
int isastream(int filedes);
    if fd is a STREAMS dev return 1, else return 0

struct str_list {
    int                sl_nmods;   /* number of entries in array */
    struct str_mlist * sl_modlist; /* ptr to first element of array */
};

struct str_mlist {
    char l_name[FMNAMESZ+1]; /* null terminated module name */
};
FMNAMESZ defined in sys/conf.h, it is 8 usually

#include <stropts.h>
int getmsg(int filedes, struct strbuf * restrict ctlptr, 
           struct strbuf * restrict dataptr, int * restrict flagptr);
    if success ret > 0, else error ret == -1
int getpmsg(int filedes, struct strbuf * restrict ctlptr, 
            struct strbuf * restrict dataptr, int * restrict bandptr, 
            int * restrict flagptr);
    if success ret > 0, else error ret == -1

#include <sys/select.h>
int select(int maxfdp1, fd_set * restrict readfds, 
           fd_set * restrict writefds, fd_set * restrict exceptfds, 
           struct timeval * restrict tvptr);
    tvptr may be changed
    if tvptr == NULL:
        wait forever
    else if tvptr->tv_sec == 0 && tvptr->tv_usec == 0:
        no wait
    else:
        wait for tvptr
    success return ready-des-count, timeout return 0, error return -1

#include <sys/select.h>
int FD_ISSET(int fd, fd_set * fdset);
    if true return non-zero, else return zero
void FD_CLR(int fd, fd_set * fdset);
void FD_SET(int fd, fd_set * fdset);
void FD_ZERO(fd_set * fdset);

#include <sys/select.h>
int pselect(int maxfdp1, fd_set * restrict readfds, 
            fd_set * restrict writefds, fd_set * restrict exceptfds, 
            const struct timespec * restrict tsptr, 
            const sigset_t * restrict sigmask); 
    tsptr cannot be changed
    when call pselect, signal-mask be atomic to set as sigmask,
    when return, signal-mask will be set back to it was
    success return ready-des-count, timeout return 0, error return -1

#include <poll.h>
int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);
    timeout == -1: wait forever
    timeout == 0:  no wait
    timeout > 0:   wait for timeout ms
    success return ready-des-count, timeout return 0, error return -1
    struct pollfd {
        int    fd;       /* file descriptor to check, or < 0 to ignore */
        short  events;   /* events of interest on fd */
        short  revents;  /* events that occurred on fd */
    };
    events:
        POLLIN,  POLLRDNORM, POLLRDBAND, POLLPRI  /* read */
        POLLOUT, POLLWRNORM, POLLWRBAND           /* write */
    revents:
        POLLIN,  POLLRDNORM, POLLRDBAND, POLLPRI  /* read */
        POLLOUT, POLLWRNORM, POLLWRBAND           /* write */
        POLLERR, POLLHUP, POLLNVAL                /* except */

#include <sys/uio.h>
ssize_t readv(int filedes, const struct iovec * iov, int iovcnt);
    success return total-read-bytes-count, error return -1
ssize_t writev(int filedes, const struct iovec * iov, int iovcnt);
    success return total-write-bytes-count, error return -1
    struct iovec {
        void  * iov_base; /* starting address of buffer */
        size_t  iov_len;  /* size of buffer */
    };

#include <sys/mman.h>
void * mmap(void * addr, size_t len, int prot, 
            int flag, int filedes, off_t off);
    prot:
        PROT_READ, PROT_WRITE, PROT_EXEC, PROT_NONE
    flag:
        MAP_FIXED, MAP_SHARED, MAP_PRIVATE
    (off % pagesize) and (addr % pagesize) should be 0
    pagesize can get with sysconf(_SC_PAGESIZE/_SC_PAGE_SIZE)
    if success return map-addr, else error return MAP_FAILED

#include <sys/mman.h>
int mprotect(void * addr, size_t len, int prot);
    prot:
        PROT_READ, PROT_WRITE, PROT_EXEC, PROT_NONE
    if success return 0, else error return -1

#include <sys/mman.h>
int msync(void * addr, size_t len, int flags);
    flag:
        MS_ASYNC, MS_SYNC, MS_INVALIDATE
    if success return 0, else error return -1

#include <sys/mman.h>
int munmap(void * addr, size_t len);
    if success return 0, else error return -1

示例:

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int 
lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
    struct flock lock;

    lock.l_type = type;
    lock.l_start = offset;
    lock.l_whence = whence;
    lock.l_len = len;

    return(fcntl(fd, cmd, &lock));
}

int read_lock(int fd, off_t offset, int whence, off_t len)
{
    return(lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len));
}

int readw_lock(int fd, off_t offset, int whence, off_t len)
{
    return(lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len));
}

int write_lock(int fd, off_t offset, int whence, off_t len)
{
    return(lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len));
}

int writew_lock(int fd, off_t offset, int whence, off_t len)
{
    return(lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len));
}

int un_lock(int fd, off_t offset, int whence, off_t len)
{
    return(lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len));
}

pid_t 
lock_test(int fd, int type, off_t offset, int whence, off_t len)
{
    struct flock lock;

    lock.l_type = type;
    lock.l_start = offset;
    lock.l_whence = whence;
    lock.l_len = len;

    if (fcntl(fd, F_GETLK, &lock) < 0) {
        printf("fcntl error: %s\n", strerror(errno));
        exit(1);
    }

    if (lock.l_type = F_UNLCK) {
        return(0);
    }
    return(lock.l_pid);
}

/* can current process */
int is_read_lockable(fd, offset, whence, len)
{
    return(lock_test(fd, F_RDLCK, offset, whence, len) == 0);
}

/* can current process */
int is_write_lockable(fd, offset, whence, len)
{
    return(lock_test(fd, F_WRLCK, offset, whence, len) == 0);
}

int 
lockfile(int fd)
{
    struct flock lock;

    lock.l_type = F_WRLCK;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;

    return(fcntl(fd, F_SETLK, &lock));
}

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#include "changefileflag.h"

char buf[500000];

int 
main(void)
{
    int      ntowrite;
    int      nwrite;
    char   * ptr;

    ntowrite = read(STDIN_FILENO, buf, sizeof(buf));
    fprintf(stderr, "read %d bytes\n", ntowrite);

    set_fl(STDOUT_FILENO, O_NONBLOCK); /* set nonblocking */

    ptr = buf;
    while (ntowrite > 0) {
        errno = 0;
        nwrite = write(STDOUT_FILENO, ptr, ntowrite);
        fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno);

        if (nwrite > 0) {
            ptr += nwrite;
            ntowrite -= nwrite;
        }
    }
}

#include <fcntl.h>

#include "waitfor.h"
#include "filelock.h"

void 
lockabyte(const char * name, int fd, off_t offset)
{
    if (writew_lock(fd, offset, SEEK_SET, 1) < 0) {
        printf("%s: writew_lock error: %s\n", name, strerror(errno));
    }
    else {
        printf("%s: got the lock, byte %ld\n", name, offset);
    }
}

int 
main(void)
{
    int      fd;
    pid_t    pid;

    /*
     * create a file and write two bytes to it
     */
    if ((fd = creat("templock", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
        printf("creat error\n");
        exit(1);
    }
    if (write(fd, "ab", 2) != 2) {
        printf("write error\n");
        exit(1);
    }

    TELL_WAIT();
    if ((pid = fork()) < 0) {
        printf("fork error\n");
        exit(1);
    }
    else if (pid == 0) {
        lockabyte("child", fd, 0);
        TELL_PARENT(getppid());
        WAIT_PARENT();
        lockabyte("child", fd, 1);
    }
    else {
        lockabyte("parent", fd, 1);
        TELL_CHILD(pid);
        WAIT_CHILD();
        lockabyte("parent", fd, 0);
    }
    exit(0);
}

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>

#include "waitfor.h"
#include "filelock.h"
#include "changefileflag.h"

int 
main(int argc, char * argv[])
{
    int         fd;
    pid_t       pid;
    char        buf[5];
    struct stat statbuf;

    if (argc != 2) {
        fprintf(stderr, "usage: %s filename\n", argv[0]);
        exit(1);
    }
    if ((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
        printf("open error\n");
        exit(1);
    }
    if (write(fd, "abcdef", 6) != 6) {
        printf("write error\n");
        exit(1);
    }

    /* turn on set-group-id and turn off group-execute */
    if (fstat(fd, &statbuf) < 0) {
        printf("fstat error\n");
        exit(1);
    }
    if (fchmod(fd, (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) {
        printf("fchmod error\n");
        exit(1);
    }

    TELL_WAIT();

    if ((pid = fork()) < 0) {
        printf("fork error\n");
        exit(1);
    }
    else if (pid > 0) {
        /* write lock entire file */
        if (write_lock(fd, 0, SEEK_SET, 0) < 0) {
            printf("write_lock error\n");
            exit(1);
        }

        TELL_CHILD(pid);

        if (waitpid(pid, NULL, 0) < 0) {
            printf("waitpid error\n");
            exit(1);
        }
    }
    else {
        WAIT_PARENT();

        set_fl(fd, O_NONBLOCK);

        /* first let's see what error we get if region is locked */
        if (read_lock(fd, 0, SEEK_SET, 0) != -1) { /* no wait */
            printf("child: read_lock successded\n");
            exit(1);
        }
        printf("read_lock of already-locked region returns %d\n", errno);

        /* now try to read the mandatory locked file */
        if (lseek(fd, 0, SEEK_SET) == -1) {
            printf("lseek error\n");
            exit(1);
        }
        if (read(fd, buf, 2) < 0) {
            printf("read failed (mandatory locking works)\n");
        }
        else {
            printf("read OK (no mandatory locking), buf = %2.2s\n", buf);
        }
    }
}

#include <stropts.h>
#include <unistd.h>

int 
isastream(int filedes)
{
    return(ioctl(filedes, I_CANPUT, 0) != -1);
}

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

int 
main(int argc, char * argv[])
{
    int   i;
    int   fd;

    for (i = 1; i < argc; ++i) {
        errno = 0;
        if ((fd = open(argv[i], O_RDONLY)) , 0) {
            printf("%s: cannot open: %s\n", argv[i], strerror(errno));
            continue;
        }
        if (isastream(fd) == 0) {
            printf("%s: not a stream\n", argv[i]);
        }
        else {
            printf("%s: streams device\n", argv[i]);
        }
    }
}

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stropts.h>

/* no such file in Linux */
/* #include <sys/conf.h> */

int 
main(int argc, char * argv[])
{
    int             i;
    int             fd;
    int             nmods;
    struct str_list list;

    if (argc != 2) {
        printf("usage: %s pathname\n", argv[0]);
        exit(1);
    }

    if ((fd = open(argv[1], O_RDONLY)) < 0) {
        printf("cannot open %s\n", argv[1]);
        exit(1);
    }
    if (isastream(fd) == 0) {
        printf("%s is not a stream\n", argv[1]);
        exit(1);
    }

    /*
     * fetch number of modules
     */
    if ((nmods = ioctl(fd, I_LIST, (void *)0)) < 0) {
        printf("I_LIST error for nmods\n");
        exit(1);
    }
    printf("#modules = %d\n", nmods);

    /*
     * allocate storage for all the module names
     */
    list.sl_modlist = calloc(nmods, sizeof(struct str_mlist));
    if (list.sl_modlist == NULL) {
        printf("calloc error\n");
        exit(1);
    }
    list.sl_nmods = nmods;

    /*
     * fetch the module names
     */
    if (ioctl(fd, I_LIST, &list) < 0) {
        printf("I_LIST error for list\n");
        exit(1);
    }

    /*
     * print the names
     */
    for (i = 1; i <= nmods; ++i) {
         printf("  %s: %s\n", (i == nmods) ? "driver" : "module", 
                list.sl_modlist++->l_name);
    }
    exit(0);
}

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stropts.h>

#define BUFFSIZE (4096)

int 
main(void)
{
    int           n;
    int           flag;
    char          ctlbuf[BUFFSIZE];
    char          datbuf[BUFFSIZE];
    struct strbuf ctl;
    struct strbuf dat;

    ctl.buf = ctlbuf;
    ctl.maxlen = BUFFSIZE;
    dat.buf = datbuf;
    dat.maxlen = BUFFSIZE;
    for (;;) {
        flag = 0; /* return any message */
        if ((n = getmsg(STDIN_FILENO, &ctl, &dat, &flag)) < 0) {
            printf("getmsg error\n");
            exit(1);
        }
        fprintf(stderr, "flag = %d, ctl.len = %d, dat.len = %d\n", 
                flag, ctl.len, dat.len);
        if (dat.len == 0) {
            exit(0);
        }
        else if (dat.len > 0) {
            if (write(STDOUT_FILENO, dat.buf, dat.len) != dat.len) {
                printf("write error\n");
                exit(1);
            }
        }
    }
}

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>

int 
main(int argc, char * argv[])
{
    int           fdin;
    int           fdout;
    void        * src;
    void        * dst;
    struct stat   statbuf;

    if (argc != 3) {
        printf("usage: %s <fromfile> <tofile>\n", argv[0]);
        exit(1);
    }

    if ((fdin = open(argv[1], O_RDONLY)) < 0) {
        printf("cannot open %s for reading\n", argv[1]);
        exit(1);
    }

    if ((fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
        printf("cannot creat %s for writing\n", argv[2]);
        exit(1);
    }

    if (fstat(fdin, &statbuf) < 0) { /* need size of input file */
        printf("fstat error\n");
        exit(1);
    }

    /* set size of output file */
    if (lseek(fdout, statbuf.st_size - 1, SEEK_SET) == -1) {
        printf("lseek error\n");
        exit(1);
    }
    if (write(fdout, " ", 1) != 1) {
        printf("write error\n");
        exit(1);
    }

    if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0))
             == MAP_FAILED) {
        printf("mmap error for input\n");
        exit(1);
    }

    if ((dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, 
                    fdout, 0)) == MAP_FAILED) {
        printf("mmap error for output\n");
        exit(1);
    }

    memcpy(dst, src, statbuf.st_size); /* does the file copy */
    exit(0);
}

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>

#include "filelock.h"
#include "mysignal.h"

void 
sig_int(int signo)
{
    
}

int 
main(void)
{
    int      fd;
    pid_t    pid1;
    pid_t    pid2;
    pid_t    pid3;

    setbuf(stdout, NULL);
    my_signal_intr(SIGINT, sig_int);

    /*
     * create a file
     */
    if ((fd = open("lockfile", O_RDWR | O_CREAT, 0666)) < 0) {
        printf("cannot open/creat lockfile\n");
        exit(1);
    }

    /*
     * read-lock the file
     */
    if ((pid1 = fork()) < 0) {
        printf("fork error\n");
        exit(1);
    }
    else if (pid1 == 0) {
        if (read_lock(fd, 0, SEEK_SET, 0) < 0) {
            printf("child 1: cannot read-lock file\n");
            exit(1);
        }
        printf("child 1: obtained read lock on file\n");
        pause();
        printf("child 1: exit after pause\n");
        exit(0);
    }
    else {
        sleep(2);
    }

    /*
     * parent continues ... read-lock the file again
     */
    if ((pid2 = fork()) < 0) {
        printf("fork failed\n");
        exit(0);
    }
    else if (pid2 == 0) {
        if (read_lock(fd, 0, SEEK_SET, 0) < 0) {
            printf("child 2: cannot read-lock file\n");
            exit(1);
        }
        printf("child 2: obtained read lock on file\n");
        pause();
        printf("child 2: exit after pause\n");
        exit(0);
    }
    else {
        sleep(2);
    }

    /*
     * parent continues ... block while trying to write-lock the file
     */
    if ((pid3 = fork()) < 0) {
        printf("fork failed\n");
        exit(1);
    }
    else if (pid3 == 0) {
        if (write_lock(fd, 0, SEEK_SET, 0) < 0) {
            printf("child 3: cannot set write clock: %s\n", strerror(errno));
        }
        printf("child 3 about to block in write-lock...\n");
        if (writew_lock(fd, 0, SEEK_SET, 0) < 0) {
            printf("child 3: cannot write-lock file");
            exit(1);
        }
        printf("child 3: returned and got write lock????\n");
        pause();
        printf("child 3: exit after pause\n");
        exit(0);
    }
    else {
        sleep(2);
    }

    /*
     * see if a pending write lock will block the next read-lock attempt
     */
    if (read_lock(fd, 0, SEEK_SET, 0) < 0) {
        printf("parent: cannot set read lock: %s\n", strerror(errno));
        exit(1);
    }
    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);
}

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

#include "changefileflag.h"

int 
main(void)
{
    int i;
    int n;
    int fd[2];

    if (pipe(fd) < 0) {
        printf("pipe error\n");
        exit(1);
    }
    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\n", i);
            break;
        }
    }
    printf("pipe capacity = %d\n", n);
    exit(0);
}

#include <unistd.h>

ssize_t     /* read n bytes from a descriptor */
readn(int fd, void * ptr, size_t n)
{
    size_t     nleft;
    ssize_t    nread;

    nleft = n;
    while (nleft > 0) {
        if ((nread = read(fd, ptr, nleft)) < 0) {
            if (nleft == n) {
                return(-1); /* error, return -1 */
            }
            else {
                break;      /* error, return amount read so far */
            }
        }
        else if (nread == 0) {
            break;          /* EOF */
        }
        else {
            nleft -= nread;
            ptr   += nread;
        }
    }
    return(n - nleft);      /* return >= 0 */
}

ssize_t     /* write n bytes to a descriptor */
writen(int fd, const void * ptr, size_t n)
{
    size_t     nleft;
    ssize_t    nwritten;

    nleft = n;
    while (nleft > 0) {
        if ((nwritten = write(fd, ptr, nleft)) < 0) {
            if (nleft == n) {
                return(-1); /* error, return -1 */
            }
            else {
                break;      /* error, return amount written so far */
            }
        }
        else if (nwritten == 0) {
            break;
        }
        else {
            nleft -= nwritten;
            ptr   += nwritten;
        }
    }
    return(n - nleft);      /* return >= 0 */
}

#include <stdio.h>
#include <poll.h>
#include <sys/select.h>

void 
sleep_ms(unsigned int msec)
{
    struct pollfd dummy;

    poll(&dummy, 0, msec);
}

void 
sleep_us(unsigned int usec)
{
    struct timeval tv;

    tv.tv_sec = usec / 1000000;
    tv.tv_usec = usec % 1000000;
    select(0, NULL, NULL, NULL, &tv);
}

void 
sleep_ns(unsigned int nsec)
{
    struct timespec ts;

    ts.tv_sec = nsec / 1000000000;
    ts.tv_nsec = nsec % 1000000000;
    pselect(0, NULL, NULL, NULL, &ts, NULL);
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值