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/. */
5
6 /*
7 ** File: foreign.c
8 ** Description: Testing various functions w/ foreign threads
9 **
10 ** We create a thread and get it to call exactly one runtime function.
11 ** The thread is allowed to be created by some other environment that
12 ** NSPR, but it does not announce itself to the runtime prior to calling
13 ** in.
14 **
15 ** The goal: try to survive.
16 **
17 */
18
19 #include "prcvar.h"
20 #include "prenv.h"
21 #include "prerror.h"
22 #include "prinit.h"
23 #include "prinrval.h"
24 #include "prio.h"
25 #include "prlock.h"
26 #include "prlog.h"
27 #include "prmem.h"
28 #include "prthread.h"
29 #include "prtypes.h"
30 #include "prprf.h"
31 #include "plgetopt.h"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 static enum {
37 thread_nspr, thread_pthread, thread_sproc, thread_win32
38 } thread_provider;
39
40 typedef void (*StartFn)(void*);
41 typedef struct StartObject
42 {
43 StartFn start;
44 void *arg;
45 } StartObject;
46
47 static PRFileDesc *output;
48
49 static int _debug_on = 0;
50
51 #define DEFAULT_THREAD_COUNT 10
52
53 #define DPRINTF(arg) if (_debug_on) PR_fprintf arg
54
55 #if defined(_PR_PTHREADS)
56 #include <pthread.h>
57 #include "md/_pth.h"
pthread_start(void * arg)58 static void *pthread_start(void *arg)
59 {
60 StartFn start = ((StartObject*)arg)->start;
61 void *data = ((StartObject*)arg)->arg;
62 PR_Free(arg);
63 start(data);
64 return NULL;
65 } /* pthread_start */
66 #endif /* defined(_PR_PTHREADS) */
67
68 #if defined(WIN32)
69 #include <windows.h>
70 #include <process.h> /* for _beginthreadex() */
71
windows_start(void * arg)72 static PRUintn __stdcall windows_start(void *arg)
73 {
74 StartObject *so = (StartObject*)arg;
75 StartFn start = so->start;
76 void *data = so->arg;
77 PR_Free(so);
78 start(data);
79 return 0;
80 } /* windows_start */
81 #endif /* defined(WIN32) */
82
NSPRPUB_TESTS_CreateThread(StartFn start,void * arg)83 static PRStatus NSPRPUB_TESTS_CreateThread(StartFn start, void *arg)
84 {
85 PRStatus rv;
86
87 switch (thread_provider)
88 {
89 case thread_nspr:
90 {
91 PRThread *thread = PR_CreateThread(
92 PR_USER_THREAD, start, arg,
93 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
94 PR_UNJOINABLE_THREAD, 0);
95 rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
96 }
97 break;
98 case thread_pthread:
99 #if defined(_PR_PTHREADS)
100 {
101 int rv;
102 pthread_t id;
103 pthread_attr_t tattr;
104 StartObject *start_object;
105 start_object = PR_NEW(StartObject);
106 PR_ASSERT(NULL != start_object);
107 start_object->start = start;
108 start_object->arg = arg;
109
110 rv = _PT_PTHREAD_ATTR_INIT(&tattr);
111 PR_ASSERT(0 == rv);
112
113 rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
114 PR_ASSERT(0 == rv);
115
116 rv = pthread_attr_setstacksize(&tattr, 64 * 1024);
117 PR_ASSERT(0 == rv);
118
119 rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object);
120 (void)_PT_PTHREAD_ATTR_DESTROY(&tattr);
121 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
122 }
123 #else
124 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
125 rv = PR_FAILURE;
126 break;
127 #endif /* defined(_PR_PTHREADS) */
128
129 case thread_sproc:
130 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
131 rv = PR_FAILURE;
132 break;
133 case thread_win32:
134 #if defined(WIN32)
135 {
136 void *th;
137 PRUintn id;
138 StartObject *start_object;
139 start_object = PR_NEW(StartObject);
140 PR_ASSERT(NULL != start_object);
141 start_object->start = start;
142 start_object->arg = arg;
143 th = (void*)_beginthreadex(
144 NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */
145 0U, /* DWORD - initial thread stack size, in bytes */
146 windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */
147 start_object, /* LPVOID - argument for new thread */
148 STACK_SIZE_PARAM_IS_A_RESERVATION, /*DWORD dwCreationFlags - creation flags */
149 &id /* LPDWORD - pointer to returned thread identifier */ );
150
151 rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS;
152 }
153 #else
154 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
155 rv = PR_FAILURE;
156 #endif
157 break;
158 default:
159 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
160 rv = PR_FAILURE;
161 }
162 return rv;
163 } /* NSPRPUB_TESTS_CreateThread */
164
lazyEntry(void * arg)165 static void PR_CALLBACK lazyEntry(void *arg)
166 {
167 PR_ASSERT(NULL == arg);
168 } /* lazyEntry */
169
170
OneShot(void * arg)171 static void OneShot(void *arg)
172 {
173 PRUintn pdkey;
174 PRLock *lock;
175 PRFileDesc *fd;
176 PRDir *dir;
177 PRFileDesc *pair[2];
178 intptr_t test = (intptr_t)arg;
179
180 for (test = 0; test < 12; ++test) {
181
182 switch (test)
183 {
184 case 0:
185 lock = PR_NewLock();
186 DPRINTF((output,"Thread[0x%x] called PR_NewLock\n",
187 PR_GetCurrentThread()));
188 PR_DestroyLock(lock);
189 break;
190
191 case 1:
192 (void)PR_SecondsToInterval(1);
193 DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n",
194 PR_GetCurrentThread()));
195 break;
196
197 case 2: (void)PR_CreateThread(
198 PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL,
199 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
200 DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n",
201 PR_GetCurrentThread()));
202 break;
203
204 case 3:
205 fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666);
206 DPRINTF((output,"Thread[0x%x] called PR_Open\n",
207 PR_GetCurrentThread()));
208 PR_Close(fd);
209 break;
210
211 case 4:
212 fd = PR_NewUDPSocket();
213 DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n",
214 PR_GetCurrentThread()));
215 PR_Close(fd);
216 break;
217
218 case 5:
219 fd = PR_NewTCPSocket();
220 DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n",
221 PR_GetCurrentThread()));
222 PR_Close(fd);
223 break;
224
225 case 6:
226 #define TEMP_DIR "./tmp"
227 PR_MkDir(TEMP_DIR, 0700);
228 dir = PR_OpenDir(TEMP_DIR);
229 DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n",
230 PR_GetCurrentThread()));
231 PR_CloseDir(dir);
232 break;
233
234 case 7:
235 (void)PR_NewThreadPrivateIndex(&pdkey, NULL);
236 DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n",
237 PR_GetCurrentThread()));
238 break;
239
240 case 8:
241 (void)PR_GetEnv("PATH");
242 DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n",
243 PR_GetCurrentThread()));
244 break;
245
246 case 9:
247 (void)PR_NewTCPSocketPair(pair);
248 DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n",
249 PR_GetCurrentThread()));
250 PR_Close(pair[0]);
251 PR_Close(pair[1]);
252 break;
253
254 case 10:
255 PR_SetConcurrency(2);
256 DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n",
257 PR_GetCurrentThread()));
258 break;
259
260 case 11:
261 PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH);
262 DPRINTF((output,"Thread[0x%x] called PR_SetThreadPriority\n",
263 PR_GetCurrentThread()));
264 break;
265
266 default:
267 break;
268 } /* switch() */
269 }
270 } /* OneShot */
271
main(int argc,char ** argv)272 int main(int argc, char **argv)
273 {
274 PRStatus rv;
275 intptr_t thread_cnt = DEFAULT_THREAD_COUNT;
276 PLOptStatus os;
277 PLOptState *opt = PL_CreateOptState(argc, argv, "dt:");
278
279 #if defined(WIN32)
280 thread_provider = thread_win32;
281 #elif defined(_PR_PTHREADS)
282 thread_provider = thread_pthread;
283 #else
284 thread_provider = thread_nspr;
285 #endif
286
287
288 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
289 {
290 if (PL_OPT_BAD == os) {
291 continue;
292 }
293 switch (opt->option)
294 {
295 case 'd': /* debug mode */
296 _debug_on = 1;
297 break;
298 case 't': /* thread count */
299 thread_cnt = atoi(opt->value);
300 break;
301 default:
302 break;
303 }
304 }
305 PL_DestroyOptState(opt);
306
307 PR_SetConcurrency(2);
308
309 output = PR_GetSpecialFD(PR_StandardOutput);
310
311 while (thread_cnt-- > 0)
312 {
313 rv = NSPRPUB_TESTS_CreateThread(OneShot, (void*)thread_cnt);
314 PR_ASSERT(PR_SUCCESS == rv);
315 PR_Sleep(PR_MillisecondsToInterval(5));
316 }
317 PR_Sleep(PR_SecondsToInterval(3));
318 return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1;
319 } /* main */
320
321 /* foreign.c */
322