1 /* $NetBSD: regress_finalize.c,v 1.1.1.1 2017/01/31 21:14:53 christos Exp $ */ 2 /* 3 * Copyright (c) 2013 Niels Provos and Nick Mathewson 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "event2/event-config.h" 29 #include <sys/cdefs.h> 30 __RCSID("$NetBSD: regress_finalize.c,v 1.1.1.1 2017/01/31 21:14:53 christos Exp $"); 31 #include "evconfig-private.h" 32 #include "tinytest.h" 33 #include "tinytest_macros.h" 34 #include <stdlib.h> 35 36 #include "event2/event.h" 37 #include "event2/util.h" 38 #include "event-internal.h" 39 #include "defer-internal.h" 40 41 #include "regress.h" 42 #include "regress_thread.h" 43 44 static void 45 timer_callback(evutil_socket_t fd, short what, void *arg) 46 { 47 int *int_arg = arg; 48 *int_arg += 1; 49 (void)fd; 50 (void)what; 51 } 52 static void 53 simple_callback(struct event_callback *evcb, void *arg) 54 { 55 int *int_arg = arg; 56 *int_arg += 1; 57 (void)evcb; 58 } 59 static void 60 event_finalize_callback_1(struct event *ev, void *arg) 61 { 62 int *int_arg = arg; 63 *int_arg += 100; 64 (void)ev; 65 } 66 static void 67 callback_finalize_callback_1(struct event_callback *evcb, void *arg) 68 { 69 int *int_arg = arg; 70 *int_arg += 100; 71 (void)evcb; 72 } 73 74 75 static void 76 test_fin_cb_invoked(void *arg) 77 { 78 struct basic_test_data *data = arg; 79 struct event_base *base = data->base; 80 81 struct event *ev; 82 struct event ev2; 83 struct event_callback evcb; 84 int cb_called = 0; 85 int ev_called = 0; 86 87 const struct timeval ten_sec = {10,0}; 88 89 event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called); 90 ev = evtimer_new(base, timer_callback, &ev_called); 91 /* Just finalize them; don't bother adding. */ 92 event_free_finalize(0, ev, event_finalize_callback_1); 93 event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1); 94 95 event_base_dispatch(base); 96 97 tt_int_op(cb_called, ==, 100); 98 tt_int_op(ev_called, ==, 100); 99 100 ev_called = cb_called = 0; 101 event_base_assert_ok_(base); 102 103 /* Now try it when they're active. (actually, don't finalize: make 104 * sure activation can happen! */ 105 ev = evtimer_new(base, timer_callback, &ev_called); 106 event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called); 107 108 event_active(ev, EV_TIMEOUT, 1); 109 event_callback_activate_(base, &evcb); 110 111 event_base_dispatch(base); 112 tt_int_op(cb_called, ==, 1); 113 tt_int_op(ev_called, ==, 1); 114 115 ev_called = cb_called = 0; 116 event_base_assert_ok_(base); 117 118 /* Great, it worked. Now activate and finalize and make sure only 119 * finalizing happens. */ 120 event_active(ev, EV_TIMEOUT, 1); 121 event_callback_activate_(base, &evcb); 122 event_free_finalize(0, ev, event_finalize_callback_1); 123 event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1); 124 125 event_base_dispatch(base); 126 tt_int_op(cb_called, ==, 100); 127 tt_int_op(ev_called, ==, 100); 128 129 ev_called = 0; 130 131 event_base_assert_ok_(base); 132 133 /* Okay, now add but don't have it become active, and make sure *that* 134 * works. */ 135 ev = evtimer_new(base, timer_callback, &ev_called); 136 event_add(ev, &ten_sec); 137 event_free_finalize(0, ev, event_finalize_callback_1); 138 139 event_base_dispatch(base); 140 tt_int_op(ev_called, ==, 100); 141 142 ev_called = 0; 143 event_base_assert_ok_(base); 144 145 /* Now try adding and deleting after finalizing. */ 146 ev = evtimer_new(base, timer_callback, &ev_called); 147 evtimer_assign(&ev2, base, timer_callback, &ev_called); 148 event_add(ev, &ten_sec); 149 event_free_finalize(0, ev, event_finalize_callback_1); 150 event_finalize(0, &ev2, event_finalize_callback_1); 151 152 event_add(&ev2, &ten_sec); 153 event_del(ev); 154 event_active(&ev2, EV_TIMEOUT, 1); 155 156 event_base_dispatch(base); 157 tt_int_op(ev_called, ==, 200); 158 159 event_base_assert_ok_(base); 160 161 end: 162 ; 163 } 164 165 #ifndef EVENT__DISABLE_MM_REPLACEMENT 166 static void * 167 tfff_malloc(size_t n) 168 { 169 return malloc(n); 170 } 171 static void *tfff_p1=NULL, *tfff_p2=NULL; 172 static int tfff_p1_freed=0, tfff_p2_freed=0; 173 static void 174 tfff_free(void *p) 175 { 176 if (! p) 177 return; 178 if (p == tfff_p1) 179 ++tfff_p1_freed; 180 if (p == tfff_p2) 181 ++tfff_p2_freed; 182 free(p); 183 } 184 static void * 185 tfff_realloc(void *p, size_t sz) 186 { 187 return realloc(p,sz); 188 } 189 #endif 190 191 static void 192 test_fin_free_finalize(void *arg) 193 { 194 #ifdef EVENT__DISABLE_MM_REPLACEMENT 195 tinytest_set_test_skipped_(); 196 #else 197 struct event_base *base = NULL; 198 struct event *ev, *ev2; 199 int ev_called = 0; 200 int ev2_called = 0; 201 202 (void)arg; 203 204 event_set_mem_functions(tfff_malloc, tfff_realloc, tfff_free); 205 206 base = event_base_new(); 207 tt_assert(base); 208 209 ev = evtimer_new(base, timer_callback, &ev_called); 210 ev2 = evtimer_new(base, timer_callback, &ev2_called); 211 tfff_p1 = ev; 212 tfff_p2 = ev2; 213 event_free_finalize(0, ev, event_finalize_callback_1); 214 event_finalize(0, ev2, event_finalize_callback_1); 215 216 event_base_dispatch(base); 217 218 tt_int_op(ev_called, ==, 100); 219 tt_int_op(ev2_called, ==, 100); 220 221 event_base_assert_ok_(base); 222 tt_int_op(tfff_p1_freed, ==, 1); 223 tt_int_op(tfff_p2_freed, ==, 0); 224 225 event_free(ev2); 226 227 end: 228 if (base) 229 event_base_free(base); 230 #endif 231 } 232 233 /* For test_fin_within_cb */ 234 struct event_and_count { 235 struct event *ev; 236 struct event *ev2; 237 int count; 238 }; 239 static void 240 event_finalize_callback_2(struct event *ev, void *arg) 241 { 242 struct event_and_count *evc = arg; 243 evc->count += 100; 244 event_free(ev); 245 } 246 static void 247 timer_callback_2(evutil_socket_t fd, short what, void *arg) 248 { 249 struct event_and_count *evc = arg; 250 event_finalize(0, evc->ev, event_finalize_callback_2); 251 event_finalize(0, evc->ev2, event_finalize_callback_2); 252 ++ evc->count; 253 (void)fd; 254 (void)what; 255 } 256 257 static void 258 test_fin_within_cb(void *arg) 259 { 260 struct basic_test_data *data = arg; 261 struct event_base *base = data->base; 262 263 struct event_and_count evc1, evc2; 264 evc1.count = evc2.count = 0; 265 evc2.ev2 = evc1.ev = evtimer_new(base, timer_callback_2, &evc1); 266 evc1.ev2 = evc2.ev = evtimer_new(base, timer_callback_2, &evc2); 267 268 /* Activate both. The first one will have its callback run, which 269 * will finalize both of them, preventing the second one's callback 270 * from running. */ 271 event_active(evc1.ev, EV_TIMEOUT, 1); 272 event_active(evc2.ev, EV_TIMEOUT, 1); 273 274 event_base_dispatch(base); 275 tt_int_op(evc1.count, ==, 101); 276 tt_int_op(evc2.count, ==, 100); 277 278 event_base_assert_ok_(base); 279 /* Now try with EV_PERSIST events. */ 280 evc1.count = evc2.count = 0; 281 evc2.ev2 = evc1.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc1); 282 evc1.ev2 = evc2.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc2); 283 284 event_active(evc1.ev, EV_TIMEOUT, 1); 285 event_active(evc2.ev, EV_TIMEOUT, 1); 286 287 event_base_dispatch(base); 288 tt_int_op(evc1.count, ==, 101); 289 tt_int_op(evc2.count, ==, 100); 290 291 event_base_assert_ok_(base); 292 end: 293 ; 294 } 295 296 #if 0 297 static void 298 timer_callback_3(evutil_socket_t *fd, short what, void *arg) 299 { 300 (void)fd; 301 (void)what; 302 303 } 304 static void 305 test_fin_many(void *arg) 306 { 307 struct basic_test_data *data = arg; 308 struct event_base *base = data->base; 309 310 struct event *ev1, *ev2; 311 struct event_callback evcb1, evcb2; 312 int ev1_count = 0, ev2_count = 0; 313 int evcb1_count = 0, evcb2_count = 0; 314 struct event_callback *array[4]; 315 316 int n; 317 318 /* First attempt: call finalize_many with no events running */ 319 ev1 = evtimer_new(base, timer_callback, &ev1_count); 320 ev1 = evtimer_new(base, timer_callback, &ev2_count); 321 event_deferred_cb_init_(&evcb1, 0, simple_callback, &evcb1_called); 322 event_deferred_cb_init_(&evcb2, 0, simple_callback, &evcb2_called); 323 array[0] = &ev1->ev_evcallback; 324 array[1] = &ev2->ev_evcallback; 325 array[2] = &evcb1; 326 array[3] = &evcb2; 327 328 329 330 n = event_callback_finalize_many(base, 4, array, 331 callback_finalize_callback_1); 332 333 } 334 #endif 335 336 337 #define TEST(name, flags) \ 338 { #name, test_fin_##name, (flags), &basic_setup, NULL } 339 340 struct testcase_t finalize_testcases[] = { 341 342 TEST(cb_invoked, TT_FORK|TT_NEED_BASE), 343 TEST(free_finalize, TT_FORK), 344 TEST(within_cb, TT_FORK|TT_NEED_BASE), 345 // TEST(many, TT_FORK|TT_NEED_BASE), 346 347 348 END_OF_TESTCASES 349 }; 350 351