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
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/
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
15 * The Original Code is the Netscape Portable Runtime (NSPR).
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.
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.
36 * ***** END LICENSE BLOCK ***** */
40 ** Description: Testing various functions w/ foreign threads
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
47 ** The goal: try to survive.
69 thread_nspr
, thread_pthread
, thread_sproc
, thread_win32
72 typedef void (*StartFn
)(void*);
73 typedef struct StartObject
79 static PRFileDesc
*output
;
81 static int _debug_on
= 0;
83 #define DEFAULT_THREAD_COUNT 10
85 #define DPRINTF(arg) if (_debug_on) PR_fprintf arg
87 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
90 static void *pthread_start(void *arg
)
92 StartFn start
= ((StartObject
*)arg
)->start
;
93 void *data
= ((StartObject
*)arg
)->arg
;
98 #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
100 #if defined(IRIX) && !defined(_PR_PTHREADS)
101 #include <sys/types.h>
102 #include <sys/prctl.h>
103 static void sproc_start(void *arg
, PRSize size
)
105 StartObject
*so
= (StartObject
*)arg
;
106 StartFn start
= so
->start
;
107 void *data
= so
->arg
;
111 #endif /* defined(IRIX) && !defined(_PR_PTHREADS) */
114 #include <process.h> /* for _beginthreadex() */
116 static PRUintn __stdcall
windows_start(void *arg
)
118 StartObject
*so
= (StartObject
*)arg
;
119 StartFn start
= so
->start
;
120 void *data
= so
->arg
;
124 } /* windows_start */
125 #endif /* defined(WIN32) */
127 static PRStatus
CreateThread(StartFn start
, void *arg
)
131 switch (thread_provider
)
135 PRThread
*thread
= PR_CreateThread(
136 PR_USER_THREAD
, start
, arg
,
137 PR_PRIORITY_NORMAL
, PR_GLOBAL_THREAD
,
138 PR_UNJOINABLE_THREAD
, 0);
139 rv
= (NULL
== thread
) ? PR_FAILURE
: PR_SUCCESS
;
143 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
147 pthread_attr_t tattr
;
148 StartObject
*start_object
;
149 start_object
= PR_NEW(StartObject
);
150 PR_ASSERT(NULL
!= start_object
);
151 start_object
->start
= start
;
152 start_object
->arg
= arg
;
154 rv
= _PT_PTHREAD_ATTR_INIT(&tattr
);
157 rv
= pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
160 rv
= pthread_attr_setstacksize(&tattr
, 64 * 1024);
163 rv
= _PT_PTHREAD_CREATE(&id
, tattr
, pthread_start
, start_object
);
164 (void)_PT_PTHREAD_ATTR_DESTROY(&tattr
);
165 return (0 == rv
) ? PR_SUCCESS
: PR_FAILURE
;
168 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
171 #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
174 #if defined(IRIX) && !defined(_PR_PTHREADS)
177 StartObject
*start_object
;
178 start_object
= PR_NEW(StartObject
);
179 PR_ASSERT(NULL
!= start_object
);
180 start_object
->start
= start
;
181 start_object
->arg
= arg
;
183 sproc_start
, PR_SALL
, start_object
, NULL
, 64 * 1024);
184 rv
= (0 < pid
) ? PR_SUCCESS
: PR_FAILURE
;
187 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
189 #endif /* defined(IRIX) && !defined(_PR_PTHREADS) */
196 StartObject
*start_object
;
197 start_object
= PR_NEW(StartObject
);
198 PR_ASSERT(NULL
!= start_object
);
199 start_object
->start
= start
;
200 start_object
->arg
= arg
;
201 th
= (void*)_beginthreadex(
202 NULL
, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */
203 0U, /* DWORD - initial thread stack size, in bytes */
204 windows_start
, /* LPTHREAD_START_ROUTINE - pointer to thread function */
205 start_object
, /* LPVOID - argument for new thread */
206 0U, /*DWORD dwCreationFlags - creation flags */
207 &id
/* LPDWORD - pointer to returned thread identifier */ );
209 rv
= (NULL
== th
) ? PR_FAILURE
: PR_SUCCESS
;
212 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
217 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
223 static void PR_CALLBACK
lazyEntry(void *arg
)
225 PR_ASSERT(NULL
== arg
);
229 static void OneShot(void *arg
)
236 PRIntn test
= (PRIntn
)arg
;
238 for (test
= 0; test
< 12; ++test
) {
244 DPRINTF((output
,"Thread[0x%x] called PR_NewLock\n",
245 PR_GetCurrentThread()));
246 PR_DestroyLock(lock
);
250 (void)PR_SecondsToInterval(1);
251 DPRINTF((output
,"Thread[0x%x] called PR_SecondsToInterval\n",
252 PR_GetCurrentThread()));
255 case 2: (void)PR_CreateThread(
256 PR_USER_THREAD
, lazyEntry
, NULL
, PR_PRIORITY_NORMAL
,
257 PR_LOCAL_THREAD
, PR_UNJOINABLE_THREAD
, 0);
258 DPRINTF((output
,"Thread[0x%x] called PR_CreateThread\n",
259 PR_GetCurrentThread()));
263 fd
= PR_Open("foreign.tmp", PR_CREATE_FILE
| PR_RDWR
, 0666);
264 DPRINTF((output
,"Thread[0x%x] called PR_Open\n",
265 PR_GetCurrentThread()));
270 fd
= PR_NewUDPSocket();
271 DPRINTF((output
,"Thread[0x%x] called PR_NewUDPSocket\n",
272 PR_GetCurrentThread()));
277 fd
= PR_NewTCPSocket();
278 DPRINTF((output
,"Thread[0x%x] called PR_NewTCPSocket\n",
279 PR_GetCurrentThread()));
284 dir
= PR_OpenDir("/tmp/");
285 DPRINTF((output
,"Thread[0x%x] called PR_OpenDir\n",
286 PR_GetCurrentThread()));
291 (void)PR_NewThreadPrivateIndex(&pdkey
, NULL
);
292 DPRINTF((output
,"Thread[0x%x] called PR_NewThreadPrivateIndex\n",
293 PR_GetCurrentThread()));
297 (void)PR_GetEnv("PATH");
298 DPRINTF((output
,"Thread[0x%x] called PR_GetEnv\n",
299 PR_GetCurrentThread()));
303 (void)PR_NewTCPSocketPair(pair
);
304 DPRINTF((output
,"Thread[0x%x] called PR_NewTCPSocketPair\n",
305 PR_GetCurrentThread()));
311 PR_SetConcurrency(2);
312 DPRINTF((output
,"Thread[0x%x] called PR_SetConcurrency\n",
313 PR_GetCurrentThread()));
317 PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH
);
318 DPRINTF((output
,"Thread[0x%x] called PR_SetThreadPriority\n",
319 PR_GetCurrentThread()));
328 PRIntn
main(PRIntn argc
, char **argv
)
331 PRInt32 thread_cnt
= DEFAULT_THREAD_COUNT
;
333 PLOptState
*opt
= PL_CreateOptState(argc
, argv
, "dt:");
336 thread_provider
= thread_win32
;
337 #elif defined(_PR_PTHREADS)
338 thread_provider
= thread_pthread
;
340 thread_provider
= thread_sproc
;
342 thread_provider
= thread_nspr
;
346 while (PL_OPT_EOL
!= (os
= PL_GetNextOpt(opt
)))
348 if (PL_OPT_BAD
== os
) continue;
351 case 'd': /* debug mode */
354 case 't': /* thread count */
355 thread_cnt
= atoi(opt
->value
);
361 PL_DestroyOptState(opt
);
363 PR_SetConcurrency(2);
365 output
= PR_GetSpecialFD(PR_StandardOutput
);
367 while (thread_cnt
-- > 0)
369 rv
= CreateThread(OneShot
, (void*)thread_cnt
);
370 PR_ASSERT(PR_SUCCESS
== rv
);
371 PR_Sleep(PR_MillisecondsToInterval(5));
373 PR_Sleep(PR_SecondsToInterval(3));
374 return (PR_SUCCESS
== PR_Cleanup()) ? 0 : 1;