summaryrefslogtreecommitdiffstats
path: root/src/io-unix.c
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-11-25 10:52:15 +0200
committerTimo Teras <timo.teras@iki.fi>2009-11-25 10:52:15 +0200
commitfc1044daf51f32b9d85f8497e4e0bd5a3c1e7fe9 (patch)
tree52e11c88f17c47c0d086761e50b266f5c5ccd061 /src/io-unix.c
parentcec85dedb7fd66cf2c23cafadd7c53eb7afed78f (diff)
downloadlibtf-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.c131
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;
+}