timer: handle time going backwards.
[ccan] / ccan / io / test / run-10-many.c
1 #include <ccan/io/io.h>
2 /* Include the C files directly. */
3 #include <ccan/io/poll.c>
4 #include <ccan/io/io.c>
5 #include <ccan/tap/tap.h>
6 #include <sys/wait.h>
7 #include <stdio.h>
8
9 #define NUM 100
10 #define NUM_ITERS 1000
11
12 struct buffer {
13         int iters;
14         struct io_conn *reader, *writer;
15         char buf[32];
16 };
17
18 static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf);
19 static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf);
20
21 static struct io_plan *read_buf(struct io_conn *conn, struct buffer *buf)
22 {
23         return io_read(conn, &buf->buf, sizeof(buf->buf), poke_writer, buf);
24 }
25
26 static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf)
27 {
28         assert(conn == buf->reader);
29
30         if (buf->iters == NUM_ITERS)
31                 return io_close(conn);
32
33         /* You write. */
34         io_wake(&buf->writer);
35
36         /* I'll wait until you wake me. */
37         return io_wait(conn, &buf->reader, read_buf, buf);
38 }
39
40 static struct io_plan *write_buf(struct io_conn *conn, struct buffer *buf)
41 {
42         return io_write(conn, &buf->buf, sizeof(buf->buf), poke_reader, buf);
43 }
44
45 static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf)
46 {
47         assert(conn == buf->writer);
48         /* You read. */
49         io_wake(&buf->reader);
50
51         if (++buf->iters == NUM_ITERS)
52                 return io_close(conn);
53
54         /* I'll wait until you tell me to write. */
55         return io_wait(conn, &buf->writer, write_buf, buf);
56 }
57
58 static struct io_plan *setup_reader(struct io_conn *conn, struct buffer *buf)
59 {
60         return io_wait(conn, &buf->reader, read_buf, buf);
61 }
62
63 static struct buffer buf[NUM];
64
65 int main(void)
66 {
67         unsigned int i;
68         int fds[2], last_read, last_write;
69
70         plan_tests(5 + NUM);
71
72         ok1(pipe(fds) == 0);
73         last_read = fds[0];
74         last_write = fds[1];
75
76         for (i = 1; i < NUM; i++) {
77                 if (pipe(fds) < 0)
78                         break;
79                 memset(buf[i].buf, i, sizeof(buf[i].buf));
80                 sprintf(buf[i].buf, "%i-%i", i, i);
81
82                 /* Wait for writer to tell us to read. */
83                 buf[i].reader = io_new_conn(NULL, last_read,
84                                             setup_reader, &buf[i]);
85                 if (!buf[i].reader)
86                         break;
87                 buf[i].writer = io_new_conn(NULL, fds[1], write_buf, &buf[i]);
88                 if (!buf[i].writer)
89                         break;
90                 last_read = fds[0];
91         }
92         if (!ok1(i == NUM))
93                 exit(exit_status());
94
95         /* Last one completes the cirle. */
96         i = 0;
97         sprintf(buf[i].buf, "%i-%i", i, i);
98         buf[i].reader = io_new_conn(NULL, last_read, setup_reader, &buf[i]);
99         ok1(buf[i].reader);
100         buf[i].writer = io_new_conn(NULL, last_write, write_buf, &buf[i]);
101         ok1(buf[i].writer);
102
103         /* They should eventually exit */
104         ok1(io_loop(NULL, NULL) == NULL);
105
106         for (i = 0; i < NUM; i++) {
107                 char b[sizeof(buf[0].buf)];
108                 memset(b, i, sizeof(b));
109                 sprintf(b, "%i-%i", i, i);
110                 ok1(memcmp(b, buf[(i + NUM_ITERS) % NUM].buf, sizeof(b)) == 0);
111         }
112
113         /* This exits depending on whether all tests passed */
114         return exit_status();
115 }