第十四章 高级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);
}