blob: 1d6fa9053eb87dc9d2d55d8d1a6d3403b237d10c [file] [log] [blame]
ctiller58393c22015-01-07 14:03:30 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
ctiller58393c22015-01-07 14:03:30 -08004 * 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/iomgr.h"
35
David Garcia Quintas5f228f52015-05-26 19:58:50 -070036#include <assert.h>
ctiller58393c22015-01-07 14:03:30 -080037#include <stdlib.h>
38
39#include "src/core/iomgr/iomgr_internal.h"
40#include "src/core/iomgr/alarm_internal.h"
41#include <grpc/support/alloc.h>
42#include <grpc/support/log.h>
43#include <grpc/support/thd.h>
44#include <grpc/support/sync.h>
45
ctiller58393c22015-01-07 14:03:30 -080046static gpr_mu g_mu;
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +010047static gpr_cv g_rcv;
David Garcia Quintas5f228f52015-05-26 19:58:50 -070048static grpc_iomgr_closure *g_cbs_head = NULL;
49static grpc_iomgr_closure *g_cbs_tail = NULL;
ctiller58393c22015-01-07 14:03:30 -080050static int g_shutdown;
51static int g_refs;
52static gpr_event g_background_callback_executor_done;
53
54/* Execute followup callbacks continuously.
55 Other threads may check in and help during pollset_work() */
56static void background_callback_executor(void *ignored) {
57 gpr_mu_lock(&g_mu);
58 while (!g_shutdown) {
59 gpr_timespec deadline = gpr_inf_future;
David Garcia Quintas00ff7df2015-05-12 00:19:47 -070060 gpr_timespec short_deadline =
61 gpr_time_add(gpr_now(), gpr_time_from_millis(100));
ctiller58393c22015-01-07 14:03:30 -080062 if (g_cbs_head) {
David Garcia Quintasa30020f2015-05-27 19:21:01 -070063 grpc_iomgr_closure *closure = g_cbs_head;
64 g_cbs_head = closure->next;
ctiller58393c22015-01-07 14:03:30 -080065 if (!g_cbs_head) g_cbs_tail = NULL;
66 gpr_mu_unlock(&g_mu);
David Garcia Quintasa30020f2015-05-27 19:21:01 -070067 assert(closure->success >= 0);
68 closure->cb(closure->cb_arg, closure->success);
ctiller58393c22015-01-07 14:03:30 -080069 gpr_mu_lock(&g_mu);
70 } else if (grpc_alarm_check(&g_mu, gpr_now(), &deadline)) {
71 } else {
David Garcia Quintas00ff7df2015-05-12 00:19:47 -070072 gpr_mu_unlock(&g_mu);
73 gpr_sleep_until(gpr_time_min(short_deadline, deadline));
74 gpr_mu_lock(&g_mu);
ctiller58393c22015-01-07 14:03:30 -080075 }
76 }
77 gpr_mu_unlock(&g_mu);
78 gpr_event_set(&g_background_callback_executor_done, (void *)1);
79}
80
David Garcia Quintas5b984ce2015-05-12 16:04:28 -070081void grpc_kick_poller(void) {
82 /* Empty. The background callback executor polls periodically. The activity
83 * the kicker is trying to draw the executor's attention to will be picked up
84 * either by one of the periodic wakeups or by one of the polling application
85 * threads. */
86}
ctiller58393c22015-01-07 14:03:30 -080087
Craig Tiller32946d32015-01-15 11:37:30 -080088void grpc_iomgr_init(void) {
ctiller58393c22015-01-07 14:03:30 -080089 gpr_thd_id id;
90 gpr_mu_init(&g_mu);
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +010091 gpr_cv_init(&g_rcv);
ctiller58393c22015-01-07 14:03:30 -080092 grpc_alarm_list_init(gpr_now());
93 g_refs = 0;
94 grpc_iomgr_platform_init();
95 gpr_event_init(&g_background_callback_executor_done);
96 gpr_thd_new(&id, background_callback_executor, NULL, NULL);
97}
98
Craig Tiller32946d32015-01-15 11:37:30 -080099void grpc_iomgr_shutdown(void) {
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700100 grpc_iomgr_closure *closure;
ctiller58393c22015-01-07 14:03:30 -0800101 gpr_timespec shutdown_deadline =
102 gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
103
ctiller58393c22015-01-07 14:03:30 -0800104
105 gpr_mu_lock(&g_mu);
106 g_shutdown = 1;
107 while (g_cbs_head || g_refs) {
108 gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", g_refs,
109 g_cbs_head ? " and executing final callbacks" : "");
110 while (g_cbs_head) {
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700111 closure = g_cbs_head;
112 g_cbs_head = closure->next;
ctiller58393c22015-01-07 14:03:30 -0800113 if (!g_cbs_head) g_cbs_tail = NULL;
114 gpr_mu_unlock(&g_mu);
115
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700116 closure->cb(closure->cb_arg, 0);
ctiller58393c22015-01-07 14:03:30 -0800117 gpr_mu_lock(&g_mu);
118 }
119 if (g_refs) {
Nicolas Noble8703f4d2015-03-23 13:52:18 -0700120 int timeout = 0;
121 gpr_timespec short_deadline = gpr_time_add(gpr_now(),
122 gpr_time_from_millis(100));
123 while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
124 if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
125 timeout = 1;
126 break;
127 }
128 }
129 if (timeout) {
ctiller58393c22015-01-07 14:03:30 -0800130 gpr_log(GPR_DEBUG,
131 "Failed to free %d iomgr objects before shutdown deadline: "
132 "memory leaks are likely",
133 g_refs);
134 break;
135 }
136 }
137 }
138 gpr_mu_unlock(&g_mu);
139
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +0100140 grpc_kick_poller();
ctiller58393c22015-01-07 14:03:30 -0800141 gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future);
142
David Klempnerd1785242015-01-28 17:00:21 -0800143 grpc_iomgr_platform_shutdown();
ctiller58393c22015-01-07 14:03:30 -0800144 grpc_alarm_list_shutdown();
145 gpr_mu_destroy(&g_mu);
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +0100146 gpr_cv_destroy(&g_rcv);
ctiller58393c22015-01-07 14:03:30 -0800147}
148
Craig Tiller32946d32015-01-15 11:37:30 -0800149void grpc_iomgr_ref(void) {
ctiller58393c22015-01-07 14:03:30 -0800150 gpr_mu_lock(&g_mu);
151 ++g_refs;
152 gpr_mu_unlock(&g_mu);
153}
154
Craig Tiller32946d32015-01-15 11:37:30 -0800155void grpc_iomgr_unref(void) {
ctiller58393c22015-01-07 14:03:30 -0800156 gpr_mu_lock(&g_mu);
157 if (0 == --g_refs) {
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +0100158 gpr_cv_signal(&g_rcv);
ctiller58393c22015-01-07 14:03:30 -0800159 }
160 gpr_mu_unlock(&g_mu);
161}
162
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700163
164void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb,
165 void *cb_arg) {
166 closure->cb = cb;
167 closure->cb_arg = cb_arg;
168 closure->success = -1; /* uninitialized */
169 closure->next = NULL;
David Garcia Quintas5f228f52015-05-26 19:58:50 -0700170}
171
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700172typedef struct {
173 grpc_iomgr_closure managed;
174 grpc_iomgr_closure *manager;
175} managed_closure_arg;
176
177static void closure_manager_func(void *arg, int success) {
178 managed_closure_arg *mc_arg = (managed_closure_arg*) arg;
179
180 mc_arg->managed.cb(mc_arg->managed.cb_arg, success);
181 gpr_free(mc_arg->manager);
182 gpr_free(mc_arg);
183}
184
185void grpc_iomgr_managed_closure_init(grpc_iomgr_closure *manager,
186 grpc_iomgr_cb_func managed_cb,
187 void *managed_cb_arg) {
188 managed_closure_arg *managed_arg = gpr_malloc(sizeof(managed_closure_arg));
189
190 managed_arg->managed.cb = managed_cb;
191 managed_arg->managed.cb_arg = managed_cb_arg;
192 managed_arg->manager= manager;
193
194 grpc_iomgr_closure_init(manager, closure_manager_func, managed_arg);
195}
196
197
198void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *closure, int success) {
199 closure->success = success;
ctiller58393c22015-01-07 14:03:30 -0800200 gpr_mu_lock(&g_mu);
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700201 closure->next = NULL;
ctiller58393c22015-01-07 14:03:30 -0800202 if (!g_cbs_tail) {
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700203 g_cbs_head = g_cbs_tail = closure;
ctiller58393c22015-01-07 14:03:30 -0800204 } else {
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700205 g_cbs_tail->next = closure;
206 g_cbs_tail = closure;
ctiller58393c22015-01-07 14:03:30 -0800207 }
ctiller58393c22015-01-07 14:03:30 -0800208 gpr_mu_unlock(&g_mu);
209}
210
David Garcia Quintas5f228f52015-05-26 19:58:50 -0700211
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700212void grpc_iomgr_add_callback(grpc_iomgr_closure *closure) {
213 grpc_iomgr_add_delayed_callback(closure, 1);
ctiller58393c22015-01-07 14:03:30 -0800214}
215
David Garcia Quintas5f228f52015-05-26 19:58:50 -0700216
ctiller58393c22015-01-07 14:03:30 -0800217int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success) {
218 int n = 0;
219 gpr_mu *retake_mu = NULL;
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700220 grpc_iomgr_closure *closure;
ctiller58393c22015-01-07 14:03:30 -0800221 for (;;) {
222 /* check for new work */
223 if (!gpr_mu_trylock(&g_mu)) {
224 break;
225 }
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700226 closure = g_cbs_head;
227 if (!closure) {
ctiller58393c22015-01-07 14:03:30 -0800228 gpr_mu_unlock(&g_mu);
229 break;
230 }
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700231 g_cbs_head = closure->next;
ctiller58393c22015-01-07 14:03:30 -0800232 if (!g_cbs_head) g_cbs_tail = NULL;
233 gpr_mu_unlock(&g_mu);
234 /* if we have a mutex to drop, do so before executing work */
235 if (drop_mu) {
236 gpr_mu_unlock(drop_mu);
237 retake_mu = drop_mu;
238 drop_mu = NULL;
239 }
David Garcia Quintasa30020f2015-05-27 19:21:01 -0700240 assert(closure->success >= 0);
241 closure->cb(closure->cb_arg, success && closure->success);
ctiller58393c22015-01-07 14:03:30 -0800242 n++;
243 }
244 if (retake_mu) {
245 gpr_mu_lock(retake_mu);
246 }
247 return n;
Craig Tiller190d3602015-02-18 09:23:38 -0800248}