Back to index

lightning-sunbird  0.9+nobinonly
foreign.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** File:        foreign.c
00040 ** Description: Testing various functions w/ foreign threads
00041 **
00042 **      We create a thread and get it to call exactly one runtime function.
00043 **      The thread is allowed to be created by some other environment that
00044 **      NSPR, but it does not announce itself to the runtime prior to calling
00045 **      in.
00046 **
00047 **      The goal: try to survive.
00048 **      
00049 */
00050 
00051 #include "prcvar.h"
00052 #include "prenv.h"
00053 #include "prerror.h"
00054 #include "prinit.h"
00055 #include "prinrval.h"
00056 #include "prio.h"
00057 #include "prlock.h"
00058 #include "prlog.h"
00059 #include "prmem.h"
00060 #include "prthread.h"
00061 #include "prtypes.h"
00062 #include "prprf.h"
00063 #include "plgetopt.h"
00064 
00065 #include <stdio.h>
00066 #include <stdlib.h>
00067 
00068 static enum {
00069     thread_nspr, thread_pthread, thread_uithread, thread_sproc, thread_win32
00070 } thread_provider;
00071 
00072 typedef void (*StartFn)(void*);
00073 typedef struct StartObject
00074 {
00075     StartFn start;
00076     void *arg;
00077 } StartObject;
00078 
00079 static PRFileDesc *output;
00080 
00081 static int _debug_on = 0;
00082 
00083 #define DEFAULT_THREAD_COUNT       10
00084 
00085 #define DPRINTF(arg) if (_debug_on) PR_fprintf arg
00086 
00087 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
00088 #include <pthread.h>
00089 #include "md/_pth.h"
00090 static void *pthread_start(void *arg)
00091 {
00092     StartFn start = ((StartObject*)arg)->start;
00093     void *data = ((StartObject*)arg)->arg;
00094     PR_Free(arg);
00095     start(data);
00096     return NULL;
00097 }  /* pthread_start */
00098 #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
00099 
00100 #if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
00101 #include <thread.h>
00102 static void *uithread_start(void *arg)
00103 {
00104     StartFn start = ((StartObject*)arg)->start;
00105     void *data = ((StartObject*)arg)->arg;
00106     PR_Free(arg);
00107     start(data);
00108     return NULL;
00109 }  /* uithread_start */
00110 #endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */
00111 
00112 #if defined(IRIX) && !defined(_PR_PTHREADS)
00113 #include <sys/types.h>
00114 #include <sys/prctl.h>
00115 static void sproc_start(void *arg, PRSize size)
00116 {
00117     StartObject *so = (StartObject*)arg;
00118     StartFn start = so->start;
00119     void *data = so->arg;
00120     PR_Free(so);
00121     start(data);
00122 }  /* sproc_start */
00123 #endif  /* defined(IRIX) && !defined(_PR_PTHREADS) */
00124 
00125 #if defined(WIN32)
00126 #include <process.h>  /* for _beginthreadex() */
00127 
00128 static PRUintn __stdcall windows_start(void *arg)
00129 {
00130     StartObject *so = (StartObject*)arg;
00131     StartFn start = so->start;
00132     void *data = so->arg;
00133     PR_Free(so);
00134     start(data);
00135     return 0;
00136 }  /* windows_start */
00137 #endif /* defined(WIN32) */
00138 
00139 static PRStatus CreateThread(StartFn start, void *arg)
00140 {
00141     PRStatus rv;
00142 
00143     switch (thread_provider)
00144     {
00145     case thread_nspr:
00146         {
00147             PRThread *thread = PR_CreateThread(
00148                 PR_USER_THREAD, start, arg,
00149                 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
00150                 PR_UNJOINABLE_THREAD, 0);
00151             rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
00152         }
00153         break;
00154     case thread_pthread:
00155 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
00156         {
00157             int rv;
00158             pthread_t id;
00159             pthread_attr_t tattr;
00160             StartObject *start_object;
00161             start_object = PR_NEW(StartObject);
00162             PR_ASSERT(NULL != start_object);
00163             start_object->start = start;
00164             start_object->arg = arg;
00165 
00166             rv = _PT_PTHREAD_ATTR_INIT(&tattr);
00167             PR_ASSERT(0 == rv);
00168 
00169             rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
00170             PR_ASSERT(0 == rv);
00171 
00172             rv = pthread_attr_setstacksize(&tattr, 64 * 1024);
00173             PR_ASSERT(0 == rv);
00174 
00175             rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object);
00176             (void)_PT_PTHREAD_ATTR_DESTROY(&tattr);
00177             return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
00178         }
00179 #else
00180         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00181         rv = PR_FAILURE;
00182         break;
00183 #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
00184 
00185     case thread_uithread:
00186 #if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
00187         {
00188             int rv;
00189             thread_t id;
00190             long flags;
00191             StartObject *start_object;
00192             start_object = PR_NEW(StartObject);
00193             PR_ASSERT(NULL != start_object);
00194             start_object->start = start;
00195             start_object->arg = arg;
00196 
00197             flags = THR_DETACHED;
00198 
00199             rv = thr_create(NULL, NULL, uithread_start, start_object, flags, &id);
00200             return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
00201         }
00202 #else
00203         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00204         rv = PR_FAILURE;
00205         break;
00206 #endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */
00207 
00208     case thread_sproc:
00209 #if defined(IRIX) && !defined(_PR_PTHREADS)
00210         {
00211             PRInt32 pid;
00212             StartObject *start_object;
00213             start_object = PR_NEW(StartObject);
00214             PR_ASSERT(NULL != start_object);
00215             start_object->start = start;
00216             start_object->arg = arg;
00217             pid = sprocsp(
00218                 sproc_start, PR_SALL, start_object, NULL, 64 * 1024);
00219             rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE;
00220         }
00221 #else
00222         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00223         rv = PR_FAILURE;
00224 #endif  /* defined(IRIX) && !defined(_PR_PTHREADS) */
00225         break;
00226     case thread_win32:
00227 #if defined(WIN32)
00228         {
00229             void *th;
00230             PRUintn id;       
00231             StartObject *start_object;
00232             start_object = PR_NEW(StartObject);
00233             PR_ASSERT(NULL != start_object);
00234             start_object->start = start;
00235             start_object->arg = arg;
00236             th = (void*)_beginthreadex(
00237                 NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */  
00238                 0U, /* DWORD - initial thread stack size, in bytes */
00239                 windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */
00240                 start_object, /* LPVOID - argument for new thread */
00241                 0U, /*DWORD dwCreationFlags - creation flags */
00242                 &id /* LPDWORD - pointer to returned thread identifier */ );
00243 
00244             rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS;
00245         }
00246 #else
00247         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00248         rv = PR_FAILURE;
00249 #endif
00250         break;
00251     default:
00252         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00253         rv = PR_FAILURE;
00254     }
00255     return rv;
00256 }  /* CreateThread */
00257 
00258 static void PR_CALLBACK lazyEntry(void *arg)
00259 {
00260     PR_ASSERT(NULL == arg);
00261 }  /* lazyEntry */
00262 
00263 
00264 static void OneShot(void *arg)
00265 {
00266     PRUintn pdkey;
00267     PRLock *lock;
00268     PRFileDesc *fd;
00269     PRDir *dir;
00270     PRFileDesc *pair[2];
00271     PRIntn test = (PRIntn)arg;
00272 
00273        for (test = 0; test < 12; ++test) {
00274 
00275     switch (test)
00276     {
00277         case 0:
00278             lock = PR_NewLock(); 
00279                      DPRINTF((output,"Thread[0x%x] called PR_NewLock\n",
00280                      PR_GetCurrentThread()));
00281             PR_DestroyLock(lock);
00282             break;
00283             
00284         case 1:
00285             (void)PR_SecondsToInterval(1);
00286                      DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n",
00287                      PR_GetCurrentThread()));
00288             break;
00289             
00290         case 2: (void)PR_CreateThread(
00291             PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL,
00292             PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); 
00293                      DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n",
00294                      PR_GetCurrentThread()));
00295             break;
00296             
00297         case 3:
00298             fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666); 
00299                      DPRINTF((output,"Thread[0x%x] called PR_Open\n",
00300                      PR_GetCurrentThread()));
00301             PR_Close(fd);
00302             break;
00303             
00304         case 4:
00305             fd = PR_NewUDPSocket(); 
00306                      DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n",
00307                      PR_GetCurrentThread()));
00308             PR_Close(fd);
00309             break;
00310             
00311         case 5:
00312             fd = PR_NewTCPSocket(); 
00313                      DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n",
00314                      PR_GetCurrentThread()));
00315             PR_Close(fd);
00316             break;
00317             
00318         case 6:
00319             dir = PR_OpenDir("/tmp/"); 
00320                      DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n",
00321                      PR_GetCurrentThread()));
00322             PR_CloseDir(dir);
00323             break;
00324             
00325         case 7:
00326             (void)PR_NewThreadPrivateIndex(&pdkey, NULL);
00327                      DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n",
00328                      PR_GetCurrentThread()));
00329             break;
00330         
00331         case 8:
00332             (void)PR_GetEnv("PATH");
00333                      DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n",
00334                      PR_GetCurrentThread()));
00335             break;
00336             
00337         case 9:
00338             (void)PR_NewTCPSocketPair(pair);
00339                      DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n",
00340                      PR_GetCurrentThread()));
00341             PR_Close(pair[0]);
00342             PR_Close(pair[1]);
00343             break;
00344             
00345         case 10:
00346             PR_SetConcurrency(2);
00347                      DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n",
00348                      PR_GetCurrentThread()));
00349             break;
00350 
00351         case 11:
00352             PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH);
00353                      DPRINTF((output,"Thread[0x%x] called PR_SetThreadPriority\n",
00354                      PR_GetCurrentThread()));
00355             break;
00356             
00357         default: 
00358             break;
00359     } /* switch() */
00360        }
00361 }  /* OneShot */
00362 
00363 PRIntn main(PRIntn argc, char **argv)
00364 {
00365     PRStatus rv;
00366        PRInt32       thread_cnt = DEFAULT_THREAD_COUNT;
00367        PLOptStatus os;
00368        PLOptState *opt = PL_CreateOptState(argc, argv, "dt:");
00369 
00370 #if defined(WIN32)
00371        thread_provider = thread_win32;
00372 #elif defined(_PR_PTHREADS)
00373        thread_provider = thread_pthread;
00374 #elif defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
00375        thread_provider = thread_uithread;
00376 #elif defined(IRIX)
00377        thread_provider = thread_sproc;
00378 #else
00379     thread_provider = thread_nspr;
00380 #endif
00381 
00382 
00383        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00384     {
00385               if (PL_OPT_BAD == os) continue;
00386         switch (opt->option)
00387         {
00388         case 'd':  /* debug mode */
00389                      _debug_on = 1;
00390             break;
00391         case 't':  /* thread count */
00392             thread_cnt = atoi(opt->value);
00393             break;
00394          default:
00395             break;
00396         }
00397     }
00398        PL_DestroyOptState(opt);
00399 
00400        PR_SetConcurrency(2);
00401 
00402        output = PR_GetSpecialFD(PR_StandardOutput);
00403 
00404     while (thread_cnt-- > 0)
00405     {
00406         rv = CreateThread(OneShot, (void*)thread_cnt);
00407         PR_ASSERT(PR_SUCCESS == rv);
00408         PR_Sleep(PR_MillisecondsToInterval(5));
00409     }
00410     PR_Sleep(PR_SecondsToInterval(3));
00411     return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1;
00412 }  /* main */
00413 
00414 /* foreign.c */