9static int queued_rights(
void) {
10 int failed = 0, p[2] = {-1, -1}, pair[2] = {-1, -1}, gate[2] = {-1, -1}, alias = -1,
13 CHECK(!pipe(p) && !pipe(gate) && !socketpair(AF_UNIX, SOCK_STREAM, 0, pair));
14 CHECK(!pt_fill(p[1], 16, 41) && (alias = dup(p[0])) >= 0);
15 CHECK((child = fork()) >= 0);
24 if (read(gate[0], &
byte, 1) != 1)
26 int fd = pt_receive_fd(pair[1]), q[2];
27 if (fd < 0 || pipe(q) || splice(fd, NULL, q[1], NULL, 8, 0) != 8 || pt_read(q[0], 8, 0, 41) ||
28 pt_send_fd(pair[1], fd))
37 CHECK(!pt_send_fd(pair[0], alias));
38 CHECK(!close(p[0]) && !close(alias));
40 CHECK(write(gate[1],
"g", 1) == 1);
41 CHECK((received = pt_receive_fd(pair[0])) >= 0);
42 CHECK(!pt_read(received, 8, 8, 41));
43 int status = pt_reap(child, 5000);
55 for (
int n = 0; n < 2; ++n) {
65static int numeric_reuse(
void) {
66 int failed = 0, p[2] = {-1, -1}, q[2] = {-1, -1}, pair[2] = {-1, -1}, replacement[2] = {-1, -1};
67 int input_alias = -1, output_alias = -1, running = 0;
68 struct pt_call call = {.kind = PT_SPLICE, .count = 32, .result = -2};
70 CHECK(!pipe(p) && !pipe(q) && !socketpair(AF_UNIX, SOCK_STREAM, 0, pair) &&
71 !socketpair(AF_UNIX, SOCK_STREAM, 0, replacement));
72 CHECK(!pt_fill(p[1], 32, 59) && !pt_fill(q[1], 8, 83));
73 ssize_t capacity = pt_socket_full(pair[0]);
74 CHECK(capacity > 0 && (input_alias = dup(p[0])) >= 0 && (output_alias = dup(pair[0])) >= 0);
76 call.output = pair[0];
77 CHECK(!pthread_create(&
worker, NULL, pt_worker, &call));
79 CHECK(!pt_wait(&call.ready, 5000));
80 __atomic_store_n(&call.gate, 1, __ATOMIC_RELEASE);
81 CHECK(!pt_wait_readiness(p[0], POLLIN, 0));
82 CHECK(!__atomic_load_n(&call.done, __ATOMIC_ACQUIRE));
83 CHECK(dup2(q[0], p[0]) == p[0] && dup2(replacement[0], pair[0]) == pair[0]);
84 CHECK(!pt_read(pair[1], capacity, 0, PT_FILLER));
85 CHECK(!pt_join(
worker, &call));
87 CHECK(call.result > 0 && call.result <= 32 && call.error == 0);
88 CHECK(!pt_read(pair[1], call.result, 0, 59));
89 CHECK(!pt_read(input_alias, 32 - call.result, call.result, 59));
90 CHECK(!pt_read(p[0], 8, 0, 83));
91 CHECK(!fcntl(replacement[1], F_SETFL, O_NONBLOCK));
93 CHECK(read(replacement[1], &
byte, 1) == -1 && errno == EAGAIN);
98 shutdown(pair[1], SHUT_RD);
101 if (input_alias >= 0)
103 if (output_alias >= 0)
105 for (
int n = 0; n < 2; ++n) {
112 if (replacement[n] >= 0)
113 close(replacement[n]);
117static int terminal_exit(
int reservation) {
118 int failed = 0, p[2] = {-1, -1}, output[2] = {-1, -1};
123 CHECK(!socketpair(AF_UNIX, SOCK_STREAM, 0, output) && !pt_fill(p[1], 32, 47));
124 CHECK((filler = pt_socket_full(output[1])) > 0);
126 CHECK(!pipe(output));
127 CHECK((child = fork()) >= 0);
132 struct pt_call call = {.kind = reservation ? PT_SPLICE : PT_TEE,
138 if (pthread_create(&
worker, NULL, pt_worker, &call) || pt_wait(&call.ready, 3000))
140 __atomic_store_n(&call.gate, 1, __ATOMIC_RELEASE);
142 if (pt_wait_readiness(p[0], POLLIN, 0) || __atomic_load_n(&call.done, __ATOMIC_ACQUIRE))
144 }
else if (pt_wait(&call.entered, 3000))
153 int status = pt_reap(child, 5000);
156 CHECK(write(p[1],
"x", 1) == -1 && errno == EPIPE);
157 CHECK(!pt_read(output[0], filler, 0, PT_FILLER));
158 CHECK(!fcntl(output[0], F_SETFL, O_NONBLOCK));
160 CHECK(read(output[0], &
byte, 1) == 0);
163 kill(child, SIGKILL);
164 pt_reap(child, 1000);
166 for (
int n = 0; n < 2; ++n) {
174int pipe_transfer_lifetime(
void) {
175 return queued_rights() || numeric_reuse() || terminal_exit(1) || terminal_exit(0);