nsprpub/pr/tests/stack.c

changeset 0
6474c204b198
     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 +

mercurial