blob: 1377b6dc9e3acb6aeae97f3cedaa51a570a5eb33 [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
36#include <stdlib.h>
37
38#include "src/core/iomgr/iomgr_internal.h"
39#include "src/core/iomgr/alarm_internal.h"
Craig Tillerfa275a92015-06-01 13:55:54 -070040#include "src/core/support/string.h"
ctiller58393c22015-01-07 14:03:30 -080041#include <grpc/support/alloc.h>
42#include <grpc/support/log.h>
43#include <grpc/support/thd.h>
44#include <grpc/support/sync.h>
45
46typedef struct delayed_callback {
47 grpc_iomgr_cb_func cb;
48 void *cb_arg;
49 int success;
50 struct delayed_callback *next;
51} delayed_callback;
52
53static gpr_mu g_mu;
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +010054static gpr_cv g_rcv;
ctiller58393c22015-01-07 14:03:30 -080055static delayed_callback *g_cbs_head = NULL;
56static delayed_callback *g_cbs_tail = NULL;
57static int g_shutdown;
ctiller58393c22015-01-07 14:03:30 -080058static gpr_event g_background_callback_executor_done;
Craig Tillerfa275a92015-06-01 13:55:54 -070059static grpc_iomgr_object g_root_object;
ctiller58393c22015-01-07 14:03:30 -080060
61/* Execute followup callbacks continuously.
62 Other threads may check in and help during pollset_work() */
63static void background_callback_executor(void *ignored) {
64 gpr_mu_lock(&g_mu);
65 while (!g_shutdown) {
66 gpr_timespec deadline = gpr_inf_future;
David Garcia Quintas00ff7df2015-05-12 00:19:47 -070067 gpr_timespec short_deadline =
68 gpr_time_add(gpr_now(), gpr_time_from_millis(100));
ctiller58393c22015-01-07 14:03:30 -080069 if (g_cbs_head) {
70 delayed_callback *cb = g_cbs_head;
71 g_cbs_head = cb->next;
72 if (!g_cbs_head) g_cbs_tail = NULL;
73 gpr_mu_unlock(&g_mu);
74 cb->cb(cb->cb_arg, cb->success);
75 gpr_free(cb);
76 gpr_mu_lock(&g_mu);
77 } else if (grpc_alarm_check(&g_mu, gpr_now(), &deadline)) {
78 } else {
David Garcia Quintas00ff7df2015-05-12 00:19:47 -070079 gpr_mu_unlock(&g_mu);
80 gpr_sleep_until(gpr_time_min(short_deadline, deadline));
81 gpr_mu_lock(&g_mu);
ctiller58393c22015-01-07 14:03:30 -080082 }
83 }
84 gpr_mu_unlock(&g_mu);
85 gpr_event_set(&g_background_callback_executor_done, (void *)1);
86}
87
David Garcia Quintas5b984ce2015-05-12 16:04:28 -070088void grpc_kick_poller(void) {
89 /* Empty. The background callback executor polls periodically. The activity
90 * the kicker is trying to draw the executor's attention to will be picked up
91 * either by one of the periodic wakeups or by one of the polling application
92 * threads. */
93}
ctiller58393c22015-01-07 14:03:30 -080094
Craig Tiller32946d32015-01-15 11:37:30 -080095void grpc_iomgr_init(void) {
ctiller58393c22015-01-07 14:03:30 -080096 gpr_thd_id id;
97 gpr_mu_init(&g_mu);
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +010098 gpr_cv_init(&g_rcv);
ctiller58393c22015-01-07 14:03:30 -080099 grpc_alarm_list_init(gpr_now());
Craig Tillerfa275a92015-06-01 13:55:54 -0700100 g_root_object.next = g_root_object.prev = &g_root_object;
101 g_root_object.name = "root";
ctiller58393c22015-01-07 14:03:30 -0800102 grpc_iomgr_platform_init();
103 gpr_event_init(&g_background_callback_executor_done);
104 gpr_thd_new(&id, background_callback_executor, NULL, NULL);
105}
106
Craig Tillerfa275a92015-06-01 13:55:54 -0700107static size_t count_objects(void) {
108 grpc_iomgr_object *obj;
109 size_t n = 0;
110 for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
111 n++;
112 }
113 return n;
114}
115
Craig Tiller32946d32015-01-15 11:37:30 -0800116void grpc_iomgr_shutdown(void) {
ctiller58393c22015-01-07 14:03:30 -0800117 delayed_callback *cb;
Craig Tillerfa275a92015-06-01 13:55:54 -0700118 grpc_iomgr_object *obj;
ctiller58393c22015-01-07 14:03:30 -0800119 gpr_timespec shutdown_deadline =
120 gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
121
ctiller58393c22015-01-07 14:03:30 -0800122
123 gpr_mu_lock(&g_mu);
124 g_shutdown = 1;
Craig Tillerfa275a92015-06-01 13:55:54 -0700125 while (g_cbs_head || g_root_object.next != &g_root_object) {
126 size_t nobjs = count_objects();
127 gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", nobjs,
ctiller58393c22015-01-07 14:03:30 -0800128 g_cbs_head ? " and executing final callbacks" : "");
Craig Tillerfa275a92015-06-01 13:55:54 -0700129 if (g_cbs_head) {
130 do {
131 cb = g_cbs_head;
132 g_cbs_head = cb->next;
133 if (!g_cbs_head) g_cbs_tail = NULL;
134 gpr_mu_unlock(&g_mu);
ctiller58393c22015-01-07 14:03:30 -0800135
Craig Tillerfa275a92015-06-01 13:55:54 -0700136 cb->cb(cb->cb_arg, 0);
137 gpr_free(cb);
138 gpr_mu_lock(&g_mu);
139 } while (g_cbs_head);
140 continue;
ctiller58393c22015-01-07 14:03:30 -0800141 }
Craig Tillerfa275a92015-06-01 13:55:54 -0700142 if (nobjs > 0) {
Nicolas Noble8703f4d2015-03-23 13:52:18 -0700143 int timeout = 0;
144 gpr_timespec short_deadline = gpr_time_add(gpr_now(),
145 gpr_time_from_millis(100));
146 while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
147 if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
148 timeout = 1;
149 break;
150 }
151 }
152 if (timeout) {
ctiller58393c22015-01-07 14:03:30 -0800153 gpr_log(GPR_DEBUG,
154 "Failed to free %d iomgr objects before shutdown deadline: "
155 "memory leaks are likely",
Craig Tillerfa275a92015-06-01 13:55:54 -0700156 count_objects());
157 for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
158 gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s", obj->name);
159 }
ctiller58393c22015-01-07 14:03:30 -0800160 break;
161 }
162 }
163 }
164 gpr_mu_unlock(&g_mu);
165
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +0100166 grpc_kick_poller();
ctiller58393c22015-01-07 14:03:30 -0800167 gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future);
168
David Klempnerd1785242015-01-28 17:00:21 -0800169 grpc_iomgr_platform_shutdown();
ctiller58393c22015-01-07 14:03:30 -0800170 grpc_alarm_list_shutdown();
171 gpr_mu_destroy(&g_mu);
Nicolas "Pixel" Nobleae7b45a2015-02-04 03:28:34 +0100172 gpr_cv_destroy(&g_rcv);
ctiller58393c22015-01-07 14:03:30 -0800173}
174
Craig Tillerfa275a92015-06-01 13:55:54 -0700175void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
176 obj->name = gpr_strdup(name);
ctiller58393c22015-01-07 14:03:30 -0800177 gpr_mu_lock(&g_mu);
Craig Tillerfa275a92015-06-01 13:55:54 -0700178 obj->next = &g_root_object;
179 obj->prev = obj->next->prev;
180 obj->next->prev = obj->prev->next = obj;
ctiller58393c22015-01-07 14:03:30 -0800181 gpr_mu_unlock(&g_mu);
182}
183
Craig Tillerfa275a92015-06-01 13:55:54 -0700184void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
185 gpr_free(obj->name);
ctiller58393c22015-01-07 14:03:30 -0800186 gpr_mu_lock(&g_mu);
Craig Tillerfa275a92015-06-01 13:55:54 -0700187 obj->next->prev = obj->prev;
188 obj->prev->next = obj->next;
189 gpr_cv_signal(&g_rcv);
ctiller58393c22015-01-07 14:03:30 -0800190 gpr_mu_unlock(&g_mu);
191}
192
193void grpc_iomgr_add_delayed_callback(grpc_iomgr_cb_func cb, void *cb_arg,
194 int success) {
195 delayed_callback *dcb = gpr_malloc(sizeof(delayed_callback));
196 dcb->cb = cb;
197 dcb->cb_arg = cb_arg;
198 dcb->success = success;
199 gpr_mu_lock(&g_mu);
200 dcb->next = NULL;
201 if (!g_cbs_tail) {
202 g_cbs_head = g_cbs_tail = dcb;
203 } else {
204 g_cbs_tail->next = dcb;
205 g_cbs_tail = dcb;
206 }
ctiller58393c22015-01-07 14:03:30 -0800207 gpr_mu_unlock(&g_mu);
208}
209
210void grpc_iomgr_add_callback(grpc_iomgr_cb_func cb, void *cb_arg) {
211 grpc_iomgr_add_delayed_callback(cb, cb_arg, 1);
212}
213
214int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success) {
215 int n = 0;
216 gpr_mu *retake_mu = NULL;
217 delayed_callback *cb;
218 for (;;) {
219 /* check for new work */
220 if (!gpr_mu_trylock(&g_mu)) {
221 break;
222 }
223 cb = g_cbs_head;
224 if (!cb) {
225 gpr_mu_unlock(&g_mu);
226 break;
227 }
228 g_cbs_head = cb->next;
229 if (!g_cbs_head) g_cbs_tail = NULL;
230 gpr_mu_unlock(&g_mu);
231 /* if we have a mutex to drop, do so before executing work */
232 if (drop_mu) {
233 gpr_mu_unlock(drop_mu);
234 retake_mu = drop_mu;
235 drop_mu = NULL;
236 }
237 cb->cb(cb->cb_arg, success && cb->success);
238 gpr_free(cb);
239 n++;
240 }
241 if (retake_mu) {
242 gpr_mu_lock(retake_mu);
243 }
244 return n;
Craig Tiller190d3602015-02-18 09:23:38 -0800245}