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 <unistd.h>
12
13 #define NUM_THREADS 8
14
15 int numThreadsToCreateTotal = 50;
16
17 pthread_t thread[NUM_THREADS] = {};
18
19 volatile int counter = 0; // Shared data
20 pthread_mutex_t lock;
21
sleep(int msecs)22 void sleep(int msecs)
23 {
24 // Test two different variants of sleeping to verify
25 // against bug https://bugzilla.mozilla.org/show_bug.cgi?id=1131757
26 #ifdef SPINLOCK_TEST
27 double t0 = emscripten_get_now();
28 double t1 = t0 + (double)msecs;
29 while(emscripten_get_now() < t1)
30 ;
31 #else
32 usleep(msecs*1000);
33 #endif
34 }
ThreadMain(void * arg)35 void *ThreadMain(void *arg)
36 {
37 pthread_mutex_lock(&lock);
38 int c = counter;
39 sleep(100); // Create contention on the lock.
40 ++c;
41 counter = c;
42 pthread_mutex_unlock(&lock);
43 pthread_exit(0);
44 }
45
CreateThread(int i,int n)46 void CreateThread(int i, int n)
47 {
48 pthread_attr_t attr;
49 pthread_attr_init(&attr);
50 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
51 pthread_attr_setstacksize(&attr, 4*1024);
52 int rc = pthread_create(&thread[i], &attr, ThreadMain, 0);
53 if (rc != 0 || thread[i] == 0)
54 printf("Failed to create thread!\n");
55 pthread_attr_destroy(&attr);
56 }
57
58 int threadNum = 0;
WaitToJoin(double time,void * userData)59 EM_BOOL WaitToJoin(double time, void *userData)
60 {
61 int threadsRunning = 0;
62 // Join all threads.
63 for(int i = 0; i < NUM_THREADS; ++i)
64 {
65 if (thread[i])
66 {
67 void *status;
68 int rc = pthread_join(thread[i], &status);
69 if (rc == 0)
70 {
71 thread[i] = 0;
72 if (threadNum < numThreadsToCreateTotal)
73 {
74 CreateThread(i, threadNum++);
75 ++threadsRunning;
76 }
77 }
78 else
79 ++threadsRunning;
80 }
81 }
82 if (!threadsRunning)
83 {
84 if (counter == numThreadsToCreateTotal)
85 EM_ASM(console.log('All threads finished. Counter = ' + $0 + ' as expected.'), counter);
86 else
87 EM_ASM(console.error('All threads finished, but counter = ' + $0 + ' != ' + $1 + '!'), counter, numThreadsToCreateTotal);
88 #ifdef REPORT_RESULT
89 REPORT_RESULT(counter);
90 #endif
91 return EM_FALSE;
92 }
93 return EM_TRUE;
94 }
95
main()96 int main()
97 {
98 pthread_mutexattr_t attr;
99 pthread_mutexattr_init(&attr);
100 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
101 pthread_mutex_init(&lock, &attr);
102
103 pthread_mutex_lock(&lock);
104 pthread_mutex_unlock(&lock);
105
106 if (emscripten_has_threading_support()) {
107 // Create new threads in parallel.
108 for(int i = 0; i < NUM_THREADS; ++i)
109 CreateThread(i, threadNum++);
110
111 emscripten_set_timeout_loop(WaitToJoin, 100, 0);
112 } else {
113 #ifdef REPORT_RESULT
114 REPORT_RESULT(50);
115 #endif
116 }
117 }
118