replace/setxattr: correctly use our flags on Darwin
[gd/samba-autobuild/.git] / lib / tevent / tevent_immediate.c
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
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 */
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  */
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
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 */
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