nsprpub/pr/tests/stack.c

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6
michael@0 7 /*
michael@0 8 *
michael@0 9 * Test atomic stack operations
michael@0 10 *
michael@0 11 * Two stacks are created and threads add data items (each containing
michael@0 12 * one of the first n integers) to the first stack, remove data items
michael@0 13 * from the first stack and add them to the second stack. The primordial
michael@0 14 * thread compares the sum of the first n integers to the sum of the
michael@0 15 * integers in the data items in the second stack. The test succeeds if
michael@0 16 * they are equal.
michael@0 17 */
michael@0 18
michael@0 19 #include "nspr.h"
michael@0 20 #include "plgetopt.h"
michael@0 21
michael@0 22 typedef struct _DataRecord {
michael@0 23 PRInt32 data;
michael@0 24 PRStackElem link;
michael@0 25 } DataRecord;
michael@0 26
michael@0 27 #define RECORD_LINK_PTR(lp) ((DataRecord*) ((char*) (lp) - offsetof(DataRecord,link)))
michael@0 28
michael@0 29 #define MAX_THREAD_CNT 100
michael@0 30 #define DEFAULT_THREAD_CNT 4
michael@0 31 #define DEFAULT_DATA_CNT 100
michael@0 32 #define DEFAULT_LOOP_CNT 10000
michael@0 33
michael@0 34 /*
michael@0 35 * sum of the first n numbers using the formula n*(n+1)/2
michael@0 36 */
michael@0 37 #define SUM_OF_NUMBERS(n) ((n & 1) ? (((n + 1)/2) * n) : ((n/2) * (n+1)))
michael@0 38
michael@0 39 typedef struct stack_data {
michael@0 40 PRStack *list1;
michael@0 41 PRStack *list2;
michael@0 42 PRInt32 initial_data_value;
michael@0 43 PRInt32 data_cnt;
michael@0 44 PRInt32 loops;
michael@0 45 } stack_data;
michael@0 46
michael@0 47 static void stackop(void *arg);
michael@0 48
michael@0 49 static int _debug_on;
michael@0 50
michael@0 51 PRFileDesc *output;
michael@0 52 PRFileDesc *errhandle;
michael@0 53
michael@0 54 int main(int argc, char **argv)
michael@0 55 {
michael@0 56 #if !(defined(SYMBIAN) && defined(__WINS__))
michael@0 57 PRInt32 rv, cnt, sum;
michael@0 58 DataRecord *Item;
michael@0 59 PRStack *list1, *list2;
michael@0 60 PRStackElem *node;
michael@0 61 PRStatus rc;
michael@0 62
michael@0 63 PRInt32 thread_cnt = DEFAULT_THREAD_CNT;
michael@0 64 PRInt32 data_cnt = DEFAULT_DATA_CNT;
michael@0 65 PRInt32 loops = DEFAULT_LOOP_CNT;
michael@0 66 PRThread **threads;
michael@0 67 stack_data *thread_args;
michael@0 68
michael@0 69 PLOptStatus os;
michael@0 70 PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:l:");
michael@0 71
michael@0 72 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
michael@0 73 {
michael@0 74 if (PL_OPT_BAD == os) continue;
michael@0 75 switch (opt->option)
michael@0 76 {
michael@0 77 case 'd': /* debug mode */
michael@0 78 _debug_on = 1;
michael@0 79 break;
michael@0 80 case 't': /* thread count */
michael@0 81 thread_cnt = atoi(opt->value);
michael@0 82 break;
michael@0 83 case 'c': /* data count */
michael@0 84 data_cnt = atoi(opt->value);
michael@0 85 break;
michael@0 86 case 'l': /* loop count */
michael@0 87 loops = atoi(opt->value);
michael@0 88 break;
michael@0 89 default:
michael@0 90 break;
michael@0 91 }
michael@0 92 }
michael@0 93 PL_DestroyOptState(opt);
michael@0 94
michael@0 95 PR_SetConcurrency(4);
michael@0 96
michael@0 97 output = PR_GetSpecialFD(PR_StandardOutput);
michael@0 98 errhandle = PR_GetSpecialFD(PR_StandardError);
michael@0 99 list1 = PR_CreateStack("Stack_1");
michael@0 100 if (list1 == NULL) {
michael@0 101 PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n",
michael@0 102 PR_GetError());
michael@0 103 return 1;
michael@0 104 }
michael@0 105
michael@0 106 list2 = PR_CreateStack("Stack_2");
michael@0 107 if (list2 == NULL) {
michael@0 108 PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n",
michael@0 109 PR_GetError());
michael@0 110 return 1;
michael@0 111 }
michael@0 112
michael@0 113
michael@0 114 threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt);
michael@0 115 thread_args = (stack_data *) PR_CALLOC(sizeof(stack_data) * thread_cnt);
michael@0 116
michael@0 117 if (_debug_on)
michael@0 118 PR_fprintf(output,"%s: thread_cnt = %d data_cnt = %d\n", argv[0],
michael@0 119 thread_cnt, data_cnt);
michael@0 120 for(cnt = 0; cnt < thread_cnt; cnt++) {
michael@0 121 PRThreadScope scope;
michael@0 122
michael@0 123 thread_args[cnt].list1 = list1;
michael@0 124 thread_args[cnt].list2 = list2;
michael@0 125 thread_args[cnt].loops = loops;
michael@0 126 thread_args[cnt].data_cnt = data_cnt;
michael@0 127 thread_args[cnt].initial_data_value = 1 + cnt * data_cnt;
michael@0 128
michael@0 129 if (cnt & 1)
michael@0 130 scope = PR_GLOBAL_THREAD;
michael@0 131 else
michael@0 132 scope = PR_LOCAL_THREAD;
michael@0 133
michael@0 134
michael@0 135 threads[cnt] = PR_CreateThread(PR_USER_THREAD,
michael@0 136 stackop, &thread_args[cnt],
michael@0 137 PR_PRIORITY_NORMAL,
michael@0 138 scope,
michael@0 139 PR_JOINABLE_THREAD,
michael@0 140 0);
michael@0 141 if (threads[cnt] == NULL) {
michael@0 142 PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n",
michael@0 143 PR_GetError());
michael@0 144 PR_ProcessExit(2);
michael@0 145 }
michael@0 146 if (_debug_on)
michael@0 147 PR_fprintf(output,"%s: created thread = 0x%x\n", argv[0],
michael@0 148 threads[cnt]);
michael@0 149 }
michael@0 150
michael@0 151 for(cnt = 0; cnt < thread_cnt; cnt++) {
michael@0 152 rc = PR_JoinThread(threads[cnt]);
michael@0 153 PR_ASSERT(rc == PR_SUCCESS);
michael@0 154 }
michael@0 155
michael@0 156 node = PR_StackPop(list1);
michael@0 157 /*
michael@0 158 * list1 should be empty
michael@0 159 */
michael@0 160 if (node != NULL) {
michael@0 161 PR_fprintf(errhandle, "Error - Stack 1 not empty\n");
michael@0 162 PR_ASSERT(node == NULL);
michael@0 163 PR_ProcessExit(4);
michael@0 164 }
michael@0 165
michael@0 166 cnt = data_cnt * thread_cnt;
michael@0 167 sum = 0;
michael@0 168 while (cnt-- > 0) {
michael@0 169 node = PR_StackPop(list2);
michael@0 170 /*
michael@0 171 * There should be at least 'cnt' number of records
michael@0 172 */
michael@0 173 if (node == NULL) {
michael@0 174 PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n");
michael@0 175 PR_ProcessExit(3);
michael@0 176 }
michael@0 177 Item = RECORD_LINK_PTR(node);
michael@0 178 sum += Item->data;
michael@0 179 }
michael@0 180 node = PR_StackPop(list2);
michael@0 181 /*
michael@0 182 * there should be exactly 'cnt' number of records
michael@0 183 */
michael@0 184 if (node != NULL) {
michael@0 185 PR_fprintf(errhandle, "Error - Stack 2 not empty\n");
michael@0 186 PR_ASSERT(node == NULL);
michael@0 187 PR_ProcessExit(4);
michael@0 188 }
michael@0 189 PR_DELETE(threads);
michael@0 190 PR_DELETE(thread_args);
michael@0 191
michael@0 192 PR_DestroyStack(list1);
michael@0 193 PR_DestroyStack(list2);
michael@0 194
michael@0 195 if (sum == SUM_OF_NUMBERS(data_cnt * thread_cnt)) {
michael@0 196 PR_fprintf(output, "%s successful\n", argv[0]);
michael@0 197 PR_fprintf(output, "\t\tsum = 0x%x, expected = 0x%x\n", sum,
michael@0 198 SUM_OF_NUMBERS(thread_cnt * data_cnt));
michael@0 199 return 0;
michael@0 200 } else {
michael@0 201 PR_fprintf(output, "%s failed: sum = 0x%x, expected = 0x%x\n",
michael@0 202 argv[0], sum,
michael@0 203 SUM_OF_NUMBERS(data_cnt * thread_cnt));
michael@0 204 return 2;
michael@0 205 }
michael@0 206 #endif
michael@0 207 }
michael@0 208
michael@0 209 static void stackop(void *thread_arg)
michael@0 210 {
michael@0 211 PRInt32 val, cnt, index, loops;
michael@0 212 DataRecord *Items, *Item;
michael@0 213 PRStack *list1, *list2;
michael@0 214 PRStackElem *node;
michael@0 215 stack_data *arg = (stack_data *) thread_arg;
michael@0 216
michael@0 217 val = arg->initial_data_value;
michael@0 218 cnt = arg->data_cnt;
michael@0 219 loops = arg->loops;
michael@0 220 list1 = arg->list1;
michael@0 221 list2 = arg->list2;
michael@0 222
michael@0 223 /*
michael@0 224 * allocate memory for the data records
michael@0 225 */
michael@0 226 Items = (DataRecord *) PR_CALLOC(sizeof(DataRecord) * cnt);
michael@0 227 PR_ASSERT(Items != NULL);
michael@0 228 index = 0;
michael@0 229
michael@0 230 if (_debug_on)
michael@0 231 PR_fprintf(output,
michael@0 232 "Thread[0x%x] init_val = %d cnt = %d data1 = 0x%x datan = 0x%x\n",
michael@0 233 PR_GetCurrentThread(), val, cnt, &Items[0], &Items[cnt-1]);
michael@0 234
michael@0 235
michael@0 236 /*
michael@0 237 * add the data records to list1
michael@0 238 */
michael@0 239 while (cnt-- > 0) {
michael@0 240 Items[index].data = val++;
michael@0 241 PR_StackPush(list1, &Items[index].link);
michael@0 242 index++;
michael@0 243 }
michael@0 244
michael@0 245 /*
michael@0 246 * pop data records from list1 and add them back to list1
michael@0 247 * generates contention for the stack accesses
michael@0 248 */
michael@0 249 while (loops-- > 0) {
michael@0 250 cnt = arg->data_cnt;
michael@0 251 while (cnt-- > 0) {
michael@0 252 node = PR_StackPop(list1);
michael@0 253 if (node == NULL) {
michael@0 254 PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n");
michael@0 255 PR_ASSERT(node != NULL);
michael@0 256 PR_ProcessExit(3);
michael@0 257 }
michael@0 258 PR_StackPush(list1, node);
michael@0 259 }
michael@0 260 }
michael@0 261 /*
michael@0 262 * remove the data records from list1 and add them to list2
michael@0 263 */
michael@0 264 cnt = arg->data_cnt;
michael@0 265 while (cnt-- > 0) {
michael@0 266 node = PR_StackPop(list1);
michael@0 267 if (node == NULL) {
michael@0 268 PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n");
michael@0 269 PR_ASSERT(node != NULL);
michael@0 270 PR_ProcessExit(3);
michael@0 271 }
michael@0 272 PR_StackPush(list2, node);
michael@0 273 }
michael@0 274 if (_debug_on)
michael@0 275 PR_fprintf(output,
michael@0 276 "Thread[0x%x] init_val = %d cnt = %d exiting\n",
michael@0 277 PR_GetCurrentThread(), val, cnt);
michael@0 278
michael@0 279 }
michael@0 280

mercurial