1 /*	$NetBSD: t_atomic.c,v 1.5 2014/12/10 04:37:53 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2011, 2013  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id: t_atomic.c,v 1.2 2011/01/11 23:47:12 tbox Exp  */
20 
21 #include <config.h>
22 
23 #include <ctype.h>
24 #include <stdlib.h>
25 
26 #include <isc/atomic.h>
27 #include <isc/mem.h>
28 #include <isc/util.h>
29 #include <isc/string.h>
30 #include <isc/print.h>
31 #include <isc/event.h>
32 #include <isc/task.h>
33 
34 #include <tests/t_api.h>
35 
36 char *progname;
37 
38 #define CHECK(x) RUNTIME_CHECK(ISC_R_SUCCESS == (x))
39 
40 isc_mem_t *mctx = NULL;
41 isc_taskmgr_t *task_manager = NULL;
42 
43 #if defined(ISC_PLATFORM_HAVEXADD) || defined(ISC_PLATFORM_HAVEXADDQ)
44 static void
setup(void)45 setup(void) {
46 	/* 1 */ CHECK(isc_mem_create(0, 0, &mctx));
47 	/* 2 */ CHECK(isc_taskmgr_create(mctx, 32, 0, &task_manager));
48 }
49 
50 static void
teardown(void)51 teardown(void) {
52 	/* 2 */ isc_taskmgr_destroy(&task_manager);
53 	/* 1 */ isc_mem_destroy(&mctx);
54 }
55 #endif
56 
57 #define TASKS 32
58 #define ITERATIONS 10000
59 #define COUNTS_PER_ITERATION 1000
60 #define INCREMENT_64 (isc_int64_t)0x0000000010000000
61 #define EXPECTED_COUNT_32 (TASKS * ITERATIONS * COUNTS_PER_ITERATION)
62 #define EXPECTED_COUNT_64 (TASKS * ITERATIONS * COUNTS_PER_ITERATION * INCREMENT_64)
63 
64 typedef struct {
65 	isc_uint32_t iteration;
66 } counter_t;
67 
68 counter_t counters[TASKS];
69 
70 void do_xaddq(isc_task_t *task, isc_event_t *ev);
71 
72 #if defined(ISC_PLATFORM_HAVEXADD)
73 isc_int32_t counter_32;
74 
75 void do_xadd(isc_task_t *task, isc_event_t *ev);
76 
77 void
do_xadd(isc_task_t * task,isc_event_t * ev)78 do_xadd(isc_task_t *task, isc_event_t *ev) {
79 	counter_t *state = (counter_t *)ev->ev_arg;
80 	int i;
81 
82 	for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
83 		isc_atomic_xadd(&counter_32, 1);
84 	}
85 
86 	state->iteration++;
87 	if (state->iteration < ITERATIONS) {
88 		isc_task_send(task, &ev);
89 	} else {
90 		isc_event_free(&ev);
91 	}
92 }
93 
94 static void
test_atomic_xadd()95 test_atomic_xadd() {
96 	int test_result;
97 	isc_task_t *tasks[TASKS];
98 	isc_event_t *event;
99 	int i;
100 
101 	t_assert("test_atomic_xadd", 1, T_REQUIRED, "%s",
102 		 "ensure that isc_atomic_xadd() works.");
103 
104 	setup();
105 
106 	memset(counters, 0, sizeof(counters));
107 	counter_32 = 0;
108 
109 	/*
110 	 * Create our tasks, and allocate an event to get the counters going.
111 	 */
112 	for (i = 0 ; i < TASKS ; i++) {
113 		tasks[i] = NULL;
114 		CHECK(isc_task_create(task_manager, 0, &tasks[i]));
115 		event = isc_event_allocate(mctx, NULL, 1000, do_xadd,
116 					   &counters[i], sizeof(struct isc_event));
117 		isc_task_sendanddetach(&tasks[i], &event);
118 	}
119 
120 	teardown();
121 
122 	test_result = T_PASS;
123 	t_info("32-bit counter %d, expected %d\n", counter_32, EXPECTED_COUNT_32);
124 	if (counter_32 != EXPECTED_COUNT_32)
125 		test_result = T_FAIL;
126 	t_result(test_result);
127 
128 	counter_32 = 0;
129 }
130 #endif
131 
132 #if defined(ISC_PLATFORM_HAVEXADDQ)
133 isc_int64_t counter_64;
134 
135 void do_xaddq(isc_task_t *task, isc_event_t *ev);
136 
137 void
do_xaddq(isc_task_t * task,isc_event_t * ev)138 do_xaddq(isc_task_t *task, isc_event_t *ev) {
139 	counter_t *state = (counter_t *)ev->ev_arg;
140 	int i;
141 
142 	for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
143 		isc_atomic_xaddq(&counter_64, INCREMENT_64);
144 	}
145 
146 	state->iteration++;
147 	if (state->iteration < ITERATIONS) {
148 		isc_task_send(task, &ev);
149 	} else {
150 		isc_event_free(&ev);
151 	}
152 }
153 
154 static void
test_atomic_xaddq()155 test_atomic_xaddq() {
156 	int test_result;
157 	isc_task_t *tasks[TASKS];
158 	isc_event_t *event;
159 	int i;
160 
161 	t_assert("test_atomic_xaddq", 1, T_REQUIRED, "%s",
162 		 "ensure that isc_atomic_xaddq() works.");
163 
164 	setup();
165 
166 	memset(counters, 0, sizeof(counters));
167 	counter_64 = 0;
168 
169 	/*
170 	 * Create our tasks, and allocate an event to get the counters going.
171 	 */
172 	for (i = 0 ; i < TASKS ; i++) {
173 		tasks[i] = NULL;
174 		CHECK(isc_task_create(task_manager, 0, &tasks[i]));
175 		event = isc_event_allocate(mctx, NULL, 1000, do_xaddq,
176 					   &counters[i], sizeof(struct isc_event));
177 		isc_task_sendanddetach(&tasks[i], &event);
178 	}
179 
180 	teardown();
181 
182 	test_result = T_PASS;
183 	t_info("64-bit counter %"ISC_PRINT_QUADFORMAT"d, expected %"ISC_PRINT_QUADFORMAT"d\n",
184 	       counter_64, EXPECTED_COUNT_64);
185 	if (counter_64 != EXPECTED_COUNT_64)
186 		test_result = T_FAIL;
187 	t_result(test_result);
188 
189 	counter_64 = 0;
190 }
191 #endif
192 
193 
194 testspec_t T_testlist[] = {
195 #if defined(ISC_PLATFORM_HAVEXADD)
196 	{ (PFV) test_atomic_xadd,	"test_atomic_xadd"		},
197 #endif
198 #if defined(ISC_PLATFORM_HAVEXADDQ)
199 	{ (PFV) test_atomic_xaddq,	"test_atomic_xaddq"		},
200 #endif
201 	{ (PFV) 0,			NULL }
202 };
203 
204 #ifdef WIN32
205 int
main(int argc,char ** argv)206 main(int argc, char **argv) {
207 	t_settests(T_testlist);
208 	return (t_main(argc, argv));
209 }
210 #endif
211