diff options
author | Timo Teras <timo.teras@iki.fi> | 2009-11-25 10:52:15 +0200 |
---|---|---|
committer | Timo Teras <timo.teras@iki.fi> | 2009-11-25 10:52:15 +0200 |
commit | fc1044daf51f32b9d85f8497e4e0bd5a3c1e7fe9 (patch) | |
tree | 52e11c88f17c47c0d086761e50b266f5c5ccd061 /src/io-unix.c | |
parent | cec85dedb7fd66cf2c23cafadd7c53eb7afed78f (diff) | |
download | libtf-fc1044daf51f32b9d85f8497e4e0bd5a3c1e7fe9.tar.bz2 libtf-fc1044daf51f32b9d85f8497e4e0bd5a3c1e7fe9.tar.xz |
libtf: implement basic file i/o with epoll
some scetching of i/o api, and implement basic read and write
functionality. integrate polling to scheduler and an epoll based
polling mechanism.
Diffstat (limited to 'src/io-unix.c')
-rw-r--r-- | src/io-unix.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/io-unix.c b/src/io-unix.c new file mode 100644 index 0000000..d333122 --- /dev/null +++ b/src/io-unix.c @@ -0,0 +1,131 @@ +/* io-unix.c - non-blocking io primitives for unix + * + * Copyright (C) 2009 Timo Teräs <timo.teras@iki.fi> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or later as + * published by the Free Software Foundation. + * + * See http://www.gnu.org/ for details. + */ + +int tf_open(struct tf_fd *fd, const char *pathname, int flags) +{ + int kfd, r; + + kfd = open(pathname, flags | O_CLOEXEC | O_NONBLOCK); + if (unlikely(kfd < 0)) + return -errno; + + r = tf_fd_init(fd, kfd, TF_FD_AUTOCLOSE | TF_FD_STREAM_ORIENTED); + if (r < 0) { + close(kfd); + return r; + } + return 0; +} + +int tf_open_fd(struct tf_fd *fd, int kfd) +{ + int mode, flags = 0; + + mode = fcntl(kfd, F_GETFL, 0); + if (!(mode & O_NONBLOCK)) { + fcntl(fd->fd, F_SETFL, mode | O_NONBLOCK); + flags |= TF_FD_RESTORE_BLOCKING; + } + + return tf_fd_init(fd, kfd, TF_FD_STREAM_ORIENTED | flags); +} + +int tf_close(struct tf_fd *fd) +{ + int r; + + if (fd->flags & TF_FD_RESTORE_BLOCKING) { + fcntl(fd->fd, F_SETFL, fcntl(fd->fd, F_GETFL, 0) & ~O_NONBLOCK); + } + if (fd->flags & TF_FD_AUTOCLOSE) { + r = close(fd->fd); + if (unlikely(r == -1)) + return -errno; + } + return 0; +} + +int tf_read(struct tf_fd *fd, void *buf, size_t count, tf_mtime_diff_t timeout) +{ + ssize_t n; + int r, mode; + + mode = tf_schedule_timeout(timeout); + tf_fd_wait(fd, EPOLLIN); + do { + n = read(fd->fd, buf, count); + if (n == count) { + r = 0; + break; + } + if (n < 0) { + if (errno == EINTR) + continue; + if (errno != EAGAIN) { + r = errno; + break; + } + } else if (n == 0) { + r = EIO; + break; + } else { + buf += n; + count -= n; + if (!(fd->flags & TF_FD_STREAM_ORIENTED)) + continue; + } + + r = tf_schedule(mode); + if (r != TF_WAKEUP_FD) + break; + } while (1); + tf_fd_release(fd); + + return -r; +} + +int tf_write(struct tf_fd *fd, const void *buf, size_t count, + tf_mtime_diff_t timeout) +{ + ssize_t n; + int r, mode; + + mode = tf_schedule_timeout(timeout); + tf_fd_wait(fd, EPOLLOUT); + do { + n = write(fd->fd, buf, count); + if (n == count) { + r = 0; + break; + } + if (n < 0) { + if (errno == EINTR) + continue; + if (errno != EAGAIN) { + r = errno; + break; + } + } else { + buf += n; + count -= n; + if (!(fd->flags & TF_FD_STREAM_ORIENTED)) + continue; + } + + r = tf_schedule(mode); + if (r != TF_WAKEUP_FD) + break; + } while (1); + tf_fd_release(fd); + + return -r; +} |