1 /*
2 Unix SMB/CIFS implementation.
3
4 common events code for immediate events
5
6 Copyright (C) Stefan Metzmacher 2009
7
8 ** NOTE! The following LGPL license applies to the tevent
9 ** library. This does NOT imply that all of Samba is released
10 ** under the LGPL
11
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
16
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "replace.h"
27 #define TEVENT_DEPRECATED 1
28 #include "tevent.h"
29 #include "tevent_internal.h"
30 #include "tevent_util.h"
31
tevent_common_immediate_cancel(struct tevent_immediate * im)32 static void tevent_common_immediate_cancel(struct tevent_immediate *im)
33 {
34 const char *create_location = im->create_location;
35 bool busy = im->busy;
36
37 if (im->destroyed) {
38 tevent_abort(im->event_ctx, "tevent_immediate use after free");
39 return;
40 }
41
42 if (!im->event_ctx) {
43 return;
44 }
45
46 if (im->handler_name != NULL) {
47 tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
48 "Cancel immediate event %p \"%s\"\n",
49 im, im->handler_name);
50 }
51
52 /* let the backend free im->additional_data */
53 if (im->cancel_fn) {
54 im->cancel_fn(im);
55 }
56
57 DLIST_REMOVE(im->event_ctx->immediate_events, im);
58
59 *im = (struct tevent_immediate) {
60 .create_location = create_location,
61 .busy = busy,
62 };
63
64 if (!busy) {
65 talloc_set_destructor(im, NULL);
66 }
67 }
68
69 /*
70 destroy an immediate event
71 */
tevent_common_immediate_destructor(struct tevent_immediate * im)72 static int tevent_common_immediate_destructor(struct tevent_immediate *im)
73 {
74 if (im->destroyed) {
75 tevent_common_check_double_free(im,
76 "tevent_immediate double free");
77 goto done;
78 }
79
80 tevent_common_immediate_cancel(im);
81
82 im->destroyed = true;
83
84 done:
85 if (im->busy) {
86 return -1;
87 }
88
89 return 0;
90 }
91
92 /*
93 * schedule an immediate event on
94 */
tevent_common_schedule_immediate(struct tevent_immediate * im,struct tevent_context * ev,tevent_immediate_handler_t handler,void * private_data,const char * handler_name,const char * location)95 void tevent_common_schedule_immediate(struct tevent_immediate *im,
96 struct tevent_context *ev,
97 tevent_immediate_handler_t handler,
98 void *private_data,
99 const char *handler_name,
100 const char *location)
101 {
102 const char *create_location = im->create_location;
103 bool busy = im->busy;
104 struct tevent_wrapper_glue *glue = im->wrapper;
105
106 tevent_common_immediate_cancel(im);
107
108 if (!handler) {
109 return;
110 }
111
112 *im = (struct tevent_immediate) {
113 .event_ctx = ev,
114 .wrapper = glue,
115 .handler = handler,
116 .private_data = private_data,
117 .handler_name = handler_name,
118 .create_location = create_location,
119 .schedule_location = location,
120 .busy = busy,
121 };
122
123 DLIST_ADD_END(ev->immediate_events, im);
124 talloc_set_destructor(im, tevent_common_immediate_destructor);
125
126 tevent_debug(ev, TEVENT_DEBUG_TRACE,
127 "Schedule immediate event \"%s\": %p\n",
128 handler_name, im);
129 }
130
tevent_common_invoke_immediate_handler(struct tevent_immediate * im,bool * removed)131 int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
132 bool *removed)
133 {
134 struct tevent_context *handler_ev = im->event_ctx;
135 struct tevent_context *ev = im->event_ctx;
136 struct tevent_immediate cur = *im;
137
138 if (removed != NULL) {
139 *removed = false;
140 }
141
142 tevent_debug(ev, TEVENT_DEBUG_TRACE,
143 "Run immediate event \"%s\": %p\n",
144 im->handler_name, im);
145
146 /*
147 * remember the handler and then clear the event
148 * the handler might reschedule the event
149 */
150
151 im->busy = true;
152 im->handler_name = NULL;
153 tevent_common_immediate_cancel(im);
154 if (cur.wrapper != NULL) {
155 handler_ev = cur.wrapper->wrap_ev;
156
157 tevent_wrapper_push_use_internal(handler_ev, cur.wrapper);
158 cur.wrapper->ops->before_immediate_handler(
159 cur.wrapper->wrap_ev,
160 cur.wrapper->private_state,
161 cur.wrapper->main_ev,
162 im,
163 cur.handler_name,
164 cur.schedule_location);
165 }
166 cur.handler(handler_ev, im, cur.private_data);
167 if (cur.wrapper != NULL) {
168 cur.wrapper->ops->after_immediate_handler(
169 cur.wrapper->wrap_ev,
170 cur.wrapper->private_state,
171 cur.wrapper->main_ev,
172 im,
173 cur.handler_name,
174 cur.schedule_location);
175 tevent_wrapper_pop_use_internal(handler_ev, cur.wrapper);
176 }
177 im->busy = false;
178
179 if (im->destroyed) {
180 talloc_set_destructor(im, NULL);
181 TALLOC_FREE(im);
182 if (removed != NULL) {
183 *removed = true;
184 }
185 }
186
187 return 0;
188 }
189
190 /*
191 trigger the first immediate event and return true
192 if no event was triggered return false
193 */
tevent_common_loop_immediate(struct tevent_context * ev)194 bool tevent_common_loop_immediate(struct tevent_context *ev)
195 {
196 struct tevent_immediate *im = ev->immediate_events;
197 int ret;
198
199 if (!im) {
200 return false;
201 }
202
203 ret = tevent_common_invoke_immediate_handler(im, NULL);
204 if (ret != 0) {
205 tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
206 }
207
208 return true;
209 }
210
211