1 : /* Copyright (c) 2011 The Native Client Authors. All rights reserved.
2 : * Use of this source code is governed by a BSD-style license that can be
3 : * found in the LICENSE file.
4 : */
5 :
6 : #include <stdio.h>
7 : #include "native_client/src/include/atomic_ops.h"
8 : #include "native_client/src/shared/platform/nacl_threads.h"
9 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
10 : #include "native_client/src/shared/platform/nacl_sync.h"
11 :
12 : #define THREAD_STACK_SIZE (128*1024)
13 :
14 : int32_t gIncrementsPerThread = 1000;
15 : int32_t gNumThreads;
16 :
17 : struct NaClMutex gMutex;
18 :
19 :
20 : /* For atomic counter test */
21 : Atomic32 gCounter = 0;
22 :
23 56 : static void IncrementTest() {
24 : /* Increment the counter, gIncrementsPerThread times,
25 : * with the values 1...gIncrementsPerThread
26 : */
27 : Atomic32 i;
28 24249 : for (i=1; i <= gIncrementsPerThread; i++) {
29 24224 : AtomicIncrement(&gCounter, i);
30 : }
31 25 : }
32 :
33 0 : static void DecrementTest() {
34 : /* Decrement the counter gIncrementsPerThread times,
35 : * with the values 1...gIncrementsPerThread-1
36 : */
37 : Atomic32 i;
38 23896 : for (i=1; i < gIncrementsPerThread; i++) {
39 23871 : AtomicIncrement(&gCounter, -i);
40 : }
41 25 : }
42 :
43 : /* Atomic exchange test
44 : * Each thread exchanges gExchange for its tid.
45 : * It takes the returned value and adds it to gExchangeSum.
46 : * When finished, gExchangeSum + gExchange will contain
47 : * 1 + ... + gNumThreads
48 : */
49 : Atomic32 gExchange = 0;
50 : Atomic32 gExchangeSum = 0;
51 :
52 25 : static void ExchangeTest(int32_t tid) {
53 : Atomic32 i;
54 25 : i = AtomicExchange(&gExchange, tid);
55 25 : if (i == tid) {
56 0 : fprintf(stderr,
57 : "Error: AtomicExchange returned the new value instead of old.\n");
58 0 : exit(EXIT_FAILURE);
59 : }
60 25 : AtomicIncrement(&gExchangeSum, i);
61 25 : }
62 :
63 : /* Atomic compare and swap test
64 : Each thread spins until gSwap == tid, and
65 : then exchanges it for tid + 1
66 : */
67 : Atomic32 gSwap = 1;
68 1624898 : static void CompareAndSwapTest(int32_t tid) {
69 1624898 : while (CompareAndSwap(&gSwap, tid, tid+1) != tid);
70 25 : }
71 :
72 25 : void WINAPI ThreadMain(void *state) {
73 25 : int32_t tid = (int32_t) (intptr_t) state;
74 :
75 : /* Wait for the signal to begin */
76 25 : NaClXMutexLock(&gMutex);
77 25 : NaClXMutexUnlock(&gMutex);
78 :
79 : /* Swap the order to shake things up a bit */
80 25 : if (tid % 2 == 0) {
81 12 : IncrementTest();
82 12 : DecrementTest();
83 : } else {
84 13 : DecrementTest();
85 13 : IncrementTest();
86 : }
87 :
88 25 : ExchangeTest(tid);
89 :
90 25 : CompareAndSwapTest(tid);
91 25 : }
92 :
93 1 : int main(int argc, const char *argv[]) {
94 : struct NaClThread *threads;
95 : int rv;
96 : int32_t tid;
97 : int32_t tmp;
98 :
99 1 : if (argc != 2) {
100 0 : fprintf(stderr, "Usage: %s <NumThreads>\n", argv[0]);
101 0 : exit(EXIT_FAILURE);
102 : }
103 :
104 1 : gNumThreads = strtol(argv[1], NULL, 10);
105 :
106 1 : threads = (struct NaClThread*)malloc(gNumThreads*sizeof(struct NaClThread));
107 1 : if (threads == NULL) {
108 0 : fprintf(stderr, "malloc returned NULL\n");
109 0 : exit(EXIT_FAILURE);
110 : }
111 :
112 1 : if (!NaClMutexCtor(&gMutex)) {
113 0 : fprintf(stderr, "NaClMutexCtor failed\n");
114 0 : exit(EXIT_FAILURE);
115 : }
116 :
117 1 : NaClXMutexLock(&gMutex);
118 :
119 26 : for (tid = 1; tid <= gNumThreads; ++tid) {
120 25 : fprintf(stderr, "Creating thread %d\n", (int)tid);
121 :
122 25 : rv = NaClThreadCreateJoinable(&threads[tid-1],
123 : ThreadMain,
124 : (void*) (intptr_t) tid,
125 : THREAD_STACK_SIZE);
126 25 : if (!rv) {
127 0 : fprintf(stderr, "NaClThreadCtor failed\n");
128 0 : exit(EXIT_FAILURE);
129 : }
130 : }
131 :
132 1 : NaClXMutexUnlock(&gMutex);
133 :
134 26 : for (tid = 1; tid <= gNumThreads; ++tid) {
135 25 : NaClThreadJoin(&threads[tid-1]);
136 : }
137 :
138 : /* Check the results */
139 1 : tmp = gIncrementsPerThread * gNumThreads;
140 1 : if (gCounter != tmp) {
141 0 : fprintf(stderr, "ERROR: gCounter is wrong. Expected %d, got %d\n",
142 : (int)tmp, (int)gCounter);
143 0 : exit(EXIT_FAILURE);
144 : }
145 :
146 1 : tmp = gNumThreads*(gNumThreads+1)/2;
147 1 : if (gExchange + gExchangeSum != tmp) {
148 0 : fprintf(stderr,
149 : "ERROR: gExchange+gExchangeSum is wrong. Expected %d, got %d\n",
150 : (int)tmp, (int)(gExchange + gExchangeSum));
151 0 : exit(EXIT_FAILURE);
152 : }
153 :
154 1 : if (gSwap != gNumThreads+1) {
155 0 : fprintf(stderr, "ERROR: gSwap is wrong. Expected %d, got %d\n",
156 : (int)(gNumThreads+1), (int)gSwap);
157 0 : exit(EXIT_FAILURE);
158 : }
159 :
160 1 : fprintf(stderr, "PASSED\n");
161 1 : NaClMutexDtor(&gMutex);
162 1 : free(threads);
163 1 : return 0;
164 : }
|