1 // Copyright 2015 The Emscripten Authors.  All rights reserved.
2 // Emscripten is available under two separate licenses, the MIT license and the
3 // University of Illinois/NCSA Open Source License.  Both these licenses can be
4 // found in the LICENSE file.
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <pthread.h>
9 #include <emscripten.h>
10 #include <emscripten/threading.h>
11 #include <errno.h>
12 #include <assert.h>
13 #include <inttypes.h>
14 
15 #define NUM_THREADS 8
16 #define NUM_KEYS 16
17 #define NUM_ITERS 100
18 
19 pthread_key_t keys[NUM_KEYS];
ThreadMain(void * arg)20 void *ThreadMain(void *arg)
21 {
22 	uintptr_t local_keys[NUM_KEYS];
23 	for(int iter = 0; iter < NUM_ITERS; ++iter)
24 	{
25 		for(int i = 0; i < NUM_KEYS; ++i)
26 		{
27 			local_keys[i] = (uintptr_t)pthread_getspecific(keys[i]);
28 //			EM_ASM(err('Thread ' + $0 + ': Read value ' + $1 + ' from TLS for key at index ' + $2), pthread_self(), (int)local_keys[i], i);
29 		}
30 
31 		for(int i = 0; i < NUM_KEYS; ++i)
32 			++local_keys[i];
33 
34 		for(int i = 0; i < NUM_KEYS; ++i)
35 			pthread_setspecific(keys[i], (void*)local_keys[i]);
36 	}
37 
38 	for(int i = 0; i < NUM_KEYS; ++i)
39 	{
40 		local_keys[i] = (uintptr_t)pthread_getspecific(keys[i]);
41 //		EM_ASM(err('Thread ' + $0 + ' final verify: Read value ' + $1 + ' from TLS for key at index ' + $2), pthread_self(), (int)local_keys[i], i);
42 		if (local_keys[i] != NUM_ITERS)
43 			pthread_exit((void*)1);
44 	}
45 	pthread_exit(0);
46 }
47 
48 pthread_t thread[NUM_THREADS];
49 
50 int numThreadsToCreate = 32;
51 
CreateThread(int i)52 void CreateThread(int i)
53 {
54 	pthread_attr_t attr;
55 	pthread_attr_init(&attr);
56 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
57 	int rc = pthread_create(&thread[i], &attr, ThreadMain, (void*)i);
58 	if (emscripten_has_threading_support()) assert(rc == 0);
59 	else assert(rc == EAGAIN);
60 	pthread_attr_destroy(&attr);
61 }
62 
main()63 int main()
64 {
65 	for(int i = 0; i < NUM_KEYS; ++i)
66 		pthread_key_create(&keys[i], NULL);
67 
68 	// Create initial threads.
69 	for(int i = 0; i < NUM_THREADS; ++i)
70 		CreateThread(i);
71 
72 	// Join all threads and create more.
73 	if (emscripten_has_threading_support())
74 	{
75 		for(int i = 0; i < NUM_THREADS; ++i)
76 		{
77 			if (thread[i])
78 			{
79 				int status;
80 				int rc = pthread_join(thread[i], (void**)&status);
81 				assert(rc == 0);
82 				EM_ASM(err('Main: Joined thread idx ' + $0 + ' with status ' + $1), i, (int)status);
83 				assert(status == 0);
84 				thread[i] = 0;
85 				if (numThreadsToCreate > 0)
86 				{
87 					--numThreadsToCreate;
88 					CreateThread(i);
89 				}
90 			}
91 		}
92 	}
93 #ifdef REPORT_RESULT
94 	REPORT_RESULT(0);
95 #endif
96 
97 	for(int i = 0; i < NUM_KEYS; ++i)
98 		pthread_key_delete(keys[i]);
99 }
100