| 99 | report any error). Return FALSE if splice could not be used. */ |
| 100 | |
| 101 | static bool |
| 102 | splice_write (MAYBE_UNUSED char const *buf, MAYBE_UNUSED idx_t copysize) |
| 103 | { |
| 104 | bool output_started = false; |
| 105 | #if HAVE_SPLICE |
| 106 | idx_t page_size = getpagesize (); |
| 107 | |
| 108 | bool stdout_is_pipe = isapipe (STDOUT_FILENO) > 0; |
| 109 | |
| 110 | /* Determine buffer size: enlarge the target pipe, |
| 111 | then use 1/4 of actual capacity as the transfer size. */ |
| 112 | int pipefd[2] = { -1, -1 }; |
| 113 | idx_t splice_bufsize; |
| 114 | char *splice_buf = NULL; |
| 115 | |
| 116 | if (stdout_is_pipe) |
| 117 | splice_bufsize = pipe_splice_size (STDOUT_FILENO, copysize); |
| 118 | else |
| 119 | { |
| 120 | if (pipe2 (pipefd, 0) < 0) |
| 121 | return false; |
| 122 | splice_bufsize = pipe_splice_size (pipefd[0], copysize); |
| 123 | } |
| 124 | |
| 125 | if (splice_bufsize == 0) |
| 126 | goto done; |
| 127 | |
| 128 | /* Allocate page-aligned buffer for vmsplice. |
| 129 | Needed with SPLICE_F_GIFT, but generally good for performance. */ |
| 130 | if (! (splice_buf = alignalloc (page_size, splice_bufsize))) |
| 131 | goto done; |
| 132 | |
| 133 | repeat_pattern (splice_buf, buf, copysize, splice_bufsize); |
| 134 | |
| 135 | /* For the pipe case, vmsplice directly to stdout. |
| 136 | For the non-pipe case, vmsplice into the intermediate pipe |
| 137 | and then splice from it to stdout. */ |
| 138 | int vmsplice_fd = stdout_is_pipe ? STDOUT_FILENO : pipefd[1]; |
| 139 | |
| 140 | for (;;) |
| 141 | { |
| 142 | struct iovec iov = { .iov_base = splice_buf, |
| 143 | .iov_len = splice_bufsize }; |
| 144 | |
| 145 | while (iov.iov_len > 0) |
| 146 | { |
| 147 | /* Use SPLICE_F_{GIFT,MOVE} to allow the kernel to take references |
| 148 | to the pages. I.e., we're indicating we won't make changes. |
| 149 | SPLICE_F_GIFT is only appropriate for full pages. */ |
| 150 | unsigned int flags = iov.iov_len % page_size ? 0 : SPLICE_F_GIFT; |
| 151 | ssize_t n = vmsplice (vmsplice_fd, &iov, 1, flags); |
| 152 | if (n <= 0) |
| 153 | goto done; |
| 154 | |
| 155 | if (stdout_is_pipe) |
| 156 | output_started = true; |
| 157 | else |
| 158 | { |
no test coverage detected