]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
stdin/stdout: Restore fd flags on shutdown.
authorAndre Noll <maan@systemlinux.org>
Mon, 18 Mar 2013 22:51:46 +0000 (23:51 +0100)
committerAndre Noll <maan@systemlinux.org>
Sat, 4 May 2013 22:48:04 +0000 (00:48 +0200)
The stdin/stdout code should restore the flags to the old value to
avoid surprises, for example in shell scripts.

This changes stdin.c and stdout.c to save the old value. It is
restored in ->post_select when the buffer tree node is removed and
no more I/O takes place.

stdin.c
stdin.h
stdout.c
stdout.h

diff --git a/stdin.c b/stdin.c
index fd803ae5441acf01446dadab89c35d3bec14cecd..08bc1f9a4be9c2964ae1c882cf6e34cd11685a19 100644 (file)
--- a/stdin.c
+++ b/stdin.c
@@ -71,6 +71,12 @@ static void stdin_post_select(struct sched *s, struct task *t)
        sz = btr_pool_get_buffer(sit->btrp, &buf);
        if (sz == 0)
                return;
+       if (sit->must_set_nonblock_flag) {
+               ret = mark_fd_nonblocking(STDIN_FILENO);
+               if (ret < 0)
+                       goto err;
+               sit->must_set_nonblock_flag = false;
+       }
        /*
         * Do not use the maximal size to avoid having only a single buffer
         * reference for the whole pool. This is bad because if that single
@@ -84,6 +90,8 @@ static void stdin_post_select(struct sched *s, struct task *t)
                return;
 err:
        btr_remove_node(&sit->btrn);
+       /* Revert to blocking mode if necessary. */
+       fcntl(STDIN_FILENO, F_SETFL, sit->fd_flags);
        //btr_pool_free(sit->btrp);
        t->error = ret;
 }
@@ -94,8 +102,7 @@ err:
  * \param sit The stdin task structure.
  *
  * This fills in the pre/post select function pointers of the task structure
- * given by \a sit. Moreover, the stdin file desctiptor is set to nonblocking
- * mode, and a buffer tree is created.
+ * given by \a sit and creates a buffer tree for I/O.
  */
 void stdin_set_defaults(struct stdin_task *sit)
 {
@@ -105,9 +112,18 @@ void stdin_set_defaults(struct stdin_task *sit)
        sit->task.post_select = stdin_post_select;
        sit->btrp = btr_pool_new("stdin", 128 * 1024);
        sprintf(sit->task.status, "stdin reader");
-       ret = mark_fd_nonblocking(STDIN_FILENO);
-       if (ret >= 0)
-               return;
-       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
-       exit(EXIT_FAILURE);
+       /*
+        * Both STDIN_FILENO and STDOUT_FILENO may refer to the same open file
+        * description (the terminal), and thus share the same file status
+        * flags. In order to not interfere with the stdout task, we only get
+        * the file status flags for STDIN here and save a copy. The nonblock
+        * flag is set later on the first read.
+        */
+       ret = fcntl(STDIN_FILENO, F_GETFL);
+       if (ret < 0) {
+               PARA_EMERG_LOG("F_GETFL: %s\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       sit->fd_flags = ret;
+       sit->must_set_nonblock_flag = (sit->fd_flags & O_NONBLOCK) == 0;
 }
diff --git a/stdin.h b/stdin.h
index 54710ae561105bd7ad0ce907cf078d58d49a80f1..cdf0c67fd57a1078f38a9f175d598adf65ece520 100644 (file)
--- a/stdin.h
+++ b/stdin.h
@@ -14,6 +14,10 @@ struct stdin_task {
        struct btr_node *btrn;
        /** Use a buffer pool to minimize memcpy due to alignment problems. */
        struct btr_pool *btrp;
+       /** The descriptor flags of STDIN at startup. */
+       int fd_flags;
+       /** Whether we have to set STDIN to nonblocking mode. */
+       bool must_set_nonblock_flag;
 };
 
 void stdin_set_defaults(struct stdin_task *sit);
index 9c7e64e7284a3a3d247e76a7f9724f880e397a31..0cf4876db49125efe83e733e6c5f5c7ee921aa45 100644 (file)
--- a/stdout.c
+++ b/stdout.c
@@ -64,6 +64,12 @@ static void stdout_post_select(struct sched *s, struct task *t)
        if (!FD_ISSET(STDOUT_FILENO, &s->wfds))
                return;
 
+       if (sot->must_set_nonblock_flag) {
+               ret = mark_fd_nonblocking(STDOUT_FILENO);
+               if (ret < 0)
+                       goto out;
+               sot->must_set_nonblock_flag = false;
+       }
        for (;;) {
                sz = btr_next_buffer(btrn, &buf);
                if (sz == 0)
@@ -74,8 +80,11 @@ static void stdout_post_select(struct sched *s, struct task *t)
                btr_consume(btrn, ret);
        }
 out:
-       if (ret < 0)
+       if (ret < 0) {
                btr_remove_node(&sot->btrn);
+               /* Revert to blocking mode if necessary. */
+               fcntl(STDOUT_FILENO, F_SETFL, sot->fd_flags);
+       }
        t->error = ret;
 }
 /**
@@ -84,7 +93,7 @@ out:
  * \param sot The stdout task structure.
  *
  * This fills in the pre/post select function pointers of the task structure
- * given by \a sot and sets the stdout file descriptor to nonblocking mode.
+ * given by \a sot.
  */
 void stdout_set_defaults(struct stdout_task *sot)
 {
@@ -93,9 +102,13 @@ void stdout_set_defaults(struct stdout_task *sot)
        sot->task.pre_select = stdout_pre_select;
        sot->task.post_select = stdout_post_select;
        sprintf(sot->task.status, "stdout");
-       ret = mark_fd_nonblocking(STDOUT_FILENO);
-       if (ret >= 0)
-               return;
-       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
-       exit(EXIT_FAILURE);
+
+       /* See stdin.c for details. */
+       ret = fcntl(STDOUT_FILENO, F_GETFL);
+       if (ret < 0) {
+               PARA_EMERG_LOG("F_GETFL: %s\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       sot->fd_flags = ret;
+       sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0;
 }
index cc1f2626db049232601375688c8206ba24486177..a21b7cedfb699d9402f666a1a754a26d12cdcec1 100644 (file)
--- a/stdout.h
+++ b/stdout.h
@@ -16,6 +16,10 @@ struct stdout_task {
        struct task task;
        /** Stdout is always a leaf node in the buffer tree. */
        struct btr_node *btrn;
+       /** The descriptor flags of STDOUT at startup. */
+       int fd_flags;
+       /** Whether we have to set STDOUT to nonblocking mode. */
+       bool must_set_nonblock_flag;
 };
 
 void stdout_set_defaults(struct stdout_task *sot);