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