e0ae9dd225e0e3e96a43a9904ce434917b51742d
[platform/upstream/nspr.git] / nspr / pr / tests / attach.c
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 **  1996 - Netscape Communications Corporation
8 **
9 ** Name: attach.c
10 **
11 ** Description: Platform-specific code to create a native thread. The native thread will
12 **                            repeatedly call PR_AttachThread and PR_DetachThread. The
13 **                            primordial thread waits for this new thread to finish.
14 **
15 ** Modification History:
16 ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
17 **               The debug mode will print all of the printfs associated with this test.
18 **                       The regress mode will be the default mode. Since the regress tool limits
19 **           the output to a one line status:PASS or FAIL,all of the printf statements
20 **                       have been handled with an if (debug_mode) statement.
21 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
22 **                      recognize the return code from tha main program.
23 ** 12-June-97 Revert to return code 0 and 1.
24 ***********************************************************************/
25
26 /***********************************************************************
27 ** Includes
28 ***********************************************************************/
29
30 /* Used to get the command line option */
31 #include "nspr.h"
32 #include "pprthred.h"
33 #include "plgetopt.h"
34
35 #include <stdio.h>
36
37 #ifdef WIN32
38 #include <windows.h>
39 #include <process.h>
40 #elif defined(_PR_PTHREADS)
41 #include <pthread.h>
42 #include "md/_pth.h"
43 #elif defined(IRIX)
44 #include <sys/types.h>
45 #include <sys/prctl.h>
46 #include <sys/wait.h>
47 #include <errno.h>
48 #elif defined(SOLARIS)
49 #include <thread.h>
50 #elif defined(OS2)
51 #define INCL_DOS
52 #define INCL_ERRORS
53 #include <os2.h>
54 #include <process.h>
55 #elif defined(XP_BEOS)
56 #include <kernel/OS.h>
57 #endif
58
59 #define DEFAULT_COUNT 1000
60 PRIntn failed_already=0;
61 PRIntn debug_mode;
62
63
64 int count;
65
66
67 static void 
68 AttachDetach(void)
69 {
70     PRThread *me;
71     PRInt32 index;
72
73     for (index=0;index<count; index++) {
74         me = PR_AttachThread(PR_USER_THREAD, 
75                              PR_PRIORITY_NORMAL,
76                              NULL);
77  
78         if (!me) {
79             fprintf(stderr, "Error attaching thread %d: PR_AttachThread failed\n",
80                     count);
81                 failed_already = 1;
82                 return;
83         }
84         PR_DetachThread();
85     }
86 }
87
88 /************************************************************************/
89
90 static void Measure(void (*func)(void), const char *msg)
91 {
92     PRIntervalTime start, stop;
93     double d;
94
95     start = PR_IntervalNow();
96     (*func)();
97     stop = PR_IntervalNow();
98
99     d = (double)PR_IntervalToMicroseconds(stop - start);
100         if (debug_mode)
101     printf("%40s: %6.2f usec\n", msg, d / count);
102 }
103
104 #ifdef WIN32
105 static unsigned __stdcall threadStartFunc(void *arg)
106 #elif defined(IRIX) && !defined(_PR_PTHREADS)
107 static void threadStartFunc(void *arg)
108 #elif defined(XP_BEOS)
109 static int32 threadStartFunc(void *arg)
110 #else
111 static void * threadStartFunc(void *arg)
112 #endif
113 {
114 #ifdef _PR_DCETHREADS
115     {
116         int rv;
117         pthread_t self = pthread_self();
118         rv = pthread_detach(&self);
119         if (debug_mode) PR_ASSERT(0 == rv);
120                 else if (0 != rv) failed_already=1;
121     }
122 #endif
123
124     Measure(AttachDetach, "Attach/Detach");
125
126 #ifndef IRIX
127     return 0;
128 #endif
129 }
130
131 int main(int argc, char **argv)
132 {
133 #ifdef _PR_PTHREADS
134     int rv;
135     pthread_t threadID;
136     pthread_attr_t attr;
137 #elif defined(SOLARIS)
138     int rv;
139     thread_t threadID;
140 #elif defined(WIN32)
141     DWORD rv;
142     unsigned threadID;
143     HANDLE hThread;
144 #elif defined(IRIX)
145     int rv;
146     int threadID;
147 #elif defined(OS2)
148     int rv;
149     TID threadID;
150 #elif defined(XP_BEOS)
151         thread_id threadID;
152         int32 threadRV;
153         status_t waitRV;
154 #endif
155
156         /* The command line argument: -d is used to determine if the test is being run
157         in debug mode. The regress tool requires only one line output:PASS or FAIL.
158         All of the printfs associated with this test has been handled with a if (debug_mode)
159         test.
160         Usage: test_name [-d] [-c n]
161         */
162         PLOptStatus os;
163         PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
164         while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
165     {
166                 if (PL_OPT_BAD == os) continue;
167         switch (opt->option)
168         {
169         case 'd':  /* debug mode */
170                         debug_mode = 1;
171             break;
172         case 'c':  /* loop count */
173                         count = atoi(opt->value);
174             break;
175          default:
176             break;
177         }
178     }
179         PL_DestroyOptState(opt);
180
181 #if defined(WIN16)
182     printf("attach: This test is not valid for Win16\n");
183     goto exit_now;
184 #endif
185
186         if(0 == count) count = DEFAULT_COUNT;   
187
188     /*
189      * To force the implicit initialization of nspr20
190      */
191     PR_SetError(0, 0);
192     PR_STDIO_INIT();
193
194     /*
195      * Platform-specific code to create a native thread.  The native
196      * thread will repeatedly call PR_AttachThread and PR_DetachThread.
197      * The primordial thread waits for this new thread to finish.
198      */
199
200 #ifdef _PR_PTHREADS
201
202     rv = _PT_PTHREAD_ATTR_INIT(&attr);
203     if (debug_mode) PR_ASSERT(0 == rv);
204         else if (0 != rv) {
205                 failed_already=1;
206                 goto exit_now;
207         }
208         
209 #ifndef _PR_DCETHREADS
210     rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
211     if (debug_mode) PR_ASSERT(0 == rv);
212         else if (0 != rv) {
213                 failed_already=1;
214                 goto exit_now;
215         }
216 #endif  /* !_PR_DCETHREADS */
217     rv = _PT_PTHREAD_CREATE(&threadID, attr, threadStartFunc, NULL);
218     if (rv != 0) {
219                         fprintf(stderr, "thread creation failed: error code %d\n", rv);
220                         failed_already=1;
221                         goto exit_now;
222         }
223         else {
224                 if (debug_mode)
225                         printf ("thread creation succeeded \n");
226
227         }
228     rv = _PT_PTHREAD_ATTR_DESTROY(&attr);
229     if (debug_mode) PR_ASSERT(0 == rv);
230         else if (0 != rv) {
231                 failed_already=1;
232                 goto exit_now;
233         }
234     rv = pthread_join(threadID, NULL);
235     if (debug_mode) PR_ASSERT(0 == rv);
236         else if (0 != rv) {
237                 failed_already=1;
238                 goto exit_now;
239         }
240
241 #elif defined(SOLARIS)
242
243     rv = thr_create(NULL, 0, threadStartFunc, NULL, 0, &threadID);
244     if (rv != 0) {
245         if(!debug_mode) {
246                 failed_already=1;
247                 goto exit_now;
248         } else  
249                 fprintf(stderr, "thread creation failed: error code %d\n", rv);
250     }
251     rv = thr_join(threadID, NULL, NULL);
252     if (debug_mode) PR_ASSERT(0 == rv);
253         else if (0 != rv)
254         {
255                 failed_already=1;
256                 goto exit_now;
257         }
258
259
260 #elif defined(WIN32)
261
262     hThread = (HANDLE) _beginthreadex(NULL, 0, threadStartFunc, NULL,
263             0, &threadID); 
264     if (hThread == 0) {
265         fprintf(stderr, "thread creation failed: error code %d\n",
266                 GetLastError());
267                 failed_already=1;
268                 goto exit_now;
269     }
270     rv = WaitForSingleObject(hThread, INFINITE);
271     if (debug_mode)PR_ASSERT(rv != WAIT_FAILED);
272         else if (rv == WAIT_FAILED) {
273                 failed_already=1;
274                 goto exit_now;
275         }
276
277 #elif defined(IRIX)
278
279     threadID = sproc(threadStartFunc, PR_SALL, NULL);
280     if (threadID == -1) {
281
282                         fprintf(stderr, "thread creation failed: error code %d\n",
283                                         errno);
284                         failed_already=1;
285                         goto exit_now;
286         
287         }
288         else {
289                 if (debug_mode) 
290                         printf ("thread creation succeeded \n");
291                 sleep(3);
292                 goto exit_now;
293         }
294     rv = waitpid(threadID, NULL, 0);
295     if (debug_mode) PR_ASSERT(rv != -1);
296         else  if (rv != -1) {
297                 failed_already=1;
298                 goto exit_now;
299         }
300
301 #elif defined(OS2)
302
303     threadID = (TID) _beginthread((void *)threadStartFunc, NULL,
304             32768, NULL); 
305     if (threadID == -1) {
306         fprintf(stderr, "thread creation failed: error code %d\n", errno);
307         failed_already=1;
308         goto exit_now;
309     }
310     rv = DosWaitThread(&threadID, DCWW_WAIT);
311     if (debug_mode) {
312         PR_ASSERT(rv == NO_ERROR);
313     } else if (rv != NO_ERROR) {
314         failed_already=1;
315         goto exit_now;
316     }
317
318 #elif defined(XP_BEOS)
319         
320         threadID = spawn_thread(threadStartFunc, NULL, B_NORMAL_PRIORITY, NULL);
321         if (threadID <= B_ERROR) {
322                 fprintf(stderr, "thread creation failed: error code %08lx\n", threadID);
323                 failed_already = 1;
324                 goto exit_now;
325         }
326         if (resume_thread(threadID) != B_OK) {
327                 fprintf(stderr, "failed starting thread: error code %08lx\n", threadID);
328                 failed_already = 1;
329                 goto exit_now;
330         }
331
332         waitRV = wait_for_thread(threadID, &threadRV);
333         if (debug_mode)
334                 PR_ASSERT(waitRV == B_OK);
335         else if (waitRV != B_OK) {
336                 failed_already = 1;
337                 goto exit_now;
338         }
339         
340 #else
341         if (!debug_mode)
342                 failed_already=1;
343         else    
344                 printf("The attach test does not apply to this platform because\n"
345             "either this platform does not have native threads or the\n"
346             "test needs to be written for this platform.\n");
347         goto exit_now;
348 #endif
349
350 exit_now:
351    if(failed_already)   
352                 return 1;
353         else
354                 return 0;
355 }