ctiller | 58393c2 | 2015-01-07 14:03:30 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright 2014, Google Inc. |
| 4 | * All rights reserved. |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions are |
| 8 | * met: |
| 9 | * |
| 10 | * * Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * * Redistributions in binary form must reproduce the above |
| 13 | * copyright notice, this list of conditions and the following disclaimer |
| 14 | * in the documentation and/or other materials provided with the |
| 15 | * distribution. |
| 16 | * * Neither the name of Google Inc. nor the names of its |
| 17 | * contributors may be used to endorse or promote products derived from |
| 18 | * this software without specific prior written permission. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | * |
| 32 | */ |
| 33 | |
| 34 | #include <grpc/support/port_platform.h> |
| 35 | |
| 36 | #ifdef GPR_POSIX_MULTIPOLL_WITH_POLL |
| 37 | |
| 38 | #include "src/core/iomgr/pollset_posix.h" |
| 39 | |
| 40 | #include <errno.h> |
| 41 | #include <poll.h> |
| 42 | #include <stdlib.h> |
| 43 | #include <string.h> |
| 44 | |
| 45 | #include "src/core/iomgr/fd_posix.h" |
| 46 | #include "src/core/iomgr/iomgr_internal.h" |
| 47 | #include <grpc/support/alloc.h> |
| 48 | #include <grpc/support/log.h> |
| 49 | #include <grpc/support/useful.h> |
| 50 | |
| 51 | typedef struct { |
| 52 | /* all polled fds */ |
| 53 | size_t fd_count; |
| 54 | size_t fd_capacity; |
| 55 | grpc_fd **fds; |
| 56 | /* fds being polled by the current poller: parallel arrays of pollfd and the |
| 57 | * grpc_fd* that the pollfd was constructed from */ |
| 58 | size_t pfd_count; |
| 59 | size_t pfd_capacity; |
| 60 | grpc_fd **selfds; |
| 61 | struct pollfd *pfds; |
| 62 | /* fds that have been removed from the pollset explicitly */ |
| 63 | size_t del_count; |
| 64 | size_t del_capacity; |
| 65 | grpc_fd **dels; |
| 66 | } pollset_hdr; |
| 67 | |
| 68 | static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset, |
| 69 | grpc_fd *fd) { |
| 70 | size_t i; |
| 71 | pollset_hdr *h = pollset->data.ptr; |
| 72 | /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */ |
| 73 | for (i = 0; i < h->fd_count; i++) { |
| 74 | if (h->fds[i] == fd) return; |
| 75 | } |
| 76 | if (h->fd_count == h->fd_capacity) { |
| 77 | h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2); |
| 78 | h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity); |
| 79 | } |
| 80 | h->fds[h->fd_count++] = fd; |
| 81 | grpc_fd_ref(fd); |
| 82 | } |
| 83 | |
| 84 | static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset, |
| 85 | grpc_fd *fd) { |
| 86 | /* will get removed next poll cycle */ |
| 87 | pollset_hdr *h = pollset->data.ptr; |
| 88 | if (h->del_count == h->del_capacity) { |
| 89 | h->del_capacity = GPR_MAX(h->del_capacity + 8, h->del_count * 3 / 2); |
| 90 | h->dels = gpr_realloc(h->dels, sizeof(grpc_fd *) * h->del_capacity); |
| 91 | } |
| 92 | h->dels[h->del_count++] = fd; |
| 93 | grpc_fd_ref(fd); |
| 94 | } |
| 95 | |
| 96 | static void end_polling(grpc_pollset *pollset) { |
| 97 | size_t i; |
| 98 | pollset_hdr *h; |
| 99 | h = pollset->data.ptr; |
| 100 | for (i = 1; i < h->pfd_count; i++) { |
| 101 | grpc_fd_end_poll(h->selfds[i], pollset); |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | static int multipoll_with_poll_pollset_maybe_work( |
| 106 | grpc_pollset *pollset, gpr_timespec deadline, gpr_timespec now, |
| 107 | int allow_synchronous_callback) { |
| 108 | int timeout; |
| 109 | int r; |
| 110 | size_t i, np, nf, nd; |
| 111 | pollset_hdr *h; |
| 112 | |
| 113 | if (pollset->counter) { |
| 114 | return 0; |
| 115 | } |
| 116 | h = pollset->data.ptr; |
| 117 | if (gpr_time_cmp(deadline, gpr_inf_future) == 0) { |
| 118 | timeout = -1; |
| 119 | } else { |
| 120 | timeout = gpr_time_to_millis(gpr_time_sub(deadline, now)); |
| 121 | if (timeout <= 0) { |
| 122 | return 1; |
| 123 | } |
| 124 | } |
| 125 | if (h->pfd_capacity < h->fd_count + 1) { |
| 126 | h->pfd_capacity = GPR_MAX(h->pfd_capacity * 3 / 2, h->fd_count + 1); |
| 127 | gpr_free(h->pfds); |
| 128 | gpr_free(h->selfds); |
| 129 | h->pfds = gpr_malloc(sizeof(struct pollfd) * h->pfd_capacity); |
| 130 | h->selfds = gpr_malloc(sizeof(grpc_fd *) * h->pfd_capacity); |
| 131 | } |
| 132 | nf = 0; |
| 133 | np = 1; |
David Klempner | 7f3ed1e | 2015-01-16 15:35:56 -0800 | [diff] [blame^] | 134 | h->pfds[0].fd = grpc_pollset_kick_pre_poll(&pollset->kick_state); |
| 135 | if (h->pfds[0].fd < 0) { |
| 136 | /* Already kicked */ |
| 137 | return 1; |
| 138 | } |
ctiller | 58393c2 | 2015-01-07 14:03:30 -0800 | [diff] [blame] | 139 | h->pfds[0].events = POLLIN; |
| 140 | h->pfds[0].revents = POLLOUT; |
| 141 | for (i = 0; i < h->fd_count; i++) { |
| 142 | int remove = grpc_fd_is_orphaned(h->fds[i]); |
| 143 | for (nd = 0; nd < h->del_count; nd++) { |
| 144 | if (h->fds[i] == h->dels[nd]) remove = 1; |
| 145 | } |
| 146 | if (remove) { |
| 147 | grpc_fd_unref(h->fds[i]); |
| 148 | } else { |
| 149 | h->fds[nf++] = h->fds[i]; |
| 150 | h->pfds[np].events = |
| 151 | grpc_fd_begin_poll(h->fds[i], pollset, POLLIN, POLLOUT); |
| 152 | h->selfds[np] = h->fds[i]; |
| 153 | h->pfds[np].fd = h->fds[i]->fd; |
| 154 | h->pfds[np].revents = 0; |
| 155 | np++; |
| 156 | } |
| 157 | } |
| 158 | h->pfd_count = np; |
| 159 | h->fd_count = nf; |
| 160 | for (nd = 0; nd < h->del_count; nd++) { |
| 161 | grpc_fd_unref(h->dels[nd]); |
| 162 | } |
| 163 | h->del_count = 0; |
| 164 | if (h->pfd_count == 0) { |
| 165 | end_polling(pollset); |
| 166 | return 0; |
| 167 | } |
| 168 | pollset->counter = 1; |
| 169 | gpr_mu_unlock(&pollset->mu); |
| 170 | |
| 171 | r = poll(h->pfds, h->pfd_count, timeout); |
| 172 | if (r < 0) { |
ctiller | d9962df | 2015-01-07 15:31:39 -0800 | [diff] [blame] | 173 | if (errno != EINTR) { |
| 174 | gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); |
| 175 | } |
ctiller | 58393c2 | 2015-01-07 14:03:30 -0800 | [diff] [blame] | 176 | } else if (r == 0) { |
| 177 | /* do nothing */ |
| 178 | } else { |
| 179 | if (h->pfds[0].revents & POLLIN) { |
David Klempner | 7f3ed1e | 2015-01-16 15:35:56 -0800 | [diff] [blame^] | 180 | grpc_pollset_kick_consume(&pollset->kick_state); |
ctiller | 58393c2 | 2015-01-07 14:03:30 -0800 | [diff] [blame] | 181 | } |
| 182 | for (i = 1; i < np; i++) { |
| 183 | if (h->pfds[i].revents & POLLIN) { |
| 184 | grpc_fd_become_readable(h->selfds[i], allow_synchronous_callback); |
| 185 | } |
| 186 | if (h->pfds[i].revents & POLLOUT) { |
| 187 | grpc_fd_become_writable(h->selfds[i], allow_synchronous_callback); |
| 188 | } |
| 189 | } |
| 190 | } |
David Klempner | 7f3ed1e | 2015-01-16 15:35:56 -0800 | [diff] [blame^] | 191 | grpc_pollset_kick_post_poll(&pollset->kick_state); |
ctiller | 58393c2 | 2015-01-07 14:03:30 -0800 | [diff] [blame] | 192 | end_polling(pollset); |
| 193 | |
| 194 | gpr_mu_lock(&pollset->mu); |
| 195 | pollset->counter = 0; |
| 196 | gpr_cv_broadcast(&pollset->cv); |
| 197 | return 1; |
| 198 | } |
| 199 | |
| 200 | static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) { |
| 201 | size_t i; |
| 202 | pollset_hdr *h = pollset->data.ptr; |
| 203 | GPR_ASSERT(pollset->counter == 0); |
| 204 | for (i = 0; i < h->fd_count; i++) { |
| 205 | grpc_fd_unref(h->fds[i]); |
| 206 | } |
| 207 | for (i = 0; i < h->del_count; i++) { |
| 208 | grpc_fd_unref(h->dels[i]); |
| 209 | } |
| 210 | gpr_free(h->pfds); |
| 211 | gpr_free(h->selfds); |
| 212 | gpr_free(h->fds); |
| 213 | gpr_free(h->dels); |
| 214 | gpr_free(h); |
| 215 | } |
| 216 | |
| 217 | static const grpc_pollset_vtable multipoll_with_poll_pollset = { |
| 218 | multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd, |
| 219 | multipoll_with_poll_pollset_maybe_work, |
| 220 | multipoll_with_poll_pollset_destroy}; |
| 221 | |
| 222 | void grpc_platform_become_multipoller(grpc_pollset *pollset, grpc_fd **fds, |
| 223 | size_t nfds) { |
| 224 | size_t i; |
| 225 | pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr)); |
| 226 | pollset->vtable = &multipoll_with_poll_pollset; |
| 227 | pollset->data.ptr = h; |
| 228 | h->fd_count = nfds; |
| 229 | h->fd_capacity = nfds; |
| 230 | h->fds = gpr_malloc(nfds * sizeof(grpc_fd *)); |
| 231 | h->pfd_count = 0; |
| 232 | h->pfd_capacity = 0; |
| 233 | h->pfds = NULL; |
| 234 | h->selfds = NULL; |
| 235 | h->del_count = 0; |
| 236 | h->del_capacity = 0; |
| 237 | h->dels = NULL; |
| 238 | for (i = 0; i < nfds; i++) { |
| 239 | h->fds[i] = fds[i]; |
| 240 | grpc_fd_ref(fds[i]); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | #endif |