blob: 7c9a9491cb03bf5b7a919c0267f948d399f5a47d [file] [log] [blame]
ctiller58393c22015-01-07 14:03:30 -08001/*
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
51typedef 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
68static 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
84static 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
96static 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
105static 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 Klempner7f3ed1e2015-01-16 15:35:56 -0800134 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 }
ctiller58393c22015-01-07 14:03:30 -0800139 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) {
ctillerd9962df2015-01-07 15:31:39 -0800173 if (errno != EINTR) {
174 gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
175 }
ctiller58393c22015-01-07 14:03:30 -0800176 } else if (r == 0) {
177 /* do nothing */
178 } else {
179 if (h->pfds[0].revents & POLLIN) {
David Klempner7f3ed1e2015-01-16 15:35:56 -0800180 grpc_pollset_kick_consume(&pollset->kick_state);
ctiller58393c22015-01-07 14:03:30 -0800181 }
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 Klempner7f3ed1e2015-01-16 15:35:56 -0800191 grpc_pollset_kick_post_poll(&pollset->kick_state);
ctiller58393c22015-01-07 14:03:30 -0800192 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
200static 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
217static 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
222void 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