blob: 2555322532c3ba11a08d47ecdb1f8ad1f5c4e405 [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 "src/core/iomgr/pollset_posix.h"
35
36#include <errno.h>
37#include <poll.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "src/core/iomgr/alarm_internal.h"
43#include "src/core/iomgr/fd_posix.h"
44#include "src/core/iomgr/iomgr_internal.h"
45#include "src/core/iomgr/socket_utils_posix.h"
46#include <grpc/support/alloc.h>
47#include <grpc/support/log.h>
48#include <grpc/support/thd.h>
49#include <grpc/support/useful.h>
50
ctiller58393c22015-01-07 14:03:30 -080051static grpc_pollset g_backup_pollset;
52static int g_shutdown_backup_poller;
53static gpr_event g_backup_poller_done;
54
55static void backup_poller(void *p) {
56 gpr_timespec delta = gpr_time_from_millis(100);
57 gpr_timespec last_poll = gpr_now();
58
59 gpr_mu_lock(&g_backup_pollset.mu);
60 while (g_shutdown_backup_poller == 0) {
61 gpr_timespec next_poll = gpr_time_add(last_poll, delta);
62 grpc_pollset_work(&g_backup_pollset, next_poll);
63 gpr_mu_unlock(&g_backup_pollset.mu);
64 gpr_sleep_until(next_poll);
65 gpr_mu_lock(&g_backup_pollset.mu);
66 last_poll = next_poll;
67 }
68 gpr_mu_unlock(&g_backup_pollset.mu);
69
70 gpr_event_set(&g_backup_poller_done, (void *)1);
71}
72
ctiller58393c22015-01-07 14:03:30 -080073void grpc_pollset_kick(grpc_pollset *p) {
74 if (!p->counter) return;
David Klempner7f3ed1e2015-01-16 15:35:56 -080075 grpc_pollset_kick_kick(&p->kick_state);
ctiller58393c22015-01-07 14:03:30 -080076}
77
David Klempner7f3ed1e2015-01-16 15:35:56 -080078void grpc_pollset_force_kick(grpc_pollset *p) { grpc_pollset_kick(p); }
ctiller58393c22015-01-07 14:03:30 -080079
80/* global state management */
81
Craig Tiller32946d32015-01-15 11:37:30 -080082grpc_pollset *grpc_backup_pollset(void) { return &g_backup_pollset; }
ctiller58393c22015-01-07 14:03:30 -080083
Craig Tiller32946d32015-01-15 11:37:30 -080084void grpc_pollset_global_init(void) {
ctiller58393c22015-01-07 14:03:30 -080085 gpr_thd_id id;
86
David Klempner7f3ed1e2015-01-16 15:35:56 -080087 /* Initialize kick fd state */
88 grpc_pollset_kick_global_init();
ctiller58393c22015-01-07 14:03:30 -080089
90 /* initialize the backup pollset */
91 grpc_pollset_init(&g_backup_pollset);
92
93 /* start the backup poller thread */
94 g_shutdown_backup_poller = 0;
95 gpr_event_init(&g_backup_poller_done);
96 gpr_thd_new(&id, backup_poller, NULL, NULL);
97}
98
Craig Tiller32946d32015-01-15 11:37:30 -080099void grpc_pollset_global_shutdown(void) {
ctiller58393c22015-01-07 14:03:30 -0800100 /* terminate the backup poller thread */
101 gpr_mu_lock(&g_backup_pollset.mu);
102 g_shutdown_backup_poller = 1;
103 gpr_mu_unlock(&g_backup_pollset.mu);
104 gpr_event_wait(&g_backup_poller_done, gpr_inf_future);
105
106 /* destroy the backup pollset */
107 grpc_pollset_destroy(&g_backup_pollset);
108
David Klempner7f3ed1e2015-01-16 15:35:56 -0800109 /* destroy the kick pipes */
110 grpc_pollset_kick_global_destroy();
ctiller58393c22015-01-07 14:03:30 -0800111}
112
113/* main interface */
114
115static void become_empty_pollset(grpc_pollset *pollset);
116static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd);
117
118void grpc_pollset_init(grpc_pollset *pollset) {
119 gpr_mu_init(&pollset->mu);
120 gpr_cv_init(&pollset->cv);
David Klempner7f3ed1e2015-01-16 15:35:56 -0800121 grpc_pollset_kick_init(&pollset->kick_state);
ctiller58393c22015-01-07 14:03:30 -0800122 become_empty_pollset(pollset);
123}
124
125void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
126 gpr_mu_lock(&pollset->mu);
127 pollset->vtable->add_fd(pollset, fd);
128 gpr_cv_broadcast(&pollset->cv);
129 gpr_mu_unlock(&pollset->mu);
130}
131
132void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
133 gpr_mu_lock(&pollset->mu);
134 pollset->vtable->del_fd(pollset, fd);
135 gpr_cv_broadcast(&pollset->cv);
136 gpr_mu_unlock(&pollset->mu);
137}
138
139int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
140 /* pollset->mu already held */
141 gpr_timespec now;
142 now = gpr_now();
143 if (gpr_time_cmp(now, deadline) > 0) {
144 return 0;
145 }
146 if (grpc_maybe_call_delayed_callbacks(&pollset->mu, 1)) {
147 return 1;
148 }
149 if (grpc_alarm_check(&pollset->mu, now, &deadline)) {
150 return 1;
151 }
152 return pollset->vtable->maybe_work(pollset, deadline, now, 1);
153}
154
155void grpc_pollset_destroy(grpc_pollset *pollset) {
156 pollset->vtable->destroy(pollset);
David Klempner7f3ed1e2015-01-16 15:35:56 -0800157 grpc_pollset_kick_destroy(&pollset->kick_state);
ctiller58393c22015-01-07 14:03:30 -0800158 gpr_mu_destroy(&pollset->mu);
159 gpr_cv_destroy(&pollset->cv);
160}
161
162/*
163 * empty_pollset - a vtable that provides polling for NO file descriptors
164 */
165
166static void empty_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
167 become_unary_pollset(pollset, fd);
168}
169
170static void empty_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {}
171
172static int empty_pollset_maybe_work(grpc_pollset *pollset,
173 gpr_timespec deadline, gpr_timespec now,
174 int allow_synchronous_callback) {
175 return 0;
176}
177
178static void empty_pollset_destroy(grpc_pollset *pollset) {}
179
180static const grpc_pollset_vtable empty_pollset = {
181 empty_pollset_add_fd, empty_pollset_del_fd, empty_pollset_maybe_work,
182 empty_pollset_destroy};
183
184static void become_empty_pollset(grpc_pollset *pollset) {
185 pollset->vtable = &empty_pollset;
186}
187
188/*
189 * unary_poll_pollset - a vtable that provides polling for one file descriptor
190 * via poll()
191 */
192
193static void unary_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
194 grpc_fd *fds[2];
195 if (fd == pollset->data.ptr) return;
196 fds[0] = pollset->data.ptr;
197 fds[1] = fd;
198 grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds));
199 grpc_fd_unref(fds[0]);
200}
201
202static void unary_poll_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
203 if (fd == pollset->data.ptr) {
204 grpc_fd_unref(pollset->data.ptr);
205 become_empty_pollset(pollset);
206 }
207}
208
209static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
210 gpr_timespec deadline,
211 gpr_timespec now,
212 int allow_synchronous_callback) {
213 struct pollfd pfd[2];
214 grpc_fd *fd;
215 int timeout;
216 int r;
217
218 if (pollset->counter) {
219 return 0;
220 }
221 fd = pollset->data.ptr;
222 if (grpc_fd_is_orphaned(fd)) {
223 grpc_fd_unref(fd);
224 become_empty_pollset(pollset);
225 return 0;
226 }
227 if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
228 timeout = -1;
229 } else {
230 timeout = gpr_time_to_millis(gpr_time_sub(deadline, now));
231 if (timeout <= 0) {
232 return 1;
233 }
234 }
David Klempner7f3ed1e2015-01-16 15:35:56 -0800235 pfd[0].fd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
236 if (pfd[0].fd < 0) {
237 /* Already kicked */
238 return 1;
239 }
ctiller58393c22015-01-07 14:03:30 -0800240 pfd[0].events = POLLIN;
241 pfd[0].revents = 0;
242 pfd[1].fd = fd->fd;
243 pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT);
244 pfd[1].revents = 0;
245 pollset->counter = 1;
246 gpr_mu_unlock(&pollset->mu);
247
248 r = poll(pfd, GPR_ARRAY_SIZE(pfd), timeout);
249 if (r < 0) {
ctillerd9962df2015-01-07 15:31:39 -0800250 if (errno != EINTR) {
251 gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
252 }
ctiller58393c22015-01-07 14:03:30 -0800253 } else if (r == 0) {
254 /* do nothing */
255 } else {
256 if (pfd[0].revents & POLLIN) {
David Klempner7f3ed1e2015-01-16 15:35:56 -0800257 grpc_pollset_kick_consume(&pollset->kick_state);
ctiller58393c22015-01-07 14:03:30 -0800258 }
259 if (pfd[1].revents & POLLIN) {
260 grpc_fd_become_readable(fd, allow_synchronous_callback);
261 }
262 if (pfd[1].revents & POLLOUT) {
263 grpc_fd_become_writable(fd, allow_synchronous_callback);
264 }
265 }
266
David Klempner7f3ed1e2015-01-16 15:35:56 -0800267 grpc_pollset_kick_post_poll(&pollset->kick_state);
268
ctiller58393c22015-01-07 14:03:30 -0800269 gpr_mu_lock(&pollset->mu);
270 grpc_fd_end_poll(fd, pollset);
271 pollset->counter = 0;
272 gpr_cv_broadcast(&pollset->cv);
273 return 1;
274}
275
276static void unary_poll_pollset_destroy(grpc_pollset *pollset) {
277 GPR_ASSERT(pollset->counter == 0);
278 grpc_fd_unref(pollset->data.ptr);
279}
280
281static const grpc_pollset_vtable unary_poll_pollset = {
282 unary_poll_pollset_add_fd, unary_poll_pollset_del_fd,
283 unary_poll_pollset_maybe_work, unary_poll_pollset_destroy};
284
285static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd) {
286 pollset->vtable = &unary_poll_pollset;
287 pollset->counter = 0;
288 pollset->data.ptr = fd;
289 grpc_fd_ref(fd);
290}