regress_finalize.c revision 290001
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 "evconfig-private.h"
29#include "tinytest.h"
30#include "tinytest_macros.h"
31#include <stdlib.h>
32
33#include "event2/event.h"
34#include "event2/util.h"
35#include "event-internal.h"
36#include "defer-internal.h"
37
38#include "regress.h"
39#include "regress_thread.h"
40
41static void
42timer_callback(evutil_socket_t fd, short what, void *arg)
43{
44	int *int_arg = arg;
45	*int_arg += 1;
46	(void)fd;
47	(void)what;
48}
49static void
50simple_callback(struct event_callback *evcb, void *arg)
51{
52	int *int_arg = arg;
53        *int_arg += 1;
54	(void)evcb;
55}
56static void
57event_finalize_callback_1(struct event *ev, void *arg)
58{
59	int *int_arg = arg;
60        *int_arg += 100;
61	(void)ev;
62}
63static void
64callback_finalize_callback_1(struct event_callback *evcb, void *arg)
65{
66	int *int_arg = arg;
67        *int_arg += 100;
68	(void)evcb;
69}
70
71
72static void
73test_fin_cb_invoked(void *arg)
74{
75	struct basic_test_data *data = arg;
76	struct event_base *base = data->base;
77
78	struct event *ev;
79	struct event ev2;
80	struct event_callback evcb;
81	int cb_called = 0;
82	int ev_called = 0;
83
84	const struct timeval ten_sec = {10,0};
85
86	event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called);
87	ev = evtimer_new(base, timer_callback, &ev_called);
88	/* Just finalize them; don't bother adding. */
89	event_free_finalize(0, ev, event_finalize_callback_1);
90	event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1);
91
92	event_base_dispatch(base);
93
94	tt_int_op(cb_called, ==, 100);
95	tt_int_op(ev_called, ==, 100);
96
97	ev_called = cb_called = 0;
98	event_base_assert_ok_(base);
99
100	/* Now try it when they're active. (actually, don't finalize: make
101	 * sure activation can happen! */
102	ev = evtimer_new(base, timer_callback, &ev_called);
103	event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called);
104
105	event_active(ev, EV_TIMEOUT, 1);
106	event_callback_activate_(base, &evcb);
107
108	event_base_dispatch(base);
109	tt_int_op(cb_called, ==, 1);
110	tt_int_op(ev_called, ==, 1);
111
112	ev_called = cb_called = 0;
113	event_base_assert_ok_(base);
114
115	/* Great, it worked. Now activate and finalize and make sure only
116	 * finalizing happens. */
117	event_active(ev, EV_TIMEOUT, 1);
118	event_callback_activate_(base, &evcb);
119	event_free_finalize(0, ev, event_finalize_callback_1);
120	event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1);
121
122	event_base_dispatch(base);
123	tt_int_op(cb_called, ==, 100);
124	tt_int_op(ev_called, ==, 100);
125
126	ev_called = 0;
127
128	event_base_assert_ok_(base);
129
130	/* Okay, now add but don't have it become active, and make sure *that*
131	 * works. */
132	ev = evtimer_new(base, timer_callback, &ev_called);
133	event_add(ev, &ten_sec);
134	event_free_finalize(0, ev, event_finalize_callback_1);
135
136	event_base_dispatch(base);
137	tt_int_op(ev_called, ==, 100);
138
139	ev_called = 0;
140	event_base_assert_ok_(base);
141
142	/* Now try adding and deleting after finalizing. */
143	ev = evtimer_new(base, timer_callback, &ev_called);
144	evtimer_assign(&ev2, base, timer_callback, &ev_called);
145	event_add(ev, &ten_sec);
146	event_free_finalize(0, ev, event_finalize_callback_1);
147	event_finalize(0, &ev2, event_finalize_callback_1);
148
149	event_add(&ev2, &ten_sec);
150	event_del(ev);
151	event_active(&ev2, EV_TIMEOUT, 1);
152
153	event_base_dispatch(base);
154	tt_int_op(ev_called, ==, 200);
155
156	event_base_assert_ok_(base);
157
158end:
159	;
160}
161
162#ifndef EVENT__DISABLE_MM_REPLACEMENT
163static void *
164tfff_malloc(size_t n)
165{
166	return malloc(n);
167}
168static void *tfff_p1=NULL, *tfff_p2=NULL;
169static int tfff_p1_freed=0, tfff_p2_freed=0;
170static void
171tfff_free(void *p)
172{
173	if (! p)
174		return;
175	if (p == tfff_p1)
176		++tfff_p1_freed;
177	if (p == tfff_p2)
178		++tfff_p2_freed;
179	free(p);
180}
181static void *
182tfff_realloc(void *p, size_t sz)
183{
184	return realloc(p,sz);
185}
186#endif
187
188static void
189test_fin_free_finalize(void *arg)
190{
191#ifdef EVENT__DISABLE_MM_REPLACEMENT
192	tinytest_set_test_skipped_();
193#else
194	struct event_base *base = NULL;
195	struct event *ev, *ev2;
196	int ev_called = 0;
197	int ev2_called = 0;
198
199	(void)arg;
200
201	event_set_mem_functions(tfff_malloc, tfff_realloc, tfff_free);
202
203	base = event_base_new();
204	tt_assert(base);
205
206	ev = evtimer_new(base, timer_callback, &ev_called);
207	ev2 = evtimer_new(base, timer_callback, &ev2_called);
208	tfff_p1 = ev;
209	tfff_p2 = ev2;
210	event_free_finalize(0, ev, event_finalize_callback_1);
211	event_finalize(0, ev2, event_finalize_callback_1);
212
213	event_base_dispatch(base);
214
215	tt_int_op(ev_called, ==, 100);
216	tt_int_op(ev2_called, ==, 100);
217
218	event_base_assert_ok_(base);
219	tt_int_op(tfff_p1_freed, ==, 1);
220	tt_int_op(tfff_p2_freed, ==, 0);
221
222	event_free(ev2);
223
224end:
225	if (base)
226		event_base_free(base);
227#endif
228}
229
230/* For test_fin_within_cb */
231struct event_and_count {
232	struct event *ev;
233	struct event *ev2;
234	int count;
235};
236static void
237event_finalize_callback_2(struct event *ev, void *arg)
238{
239	struct event_and_count *evc = arg;
240	evc->count += 100;
241	event_free(ev);
242}
243static void
244timer_callback_2(evutil_socket_t fd, short what, void *arg)
245{
246	struct event_and_count *evc = arg;
247	event_finalize(0, evc->ev, event_finalize_callback_2);
248	event_finalize(0, evc->ev2, event_finalize_callback_2);
249	++ evc->count;
250	(void)fd;
251	(void)what;
252}
253
254static void
255test_fin_within_cb(void *arg)
256{
257	struct basic_test_data *data = arg;
258	struct event_base *base = data->base;
259
260	struct event_and_count evc1, evc2;
261	evc1.count = evc2.count = 0;
262	evc2.ev2 = evc1.ev = evtimer_new(base, timer_callback_2, &evc1);
263	evc1.ev2 = evc2.ev = evtimer_new(base, timer_callback_2, &evc2);
264
265	/* Activate both.  The first one will have its callback run, which
266	 * will finalize both of them, preventing the second one's callback
267	 * from running. */
268	event_active(evc1.ev, EV_TIMEOUT, 1);
269	event_active(evc2.ev, EV_TIMEOUT, 1);
270
271	event_base_dispatch(base);
272	tt_int_op(evc1.count, ==, 101);
273	tt_int_op(evc2.count, ==, 100);
274
275	event_base_assert_ok_(base);
276	/* Now try with EV_PERSIST events. */
277	evc1.count = evc2.count = 0;
278	evc2.ev2 = evc1.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc1);
279	evc1.ev2 = evc2.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc2);
280
281	event_active(evc1.ev, EV_TIMEOUT, 1);
282	event_active(evc2.ev, EV_TIMEOUT, 1);
283
284	event_base_dispatch(base);
285	tt_int_op(evc1.count, ==, 101);
286	tt_int_op(evc2.count, ==, 100);
287
288	event_base_assert_ok_(base);
289end:
290	;
291}
292
293#if 0
294static void
295timer_callback_3(evutil_socket_t *fd, short what, void *arg)
296{
297	(void)fd;
298	(void)what;
299
300}
301static void
302test_fin_many(void *arg)
303{
304	struct basic_test_data *data = arg;
305	struct event_base *base = data->base;
306
307	struct event *ev1, *ev2;
308	struct event_callback evcb1, evcb2;
309	int ev1_count = 0, ev2_count = 0;
310	int evcb1_count = 0, evcb2_count = 0;
311	struct event_callback *array[4];
312
313	int n;
314
315	/* First attempt: call finalize_many with no events running */
316	ev1 = evtimer_new(base, timer_callback, &ev1_count);
317	ev1 = evtimer_new(base, timer_callback, &ev2_count);
318	event_deferred_cb_init_(&evcb1, 0, simple_callback, &evcb1_called);
319	event_deferred_cb_init_(&evcb2, 0, simple_callback, &evcb2_called);
320	array[0] = &ev1->ev_evcallback;
321	array[1] = &ev2->ev_evcallback;
322	array[2] = &evcb1;
323	array[3] = &evcb2;
324
325
326
327	n = event_callback_finalize_many(base, 4, array,
328	    callback_finalize_callback_1);
329
330}
331#endif
332
333
334#define TEST(name, flags)					\
335	{ #name, test_fin_##name, (flags), &basic_setup, NULL }
336
337struct testcase_t finalize_testcases[] = {
338
339	TEST(cb_invoked, TT_FORK|TT_NEED_BASE),
340	TEST(free_finalize, TT_FORK),
341	TEST(within_cb, TT_FORK|TT_NEED_BASE),
342//	TEST(many, TT_FORK|TT_NEED_BASE),
343
344
345	END_OF_TESTCASES
346};
347
348