1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
---|
2 | /* ***** BEGIN LICENSE BLOCK *****
|
---|
3 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
---|
4 | *
|
---|
5 | * The contents of this file are subject to the Mozilla Public License Version
|
---|
6 | * 1.1 (the "License"); you may not use this file except in compliance with
|
---|
7 | * the License. You may obtain a copy of the License at
|
---|
8 | * http://www.mozilla.org/MPL/
|
---|
9 | *
|
---|
10 | * Software distributed under the License is distributed on an "AS IS" basis,
|
---|
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
---|
12 | * for the specific language governing rights and limitations under the
|
---|
13 | * License.
|
---|
14 | *
|
---|
15 | * The Original Code is the Netscape Portable Runtime (NSPR).
|
---|
16 | *
|
---|
17 | * The Initial Developer of the Original Code is
|
---|
18 | * Netscape Communications Corporation.
|
---|
19 | * Portions created by the Initial Developer are Copyright (C) 1998-2000
|
---|
20 | * the Initial Developer. All Rights Reserved.
|
---|
21 | *
|
---|
22 | * Contributor(s):
|
---|
23 | *
|
---|
24 | * Alternatively, the contents of this file may be used under the terms of
|
---|
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
|
---|
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
---|
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
|
---|
28 | * of those above. If you wish to allow use of your version of this file only
|
---|
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
|
---|
30 | * use your version of this file under the terms of the MPL, indicate your
|
---|
31 | * decision by deleting the provisions above and replace them with the notice
|
---|
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
|
---|
33 | * the provisions above, a recipient may use your version of this file under
|
---|
34 | * the terms of any one of the MPL, the GPL or the LGPL.
|
---|
35 | *
|
---|
36 | * ***** END LICENSE BLOCK ***** */
|
---|
37 |
|
---|
38 | /*
|
---|
39 | ** File: foreign.c
|
---|
40 | ** Description: Testing various functions w/ foreign threads
|
---|
41 | **
|
---|
42 | ** We create a thread and get it to call exactly one runtime function.
|
---|
43 | ** The thread is allowed to be created by some other environment that
|
---|
44 | ** NSPR, but it does not announce itself to the runtime prior to calling
|
---|
45 | ** in.
|
---|
46 | **
|
---|
47 | ** The goal: try to survive.
|
---|
48 | **
|
---|
49 | */
|
---|
50 |
|
---|
51 | #include "prcvar.h"
|
---|
52 | #include "prenv.h"
|
---|
53 | #include "prerror.h"
|
---|
54 | #include "prinit.h"
|
---|
55 | #include "prinrval.h"
|
---|
56 | #include "prio.h"
|
---|
57 | #include "prlock.h"
|
---|
58 | #include "prlog.h"
|
---|
59 | #include "prmem.h"
|
---|
60 | #include "prthread.h"
|
---|
61 | #include "prtypes.h"
|
---|
62 | #include "prprf.h"
|
---|
63 | #include "plgetopt.h"
|
---|
64 |
|
---|
65 | #include <stdio.h>
|
---|
66 | #include <stdlib.h>
|
---|
67 |
|
---|
68 | static enum {
|
---|
69 | thread_nspr, thread_pthread, thread_uithread, thread_sproc, thread_win32
|
---|
70 | } thread_provider;
|
---|
71 |
|
---|
72 | typedef void (*StartFn)(void*);
|
---|
73 | typedef struct StartObject
|
---|
74 | {
|
---|
75 | StartFn start;
|
---|
76 | void *arg;
|
---|
77 | } StartObject;
|
---|
78 |
|
---|
79 | static PRFileDesc *output;
|
---|
80 |
|
---|
81 | static int _debug_on = 0;
|
---|
82 |
|
---|
83 | #define DEFAULT_THREAD_COUNT 10
|
---|
84 |
|
---|
85 | #define DPRINTF(arg) if (_debug_on) PR_fprintf arg
|
---|
86 |
|
---|
87 | #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
---|
88 | #include <pthread.h>
|
---|
89 | #include "md/_pth.h"
|
---|
90 | static void *pthread_start(void *arg)
|
---|
91 | {
|
---|
92 | StartFn start = ((StartObject*)arg)->start;
|
---|
93 | void *data = ((StartObject*)arg)->arg;
|
---|
94 | PR_Free(arg);
|
---|
95 | start(data);
|
---|
96 | return NULL;
|
---|
97 | } /* pthread_start */
|
---|
98 | #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
|
---|
99 |
|
---|
100 | #if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
|
---|
101 | #include <thread.h>
|
---|
102 | static void *uithread_start(void *arg)
|
---|
103 | {
|
---|
104 | StartFn start = ((StartObject*)arg)->start;
|
---|
105 | void *data = ((StartObject*)arg)->arg;
|
---|
106 | PR_Free(arg);
|
---|
107 | start(data);
|
---|
108 | return NULL;
|
---|
109 | } /* uithread_start */
|
---|
110 | #endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */
|
---|
111 |
|
---|
112 | #if defined(IRIX) && !defined(_PR_PTHREADS)
|
---|
113 | #include <sys/types.h>
|
---|
114 | #include <sys/prctl.h>
|
---|
115 | static void sproc_start(void *arg, PRSize size)
|
---|
116 | {
|
---|
117 | StartObject *so = (StartObject*)arg;
|
---|
118 | StartFn start = so->start;
|
---|
119 | void *data = so->arg;
|
---|
120 | PR_Free(so);
|
---|
121 | start(data);
|
---|
122 | } /* sproc_start */
|
---|
123 | #endif /* defined(IRIX) && !defined(_PR_PTHREADS) */
|
---|
124 |
|
---|
125 | #if defined(WIN32)
|
---|
126 | #include <process.h> /* for _beginthreadex() */
|
---|
127 |
|
---|
128 | static PRUintn __stdcall windows_start(void *arg)
|
---|
129 | {
|
---|
130 | StartObject *so = (StartObject*)arg;
|
---|
131 | StartFn start = so->start;
|
---|
132 | void *data = so->arg;
|
---|
133 | PR_Free(so);
|
---|
134 | start(data);
|
---|
135 | return 0;
|
---|
136 | } /* windows_start */
|
---|
137 | #endif /* defined(WIN32) */
|
---|
138 |
|
---|
139 | static PRStatus CreateThread(StartFn start, void *arg)
|
---|
140 | {
|
---|
141 | PRStatus rv;
|
---|
142 |
|
---|
143 | switch (thread_provider)
|
---|
144 | {
|
---|
145 | case thread_nspr:
|
---|
146 | {
|
---|
147 | PRThread *thread = PR_CreateThread(
|
---|
148 | PR_USER_THREAD, start, arg,
|
---|
149 | PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
---|
150 | PR_UNJOINABLE_THREAD, 0);
|
---|
151 | rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
|
---|
152 | }
|
---|
153 | break;
|
---|
154 | case thread_pthread:
|
---|
155 | #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
---|
156 | {
|
---|
157 | int rv;
|
---|
158 | pthread_t id;
|
---|
159 | pthread_attr_t tattr;
|
---|
160 | StartObject *start_object;
|
---|
161 | start_object = PR_NEW(StartObject);
|
---|
162 | PR_ASSERT(NULL != start_object);
|
---|
163 | start_object->start = start;
|
---|
164 | start_object->arg = arg;
|
---|
165 |
|
---|
166 | rv = _PT_PTHREAD_ATTR_INIT(&tattr);
|
---|
167 | PR_ASSERT(0 == rv);
|
---|
168 |
|
---|
169 | rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
|
---|
170 | PR_ASSERT(0 == rv);
|
---|
171 |
|
---|
172 | #if !defined(LINUX)
|
---|
173 | rv = pthread_attr_setstacksize(&tattr, 64 * 1024);
|
---|
174 | PR_ASSERT(0 == rv);
|
---|
175 | #endif
|
---|
176 |
|
---|
177 | rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object);
|
---|
178 | (void)_PT_PTHREAD_ATTR_DESTROY(&tattr);
|
---|
179 | return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
|
---|
180 | }
|
---|
181 | #else
|
---|
182 | PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
---|
183 | rv = PR_FAILURE;
|
---|
184 | break;
|
---|
185 | #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
|
---|
186 |
|
---|
187 | case thread_uithread:
|
---|
188 | #if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
|
---|
189 | {
|
---|
190 | int rv;
|
---|
191 | thread_t id;
|
---|
192 | long flags;
|
---|
193 | StartObject *start_object;
|
---|
194 | start_object = PR_NEW(StartObject);
|
---|
195 | PR_ASSERT(NULL != start_object);
|
---|
196 | start_object->start = start;
|
---|
197 | start_object->arg = arg;
|
---|
198 |
|
---|
199 | flags = THR_DETACHED;
|
---|
200 |
|
---|
201 | rv = thr_create(NULL, NULL, uithread_start, start_object, flags, &id);
|
---|
202 | return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
|
---|
203 | }
|
---|
204 | #else
|
---|
205 | PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
---|
206 | rv = PR_FAILURE;
|
---|
207 | break;
|
---|
208 | #endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */
|
---|
209 |
|
---|
210 | case thread_sproc:
|
---|
211 | #if defined(IRIX) && !defined(_PR_PTHREADS)
|
---|
212 | {
|
---|
213 | PRInt32 pid;
|
---|
214 | StartObject *start_object;
|
---|
215 | start_object = PR_NEW(StartObject);
|
---|
216 | PR_ASSERT(NULL != start_object);
|
---|
217 | start_object->start = start;
|
---|
218 | start_object->arg = arg;
|
---|
219 | pid = sprocsp(
|
---|
220 | sproc_start, PR_SALL, start_object, NULL, 64 * 1024);
|
---|
221 | rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE;
|
---|
222 | }
|
---|
223 | #else
|
---|
224 | PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
---|
225 | rv = PR_FAILURE;
|
---|
226 | #endif /* defined(IRIX) && !defined(_PR_PTHREADS) */
|
---|
227 | break;
|
---|
228 | case thread_win32:
|
---|
229 | #if defined(WIN32)
|
---|
230 | {
|
---|
231 | void *th;
|
---|
232 | PRUintn id;
|
---|
233 | StartObject *start_object;
|
---|
234 | start_object = PR_NEW(StartObject);
|
---|
235 | PR_ASSERT(NULL != start_object);
|
---|
236 | start_object->start = start;
|
---|
237 | start_object->arg = arg;
|
---|
238 | th = (void*)_beginthreadex(
|
---|
239 | NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */
|
---|
240 | 0U, /* DWORD - initial thread stack size, in bytes */
|
---|
241 | windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */
|
---|
242 | start_object, /* LPVOID - argument for new thread */
|
---|
243 | 0U, /*DWORD dwCreationFlags - creation flags */
|
---|
244 | &id /* LPDWORD - pointer to returned thread identifier */ );
|
---|
245 |
|
---|
246 | rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS;
|
---|
247 | }
|
---|
248 | #else
|
---|
249 | PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
---|
250 | rv = PR_FAILURE;
|
---|
251 | #endif
|
---|
252 | break;
|
---|
253 | default:
|
---|
254 | PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
---|
255 | rv = PR_FAILURE;
|
---|
256 | }
|
---|
257 | return rv;
|
---|
258 | } /* CreateThread */
|
---|
259 |
|
---|
260 | static void PR_CALLBACK lazyEntry(void *arg)
|
---|
261 | {
|
---|
262 | PR_ASSERT(NULL == arg);
|
---|
263 | } /* lazyEntry */
|
---|
264 |
|
---|
265 |
|
---|
266 | static void OneShot(void *arg)
|
---|
267 | {
|
---|
268 | PRUintn pdkey;
|
---|
269 | PRLock *lock;
|
---|
270 | PRFileDesc *fd;
|
---|
271 | PRDir *dir;
|
---|
272 | PRFileDesc *pair[2];
|
---|
273 | PRIntn test = (PRIntn)arg;
|
---|
274 |
|
---|
275 | for (test = 0; test < 12; ++test) {
|
---|
276 |
|
---|
277 | switch (test)
|
---|
278 | {
|
---|
279 | case 0:
|
---|
280 | lock = PR_NewLock();
|
---|
281 | DPRINTF((output,"Thread[0x%x] called PR_NewLock\n",
|
---|
282 | PR_GetCurrentThread()));
|
---|
283 | PR_DestroyLock(lock);
|
---|
284 | break;
|
---|
285 |
|
---|
286 | case 1:
|
---|
287 | (void)PR_SecondsToInterval(1);
|
---|
288 | DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n",
|
---|
289 | PR_GetCurrentThread()));
|
---|
290 | break;
|
---|
291 |
|
---|
292 | case 2: (void)PR_CreateThread(
|
---|
293 | PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL,
|
---|
294 | PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
|
---|
295 | DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n",
|
---|
296 | PR_GetCurrentThread()));
|
---|
297 | break;
|
---|
298 |
|
---|
299 | case 3:
|
---|
300 | fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666);
|
---|
301 | DPRINTF((output,"Thread[0x%x] called PR_Open\n",
|
---|
302 | PR_GetCurrentThread()));
|
---|
303 | PR_Close(fd);
|
---|
304 | break;
|
---|
305 |
|
---|
306 | case 4:
|
---|
307 | fd = PR_NewUDPSocket();
|
---|
308 | DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n",
|
---|
309 | PR_GetCurrentThread()));
|
---|
310 | PR_Close(fd);
|
---|
311 | break;
|
---|
312 |
|
---|
313 | case 5:
|
---|
314 | fd = PR_NewTCPSocket();
|
---|
315 | DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n",
|
---|
316 | PR_GetCurrentThread()));
|
---|
317 | PR_Close(fd);
|
---|
318 | break;
|
---|
319 |
|
---|
320 | case 6:
|
---|
321 | dir = PR_OpenDir("/tmp/");
|
---|
322 | DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n",
|
---|
323 | PR_GetCurrentThread()));
|
---|
324 | PR_CloseDir(dir);
|
---|
325 | break;
|
---|
326 |
|
---|
327 | case 7:
|
---|
328 | (void)PR_NewThreadPrivateIndex(&pdkey, NULL);
|
---|
329 | DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n",
|
---|
330 | PR_GetCurrentThread()));
|
---|
331 | break;
|
---|
332 |
|
---|
333 | case 8:
|
---|
334 | (void)PR_GetEnv("PATH");
|
---|
335 | DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n",
|
---|
336 | PR_GetCurrentThread()));
|
---|
337 | break;
|
---|
338 |
|
---|
339 | case 9:
|
---|
340 | (void)PR_NewTCPSocketPair(pair);
|
---|
341 | DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n",
|
---|
342 | PR_GetCurrentThread()));
|
---|
343 | PR_Close(pair[0]);
|
---|
344 | PR_Close(pair[1]);
|
---|
345 | break;
|
---|
346 |
|
---|
347 | case 10:
|
---|
348 | PR_SetConcurrency(2);
|
---|
349 | DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n",
|
---|
350 | PR_GetCurrentThread()));
|
---|
351 | break;
|
---|
352 |
|
---|
353 | case 11:
|
---|
354 | PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH);
|
---|
355 | DPRINTF((output,"Thread[0x%x] called PR_SetThreadPriority\n",
|
---|
356 | PR_GetCurrentThread()));
|
---|
357 | break;
|
---|
358 |
|
---|
359 | default:
|
---|
360 | break;
|
---|
361 | } /* switch() */
|
---|
362 | }
|
---|
363 | } /* OneShot */
|
---|
364 |
|
---|
365 | PRIntn main(PRIntn argc, char **argv)
|
---|
366 | {
|
---|
367 | PRStatus rv;
|
---|
368 | PRInt32 thread_cnt = DEFAULT_THREAD_COUNT;
|
---|
369 | PLOptStatus os;
|
---|
370 | PLOptState *opt = PL_CreateOptState(argc, argv, "dt:");
|
---|
371 |
|
---|
372 | #if defined(WIN32)
|
---|
373 | thread_provider = thread_win32;
|
---|
374 | #elif defined(_PR_PTHREADS)
|
---|
375 | thread_provider = thread_pthread;
|
---|
376 | #elif defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
|
---|
377 | thread_provider = thread_uithread;
|
---|
378 | #elif defined(IRIX)
|
---|
379 | thread_provider = thread_sproc;
|
---|
380 | #else
|
---|
381 | thread_provider = thread_nspr;
|
---|
382 | #endif
|
---|
383 |
|
---|
384 |
|
---|
385 | while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
|
---|
386 | {
|
---|
387 | if (PL_OPT_BAD == os) continue;
|
---|
388 | switch (opt->option)
|
---|
389 | {
|
---|
390 | case 'd': /* debug mode */
|
---|
391 | _debug_on = 1;
|
---|
392 | break;
|
---|
393 | case 't': /* thread count */
|
---|
394 | thread_cnt = atoi(opt->value);
|
---|
395 | break;
|
---|
396 | default:
|
---|
397 | break;
|
---|
398 | }
|
---|
399 | }
|
---|
400 | PL_DestroyOptState(opt);
|
---|
401 |
|
---|
402 | PR_SetConcurrency(2);
|
---|
403 |
|
---|
404 | output = PR_GetSpecialFD(PR_StandardOutput);
|
---|
405 |
|
---|
406 | while (thread_cnt-- > 0)
|
---|
407 | {
|
---|
408 | rv = CreateThread(OneShot, (void*)thread_cnt);
|
---|
409 | PR_ASSERT(PR_SUCCESS == rv);
|
---|
410 | PR_Sleep(PR_MillisecondsToInterval(5));
|
---|
411 | }
|
---|
412 | PR_Sleep(PR_SecondsToInterval(3));
|
---|
413 | return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1;
|
---|
414 | } /* main */
|
---|
415 |
|
---|
416 | /* foreign.c */
|
---|