1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/stack.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,280 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +/* 1.11 + * 1.12 + * Test atomic stack operations 1.13 + * 1.14 + * Two stacks are created and threads add data items (each containing 1.15 + * one of the first n integers) to the first stack, remove data items 1.16 + * from the first stack and add them to the second stack. The primordial 1.17 + * thread compares the sum of the first n integers to the sum of the 1.18 + * integers in the data items in the second stack. The test succeeds if 1.19 + * they are equal. 1.20 + */ 1.21 + 1.22 +#include "nspr.h" 1.23 +#include "plgetopt.h" 1.24 + 1.25 +typedef struct _DataRecord { 1.26 + PRInt32 data; 1.27 + PRStackElem link; 1.28 +} DataRecord; 1.29 + 1.30 +#define RECORD_LINK_PTR(lp) ((DataRecord*) ((char*) (lp) - offsetof(DataRecord,link))) 1.31 + 1.32 +#define MAX_THREAD_CNT 100 1.33 +#define DEFAULT_THREAD_CNT 4 1.34 +#define DEFAULT_DATA_CNT 100 1.35 +#define DEFAULT_LOOP_CNT 10000 1.36 + 1.37 +/* 1.38 + * sum of the first n numbers using the formula n*(n+1)/2 1.39 + */ 1.40 +#define SUM_OF_NUMBERS(n) ((n & 1) ? (((n + 1)/2) * n) : ((n/2) * (n+1))) 1.41 + 1.42 +typedef struct stack_data { 1.43 + PRStack *list1; 1.44 + PRStack *list2; 1.45 + PRInt32 initial_data_value; 1.46 + PRInt32 data_cnt; 1.47 + PRInt32 loops; 1.48 +} stack_data; 1.49 + 1.50 +static void stackop(void *arg); 1.51 + 1.52 +static int _debug_on; 1.53 + 1.54 +PRFileDesc *output; 1.55 +PRFileDesc *errhandle; 1.56 + 1.57 +int main(int argc, char **argv) 1.58 +{ 1.59 +#if !(defined(SYMBIAN) && defined(__WINS__)) 1.60 + PRInt32 rv, cnt, sum; 1.61 + DataRecord *Item; 1.62 + PRStack *list1, *list2; 1.63 + PRStackElem *node; 1.64 + PRStatus rc; 1.65 + 1.66 + PRInt32 thread_cnt = DEFAULT_THREAD_CNT; 1.67 + PRInt32 data_cnt = DEFAULT_DATA_CNT; 1.68 + PRInt32 loops = DEFAULT_LOOP_CNT; 1.69 + PRThread **threads; 1.70 + stack_data *thread_args; 1.71 + 1.72 + PLOptStatus os; 1.73 + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:l:"); 1.74 + 1.75 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.76 + { 1.77 + if (PL_OPT_BAD == os) continue; 1.78 + switch (opt->option) 1.79 + { 1.80 + case 'd': /* debug mode */ 1.81 + _debug_on = 1; 1.82 + break; 1.83 + case 't': /* thread count */ 1.84 + thread_cnt = atoi(opt->value); 1.85 + break; 1.86 + case 'c': /* data count */ 1.87 + data_cnt = atoi(opt->value); 1.88 + break; 1.89 + case 'l': /* loop count */ 1.90 + loops = atoi(opt->value); 1.91 + break; 1.92 + default: 1.93 + break; 1.94 + } 1.95 + } 1.96 + PL_DestroyOptState(opt); 1.97 + 1.98 + PR_SetConcurrency(4); 1.99 + 1.100 + output = PR_GetSpecialFD(PR_StandardOutput); 1.101 + errhandle = PR_GetSpecialFD(PR_StandardError); 1.102 + list1 = PR_CreateStack("Stack_1"); 1.103 + if (list1 == NULL) { 1.104 + PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n", 1.105 + PR_GetError()); 1.106 + return 1; 1.107 + } 1.108 + 1.109 + list2 = PR_CreateStack("Stack_2"); 1.110 + if (list2 == NULL) { 1.111 + PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n", 1.112 + PR_GetError()); 1.113 + return 1; 1.114 + } 1.115 + 1.116 + 1.117 + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); 1.118 + thread_args = (stack_data *) PR_CALLOC(sizeof(stack_data) * thread_cnt); 1.119 + 1.120 + if (_debug_on) 1.121 + PR_fprintf(output,"%s: thread_cnt = %d data_cnt = %d\n", argv[0], 1.122 + thread_cnt, data_cnt); 1.123 + for(cnt = 0; cnt < thread_cnt; cnt++) { 1.124 + PRThreadScope scope; 1.125 + 1.126 + thread_args[cnt].list1 = list1; 1.127 + thread_args[cnt].list2 = list2; 1.128 + thread_args[cnt].loops = loops; 1.129 + thread_args[cnt].data_cnt = data_cnt; 1.130 + thread_args[cnt].initial_data_value = 1 + cnt * data_cnt; 1.131 + 1.132 + if (cnt & 1) 1.133 + scope = PR_GLOBAL_THREAD; 1.134 + else 1.135 + scope = PR_LOCAL_THREAD; 1.136 + 1.137 + 1.138 + threads[cnt] = PR_CreateThread(PR_USER_THREAD, 1.139 + stackop, &thread_args[cnt], 1.140 + PR_PRIORITY_NORMAL, 1.141 + scope, 1.142 + PR_JOINABLE_THREAD, 1.143 + 0); 1.144 + if (threads[cnt] == NULL) { 1.145 + PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", 1.146 + PR_GetError()); 1.147 + PR_ProcessExit(2); 1.148 + } 1.149 + if (_debug_on) 1.150 + PR_fprintf(output,"%s: created thread = 0x%x\n", argv[0], 1.151 + threads[cnt]); 1.152 + } 1.153 + 1.154 + for(cnt = 0; cnt < thread_cnt; cnt++) { 1.155 + rc = PR_JoinThread(threads[cnt]); 1.156 + PR_ASSERT(rc == PR_SUCCESS); 1.157 + } 1.158 + 1.159 + node = PR_StackPop(list1); 1.160 + /* 1.161 + * list1 should be empty 1.162 + */ 1.163 + if (node != NULL) { 1.164 + PR_fprintf(errhandle, "Error - Stack 1 not empty\n"); 1.165 + PR_ASSERT(node == NULL); 1.166 + PR_ProcessExit(4); 1.167 + } 1.168 + 1.169 + cnt = data_cnt * thread_cnt; 1.170 + sum = 0; 1.171 + while (cnt-- > 0) { 1.172 + node = PR_StackPop(list2); 1.173 + /* 1.174 + * There should be at least 'cnt' number of records 1.175 + */ 1.176 + if (node == NULL) { 1.177 + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); 1.178 + PR_ProcessExit(3); 1.179 + } 1.180 + Item = RECORD_LINK_PTR(node); 1.181 + sum += Item->data; 1.182 + } 1.183 + node = PR_StackPop(list2); 1.184 + /* 1.185 + * there should be exactly 'cnt' number of records 1.186 + */ 1.187 + if (node != NULL) { 1.188 + PR_fprintf(errhandle, "Error - Stack 2 not empty\n"); 1.189 + PR_ASSERT(node == NULL); 1.190 + PR_ProcessExit(4); 1.191 + } 1.192 + PR_DELETE(threads); 1.193 + PR_DELETE(thread_args); 1.194 + 1.195 + PR_DestroyStack(list1); 1.196 + PR_DestroyStack(list2); 1.197 + 1.198 + if (sum == SUM_OF_NUMBERS(data_cnt * thread_cnt)) { 1.199 + PR_fprintf(output, "%s successful\n", argv[0]); 1.200 + PR_fprintf(output, "\t\tsum = 0x%x, expected = 0x%x\n", sum, 1.201 + SUM_OF_NUMBERS(thread_cnt * data_cnt)); 1.202 + return 0; 1.203 + } else { 1.204 + PR_fprintf(output, "%s failed: sum = 0x%x, expected = 0x%x\n", 1.205 + argv[0], sum, 1.206 + SUM_OF_NUMBERS(data_cnt * thread_cnt)); 1.207 + return 2; 1.208 + } 1.209 +#endif 1.210 +} 1.211 + 1.212 +static void stackop(void *thread_arg) 1.213 +{ 1.214 + PRInt32 val, cnt, index, loops; 1.215 + DataRecord *Items, *Item; 1.216 + PRStack *list1, *list2; 1.217 + PRStackElem *node; 1.218 + stack_data *arg = (stack_data *) thread_arg; 1.219 + 1.220 + val = arg->initial_data_value; 1.221 + cnt = arg->data_cnt; 1.222 + loops = arg->loops; 1.223 + list1 = arg->list1; 1.224 + list2 = arg->list2; 1.225 + 1.226 + /* 1.227 + * allocate memory for the data records 1.228 + */ 1.229 + Items = (DataRecord *) PR_CALLOC(sizeof(DataRecord) * cnt); 1.230 + PR_ASSERT(Items != NULL); 1.231 + index = 0; 1.232 + 1.233 + if (_debug_on) 1.234 + PR_fprintf(output, 1.235 + "Thread[0x%x] init_val = %d cnt = %d data1 = 0x%x datan = 0x%x\n", 1.236 + PR_GetCurrentThread(), val, cnt, &Items[0], &Items[cnt-1]); 1.237 + 1.238 + 1.239 + /* 1.240 + * add the data records to list1 1.241 + */ 1.242 + while (cnt-- > 0) { 1.243 + Items[index].data = val++; 1.244 + PR_StackPush(list1, &Items[index].link); 1.245 + index++; 1.246 + } 1.247 + 1.248 + /* 1.249 + * pop data records from list1 and add them back to list1 1.250 + * generates contention for the stack accesses 1.251 + */ 1.252 + while (loops-- > 0) { 1.253 + cnt = arg->data_cnt; 1.254 + while (cnt-- > 0) { 1.255 + node = PR_StackPop(list1); 1.256 + if (node == NULL) { 1.257 + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); 1.258 + PR_ASSERT(node != NULL); 1.259 + PR_ProcessExit(3); 1.260 + } 1.261 + PR_StackPush(list1, node); 1.262 + } 1.263 + } 1.264 + /* 1.265 + * remove the data records from list1 and add them to list2 1.266 + */ 1.267 + cnt = arg->data_cnt; 1.268 + while (cnt-- > 0) { 1.269 + node = PR_StackPop(list1); 1.270 + if (node == NULL) { 1.271 + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); 1.272 + PR_ASSERT(node != NULL); 1.273 + PR_ProcessExit(3); 1.274 + } 1.275 + PR_StackPush(list2, node); 1.276 + } 1.277 + if (_debug_on) 1.278 + PR_fprintf(output, 1.279 + "Thread[0x%x] init_val = %d cnt = %d exiting\n", 1.280 + PR_GetCurrentThread(), val, cnt); 1.281 + 1.282 +} 1.283 +