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 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 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 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 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 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 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 206 main(int argc, char **argv) { 207 t_settests(T_testlist); 208 return (t_main(argc, argv)); 209 } 210 #endif 211