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