| /* Check that closing a pipe with a nonempty buffer works. | |
| #notarget: cris*-*-elf | |
| #output: got: a\ngot: b\nexit: 0\n | |
| */ | |
| #include <stddef.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <limits.h> | |
| #include <unistd.h> | |
| #include <sched.h> | |
| #include <signal.h> | |
| #include <errno.h> | |
| #include <sys/types.h> | |
| #include <sys/wait.h> | |
| #include <string.h> | |
| int pip[2]; | |
| int pipemax; | |
| int | |
| process (void *arg) | |
| { | |
| char *s = arg; | |
| int lots = pipemax + 256; | |
| char *buf = malloc (lots); | |
| int ret; | |
| if (buf == NULL) | |
| abort (); | |
| *buf = *s; | |
| /* The first write should go straight through. */ | |
| if (write (pip[1], buf, 1) != 1) | |
| abort (); | |
| *buf = s[1]; | |
| /* The second write may or may not be successful for the whole | |
| write, but should be successful for at least the pipemax part. | |
| As linux/limits.h clamps PIPE_BUF to 4096, but the page size is | |
| actually 8k, we can get away with that much. There should be no | |
| error, though. Doing this on host shows that for | |
| x86_64-unknown-linux-gnu (2.6.14-1.1656_FC4) pipemax * 10 can be | |
| successfully written, perhaps for similar reasons. */ | |
| ret = write (pip[1], buf, lots); | |
| if (ret < pipemax) | |
| { | |
| fprintf (stderr, "ret: %d, %s, %d\n", ret, strerror (errno), pipemax); | |
| fflush (0); | |
| abort (); | |
| } | |
| return 0; | |
| } | |
| int | |
| main (void) | |
| { | |
| int retcode; | |
| int pid; | |
| int st = 0; | |
| long stack[16384]; | |
| char buf[1]; | |
| /* We need to turn this off because we don't want (to have to model) a | |
| SIGPIPE resulting from the close. */ | |
| if (signal (SIGPIPE, SIG_IGN) != SIG_DFL) | |
| abort (); | |
| retcode = pipe (pip); | |
| if (retcode != 0) | |
| { | |
| fprintf (stderr, "Bad pipe %d\n", retcode); | |
| abort (); | |
| } | |
| #ifdef PIPE_MAX | |
| pipemax = PIPE_MAX; | |
| #else | |
| pipemax = fpathconf (pip[1], _PC_PIPE_BUF); | |
| #endif | |
| if (pipemax <= 0) | |
| { | |
| fprintf (stderr, "Bad pipemax %d\n", pipemax); | |
| abort (); | |
| } | |
| pid = clone (process, (char *) stack + sizeof (stack) - 64, | |
| (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND) | |
| | SIGCHLD, "ab"); | |
| if (pid <= 0) | |
| { | |
| fprintf (stderr, "Bad clone %d\n", pid); | |
| abort (); | |
| } | |
| while ((retcode = read (pip[0], buf, 1)) == 0) | |
| ; | |
| if (retcode != 1) | |
| { | |
| fprintf (stderr, "Bad read 1: %d\n", retcode); | |
| abort (); | |
| } | |
| printf ("got: %c\n", buf[0]); | |
| /* Need to read out something from the second write too before | |
| closing, or the writer can get EPIPE. */ | |
| while ((retcode = read (pip[0], buf, 1)) == 0) | |
| ; | |
| if (retcode != 1) | |
| { | |
| fprintf (stderr, "Bad read 2: %d\n", retcode); | |
| abort (); | |
| } | |
| printf ("got: %c\n", buf[0]); | |
| if (close (pip[0]) != 0) | |
| { | |
| perror ("pip close"); | |
| abort (); | |
| } | |
| retcode = waitpid (pid, &st, __WALL); | |
| if (retcode != pid || !WIFEXITED (st)) | |
| { | |
| fprintf (stderr, "Bad wait %d:%d %x\n", pid, retcode, st); | |
| perror ("errno"); | |
| abort (); | |
| } | |
| printf ("exit: %d\n", WEXITSTATUS (st)); | |
| return 0; | |
| } |