Ticket #374: fork_flush.c

File fork_flush.c, 2.6 KB (added by dmik, 7 years ago)
Line 
1#include <stdio.h>
2#include <unistd.h>
3#include <string.h>
4#include <process.h>
5#include <sys/socket.h>
6#include <sys/fcntl.h>
7#include <errno.h>
8
9#ifdef USE_POLL
10#include <sys/poll.h>
11#else
12#include <sys/select.h>
13#endif
14
15//#define WORKAROUND
16
17#ifdef WORKAROUND
18static void child_exit()
19{
20  flushall();
21}
22#endif
23
24const char child_str[] = "I'm a real child, pid 0x%04x\n";
25
26int main_child()
27{
28#ifdef WORKAROUND
29  atexit(child_exit);
30#endif
31
32  printf(child_str, getpid());
33
34  return 0x11;
35}
36
37int main_parent(int argc, const char** argv)
38{
39  int p[2];
40  int pid, status;
41  ssize_t n, cnt;
42#ifdef USE_POLL
43  struct pollfd pfd;
44#else
45  fd_set readfds;
46#endif
47  char buf[128];
48
49  if (socketpair(AF_UNIX, SOCK_STREAM, 0, p) < 0)
50  {
51    perror("socketpair");
52    return 1;
53  }
54
55  pid = fork();
56  if (!pid)
57  {
58    // child
59
60    dup2(p[1], 1);
61    close(p[0]);
62    close(p[1]);
63
64    execlp(argv[0], argv[0], "child", NULL);
65    perror("exec");
66    return 1;
67  }
68
69  // parent
70  if (pid < 0)
71  {
72    perror("fork");
73    return 1;
74  }
75
76  close(p[1]);
77
78  printf("child pid 0x%x\n", pid);
79
80  cnt = 0;
81
82#ifdef USE_POLL
83  pfd.fd = p[0];
84  pfd.events = POLLIN;
85
86  while (1)
87  {
88    if (poll(&pfd, 1, -1) < 0)
89    {
90      if (errno == EINTR)
91        continue;
92      perror("poll");
93      break;
94    }
95
96    if (!(pfd.revents & (POLLOUT|POLLIN|POLLHUP|POLLERR|POLLNVAL)))
97      continue;
98
99    n = read(pfd.fd, buf, sizeof(buf));
100    if (n <= 0)
101    {
102      close(pfd.fd);
103      if (n < 0)
104        perror("read");
105      break;
106    }
107    else
108    {
109      cnt += n;
110      printf("read %d bytes from child [%.*s]\n", n, n, buf);
111    }
112  }
113#else
114  while (1)
115  {
116    fd_set readfds;
117    FD_ZERO(&readfds);
118    FD_SET(p[0], &readfds);
119
120    if (select(p[0] + 1, &readfds, NULL, NULL, NULL) < 0)
121    {
122      if (errno == EINTR)
123        continue;
124      perror("select");
125      break;
126    }
127
128    if (!FD_ISSET(p[0], &readfds))
129      continue;
130
131    n = read(p[0], buf, sizeof(buf));
132    if (n <= 0)
133    {
134      close(p[0]);
135      if (n < 0)
136        perror("read");
137      break;
138    }
139    else
140    {
141      cnt += n;
142      printf("read %d bytes from child [%.*s]\n", n, n, buf);
143    }
144  }
145#endif
146
147  while ((pid = waitpid(-1, &status, 0)) < 0)
148  {
149    if (errno == EINTR)
150      continue;
151    else
152    {
153      perror("waitpid");
154      break;
155    }
156  }
157
158  printf("child exit status 0x%x (pid 0x%x)\n", status, pid);
159
160  if (cnt != (ssize_t)strlen(child_str))
161  {
162    printf("FAILED (read %d bytes from child instead of %d)\n", cnt, strlen(child_str));
163    return 1;
164  }
165
166  printf("SUCCEEDED");
167  return 0;
168}
169
170int main(int argc, const char** argv)
171{
172  if (argc > 1)
173    return main_child();
174  return main_parent(argc, argv);
175}