Home | History | Annotate | Line # | Download | only in c
      1  1.1  christos /* Check that closing a pipe with a nonempty buffer works.
      2  1.1  christos #progos: linux
      3  1.1  christos #output: got: a\ngot: b\nexit: 0\n
      4  1.1  christos */
      5  1.1  christos 
      6  1.1  christos 
      7  1.1  christos #include <stddef.h>
      8  1.1  christos #include <stdlib.h>
      9  1.1  christos #include <stdio.h>
     10  1.1  christos #include <limits.h>
     11  1.1  christos #include <unistd.h>
     12  1.1  christos #include <sched.h>
     13  1.1  christos #include <signal.h>
     14  1.1  christos #include <errno.h>
     15  1.1  christos #include <sys/types.h>
     16  1.1  christos #include <sys/wait.h>
     17  1.1  christos #include <string.h>
     18  1.1  christos int pip[2];
     19  1.1  christos 
     20  1.1  christos int pipemax;
     21  1.1  christos 
     22  1.1  christos int
     23  1.1  christos process (void *arg)
     24  1.1  christos {
     25  1.1  christos   char *s = arg;
     26  1.1  christos   int lots = pipemax + 256;
     27  1.1  christos   char *buf = malloc (lots);
     28  1.1  christos   int ret;
     29  1.1  christos 
     30  1.1  christos   if (buf == NULL)
     31  1.1  christos     abort ();
     32  1.1  christos 
     33  1.1  christos   *buf = *s;
     34  1.1  christos 
     35  1.1  christos   /* The first write should go straight through.  */
     36  1.1  christos   if (write (pip[1], buf, 1) != 1)
     37  1.1  christos     abort ();
     38  1.1  christos 
     39  1.1  christos   *buf = s[1];
     40  1.1  christos 
     41  1.1  christos   /* The second write may or may not be successful for the whole
     42  1.1  christos      write, but should be successful for at least the pipemax part.
     43  1.1  christos      As linux/limits.h clamps PIPE_BUF to 4096, but the page size is
     44  1.1  christos      actually 8k, we can get away with that much.  There should be no
     45  1.1  christos      error, though.  Doing this on host shows that for
     46  1.1  christos      x86_64-unknown-linux-gnu (2.6.14-1.1656_FC4) pipemax * 10 can be
     47  1.1  christos      successfully written, perhaps for similar reasons.  */
     48  1.1  christos   ret = write (pip[1], buf, lots);
     49  1.1  christos   if (ret < pipemax)
     50  1.1  christos     {
     51  1.1  christos       fprintf (stderr, "ret: %d, %s, %d\n", ret, strerror (errno), pipemax);
     52  1.1  christos       fflush (0);
     53  1.1  christos       abort ();
     54  1.1  christos     }
     55  1.1  christos 
     56  1.1  christos   return 0;
     57  1.1  christos }
     58  1.1  christos 
     59  1.1  christos int
     60  1.1  christos main (void)
     61  1.1  christos {
     62  1.1  christos   int retcode;
     63  1.1  christos   int pid;
     64  1.1  christos   int st = 0;
     65  1.1  christos   long stack[16384];
     66  1.1  christos   char buf[1];
     67  1.1  christos 
     68  1.1  christos   /* We need to turn this off because we don't want (to have to model) a
     69  1.1  christos      SIGPIPE resulting from the close.  */
     70  1.1  christos   if (signal (SIGPIPE, SIG_IGN) != SIG_DFL)
     71  1.1  christos     abort ();
     72  1.1  christos 
     73  1.1  christos   retcode = pipe (pip);
     74  1.1  christos 
     75  1.1  christos   if (retcode != 0)
     76  1.1  christos     {
     77  1.1  christos       fprintf (stderr, "Bad pipe %d\n", retcode);
     78  1.1  christos       abort ();
     79  1.1  christos     }
     80  1.1  christos 
     81  1.1  christos #ifdef PIPE_MAX
     82  1.1  christos   pipemax = PIPE_MAX;
     83  1.1  christos #else
     84  1.1  christos   pipemax = fpathconf (pip[1], _PC_PIPE_BUF);
     85  1.1  christos #endif
     86  1.1  christos 
     87  1.1  christos   if (pipemax <= 0)
     88  1.1  christos     {
     89  1.1  christos       fprintf (stderr, "Bad pipemax %d\n", pipemax);
     90  1.1  christos       abort ();
     91  1.1  christos     }
     92  1.1  christos 
     93  1.1  christos   pid = clone (process, (char *) stack + sizeof (stack) - 64,
     94  1.1  christos 	       (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
     95  1.1  christos 	       | SIGCHLD, "ab");
     96  1.1  christos   if (pid <= 0)
     97  1.1  christos     {
     98  1.1  christos       fprintf (stderr, "Bad clone %d\n", pid);
     99  1.1  christos       abort ();
    100  1.1  christos     }
    101  1.1  christos 
    102  1.1  christos   while ((retcode = read (pip[0], buf, 1)) == 0)
    103  1.1  christos     ;
    104  1.1  christos 
    105  1.1  christos   if (retcode != 1)
    106  1.1  christos     {
    107  1.1  christos       fprintf (stderr, "Bad read 1: %d\n", retcode);
    108  1.1  christos       abort ();
    109  1.1  christos     }
    110  1.1  christos 
    111  1.1  christos   printf ("got: %c\n", buf[0]);
    112  1.1  christos 
    113  1.1  christos   /* Need to read out something from the second write too before
    114  1.1  christos      closing, or the writer can get EPIPE. */
    115  1.1  christos   while ((retcode = read (pip[0], buf, 1)) == 0)
    116  1.1  christos     ;
    117  1.1  christos 
    118  1.1  christos   if (retcode != 1)
    119  1.1  christos     {
    120  1.1  christos       fprintf (stderr, "Bad read 2: %d\n", retcode);
    121  1.1  christos       abort ();
    122  1.1  christos     }
    123  1.1  christos 
    124  1.1  christos   printf ("got: %c\n", buf[0]);
    125  1.1  christos 
    126  1.1  christos   if (close (pip[0]) != 0)
    127  1.1  christos     {
    128  1.1  christos       perror ("pip close");
    129  1.1  christos       abort ();
    130  1.1  christos     }
    131  1.1  christos 
    132  1.1  christos   retcode = waitpid (pid, &st, __WALL);
    133  1.1  christos 
    134  1.1  christos   if (retcode != pid || !WIFEXITED (st))
    135  1.1  christos     {
    136  1.1  christos       fprintf (stderr, "Bad wait %d:%d %x\n", pid, retcode, st);
    137  1.1  christos       perror ("errno");
    138  1.1  christos       abort ();
    139  1.1  christos     }
    140  1.1  christos 
    141  1.1  christos   printf ("exit: %d\n", WEXITSTATUS (st));
    142  1.1  christos   return 0;
    143  1.1  christos }
    144