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