1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 * Test atomic stack operations
11 * Two stacks are created and threads add data items (each containing
12 * one of the first n integers) to the first stack, remove data items
13 * from the first stack and add them to the second stack. The primordial
14 * thread compares the sum of the first n integers to the sum of the
15 * integers in the data items in the second stack. The test succeeds if
22 typedef struct _DataRecord
{
27 #define RECORD_LINK_PTR(lp) ((DataRecord*) ((char*) (lp) - offsetof(DataRecord,link)))
29 #define MAX_THREAD_CNT 100
30 #define DEFAULT_THREAD_CNT 4
31 #define DEFAULT_DATA_CNT 100
32 #define DEFAULT_LOOP_CNT 10000
35 * sum of the first n numbers using the formula n*(n+1)/2
37 #define SUM_OF_NUMBERS(n) ((n & 1) ? (((n + 1)/2) * n) : ((n/2) * (n+1)))
39 typedef struct stack_data
{
42 PRInt32 initial_data_value
;
47 static void stackop(void *arg
);
52 PRFileDesc
*errhandle
;
54 int main(int argc
, char **argv
)
56 #if !(defined(SYMBIAN) && defined(__WINS__))
59 PRStack
*list1
, *list2
;
63 PRInt32 thread_cnt
= DEFAULT_THREAD_CNT
;
64 PRInt32 data_cnt
= DEFAULT_DATA_CNT
;
65 PRInt32 loops
= DEFAULT_LOOP_CNT
;
67 stack_data
*thread_args
;
70 PLOptState
*opt
= PL_CreateOptState(argc
, argv
, "dt:c:l:");
72 while (PL_OPT_EOL
!= (os
= PL_GetNextOpt(opt
)))
74 if (PL_OPT_BAD
== os
) continue;
77 case 'd': /* debug mode */
80 case 't': /* thread count */
81 thread_cnt
= atoi(opt
->value
);
83 case 'c': /* data count */
84 data_cnt
= atoi(opt
->value
);
86 case 'l': /* loop count */
87 loops
= atoi(opt
->value
);
93 PL_DestroyOptState(opt
);
97 output
= PR_GetSpecialFD(PR_StandardOutput
);
98 errhandle
= PR_GetSpecialFD(PR_StandardError
);
99 list1
= PR_CreateStack("Stack_1");
101 PR_fprintf(errhandle
, "PR_CreateStack failed - error %d\n",
106 list2
= PR_CreateStack("Stack_2");
108 PR_fprintf(errhandle
, "PR_CreateStack failed - error %d\n",
114 threads
= (PRThread
**) PR_CALLOC(sizeof(PRThread
*) * thread_cnt
);
115 thread_args
= (stack_data
*) PR_CALLOC(sizeof(stack_data
) * thread_cnt
);
118 PR_fprintf(output
,"%s: thread_cnt = %d data_cnt = %d\n", argv
[0],
119 thread_cnt
, data_cnt
);
120 for(cnt
= 0; cnt
< thread_cnt
; cnt
++) {
123 thread_args
[cnt
].list1
= list1
;
124 thread_args
[cnt
].list2
= list2
;
125 thread_args
[cnt
].loops
= loops
;
126 thread_args
[cnt
].data_cnt
= data_cnt
;
127 thread_args
[cnt
].initial_data_value
= 1 + cnt
* data_cnt
;
130 scope
= PR_GLOBAL_THREAD
;
132 scope
= PR_LOCAL_THREAD
;
135 threads
[cnt
] = PR_CreateThread(PR_USER_THREAD
,
136 stackop
, &thread_args
[cnt
],
141 if (threads
[cnt
] == NULL
) {
142 PR_fprintf(errhandle
, "PR_CreateThread failed - error %d\n",
147 PR_fprintf(output
,"%s: created thread = 0x%x\n", argv
[0],
151 for(cnt
= 0; cnt
< thread_cnt
; cnt
++) {
152 rc
= PR_JoinThread(threads
[cnt
]);
153 PR_ASSERT(rc
== PR_SUCCESS
);
156 node
= PR_StackPop(list1
);
158 * list1 should be empty
161 PR_fprintf(errhandle
, "Error - Stack 1 not empty\n");
162 PR_ASSERT(node
== NULL
);
166 cnt
= data_cnt
* thread_cnt
;
169 node
= PR_StackPop(list2
);
171 * There should be at least 'cnt' number of records
174 PR_fprintf(errhandle
, "Error - PR_StackPop returned NULL\n");
177 Item
= RECORD_LINK_PTR(node
);
180 node
= PR_StackPop(list2
);
182 * there should be exactly 'cnt' number of records
185 PR_fprintf(errhandle
, "Error - Stack 2 not empty\n");
186 PR_ASSERT(node
== NULL
);
190 PR_DELETE(thread_args
);
192 PR_DestroyStack(list1
);
193 PR_DestroyStack(list2
);
195 if (sum
== SUM_OF_NUMBERS(data_cnt
* thread_cnt
)) {
196 PR_fprintf(output
, "%s successful\n", argv
[0]);
197 PR_fprintf(output
, "\t\tsum = 0x%x, expected = 0x%x\n", sum
,
198 SUM_OF_NUMBERS(thread_cnt
* data_cnt
));
201 PR_fprintf(output
, "%s failed: sum = 0x%x, expected = 0x%x\n",
203 SUM_OF_NUMBERS(data_cnt
* thread_cnt
));
209 static void stackop(void *thread_arg
)
211 PRInt32 val
, cnt
, index
, loops
;
212 DataRecord
*Items
, *Item
;
213 PRStack
*list1
, *list2
;
215 stack_data
*arg
= (stack_data
*) thread_arg
;
217 val
= arg
->initial_data_value
;
224 * allocate memory for the data records
226 Items
= (DataRecord
*) PR_CALLOC(sizeof(DataRecord
) * cnt
);
227 PR_ASSERT(Items
!= NULL
);
232 "Thread[0x%x] init_val = %d cnt = %d data1 = 0x%x datan = 0x%x\n",
233 PR_GetCurrentThread(), val
, cnt
, &Items
[0], &Items
[cnt
-1]);
237 * add the data records to list1
240 Items
[index
].data
= val
++;
241 PR_StackPush(list1
, &Items
[index
].link
);
246 * pop data records from list1 and add them back to list1
247 * generates contention for the stack accesses
249 while (loops
-- > 0) {
252 node
= PR_StackPop(list1
);
254 PR_fprintf(errhandle
, "Error - PR_StackPop returned NULL\n");
255 PR_ASSERT(node
!= NULL
);
258 PR_StackPush(list1
, node
);
262 * remove the data records from list1 and add them to list2
266 node
= PR_StackPop(list1
);
268 PR_fprintf(errhandle
, "Error - PR_StackPop returned NULL\n");
269 PR_ASSERT(node
!= NULL
);
272 PR_StackPush(list2
, node
);
276 "Thread[0x%x] init_val = %d cnt = %d exiting\n",
277 PR_GetCurrentThread(), val
, cnt
);