michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: ** File: foreign.c michael@0: ** Description: Testing various functions w/ foreign threads michael@0: ** michael@0: ** We create a thread and get it to call exactly one runtime function. michael@0: ** The thread is allowed to be created by some other environment that michael@0: ** NSPR, but it does not announce itself to the runtime prior to calling michael@0: ** in. michael@0: ** michael@0: ** The goal: try to survive. michael@0: ** michael@0: */ michael@0: michael@0: #include "prcvar.h" michael@0: #include "prenv.h" michael@0: #include "prerror.h" michael@0: #include "prinit.h" michael@0: #include "prinrval.h" michael@0: #include "prio.h" michael@0: #include "prlock.h" michael@0: #include "prlog.h" michael@0: #include "prmem.h" michael@0: #include "prthread.h" michael@0: #include "prtypes.h" michael@0: #include "prprf.h" michael@0: #include "plgetopt.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: static enum { michael@0: thread_nspr, thread_pthread, thread_sproc, thread_win32 michael@0: } thread_provider; michael@0: michael@0: typedef void (*StartFn)(void*); michael@0: typedef struct StartObject michael@0: { michael@0: StartFn start; michael@0: void *arg; michael@0: } StartObject; michael@0: michael@0: static PRFileDesc *output; michael@0: michael@0: static int _debug_on = 0; michael@0: michael@0: #define DEFAULT_THREAD_COUNT 10 michael@0: michael@0: #define DPRINTF(arg) if (_debug_on) PR_fprintf arg michael@0: michael@0: #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) michael@0: #include michael@0: #include "md/_pth.h" michael@0: static void *pthread_start(void *arg) michael@0: { michael@0: StartFn start = ((StartObject*)arg)->start; michael@0: void *data = ((StartObject*)arg)->arg; michael@0: PR_Free(arg); michael@0: start(data); michael@0: return NULL; michael@0: } /* pthread_start */ michael@0: #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ michael@0: michael@0: #if defined(IRIX) && !defined(_PR_PTHREADS) michael@0: #include michael@0: #include michael@0: static void sproc_start(void *arg, PRSize size) michael@0: { michael@0: StartObject *so = (StartObject*)arg; michael@0: StartFn start = so->start; michael@0: void *data = so->arg; michael@0: PR_Free(so); michael@0: start(data); michael@0: } /* sproc_start */ michael@0: #endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ michael@0: michael@0: #if defined(WIN32) michael@0: #include michael@0: #include /* for _beginthreadex() */ michael@0: michael@0: static PRUintn __stdcall windows_start(void *arg) michael@0: { michael@0: StartObject *so = (StartObject*)arg; michael@0: StartFn start = so->start; michael@0: void *data = so->arg; michael@0: PR_Free(so); michael@0: start(data); michael@0: return 0; michael@0: } /* windows_start */ michael@0: #endif /* defined(WIN32) */ michael@0: michael@0: static PRStatus NSPRPUB_TESTS_CreateThread(StartFn start, void *arg) michael@0: { michael@0: PRStatus rv; michael@0: michael@0: switch (thread_provider) michael@0: { michael@0: case thread_nspr: michael@0: { michael@0: PRThread *thread = PR_CreateThread( michael@0: PR_USER_THREAD, start, arg, michael@0: PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, michael@0: PR_UNJOINABLE_THREAD, 0); michael@0: rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS; michael@0: } michael@0: break; michael@0: case thread_pthread: michael@0: #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) michael@0: { michael@0: int rv; michael@0: pthread_t id; michael@0: pthread_attr_t tattr; michael@0: StartObject *start_object; michael@0: start_object = PR_NEW(StartObject); michael@0: PR_ASSERT(NULL != start_object); michael@0: start_object->start = start; michael@0: start_object->arg = arg; michael@0: michael@0: rv = _PT_PTHREAD_ATTR_INIT(&tattr); michael@0: PR_ASSERT(0 == rv); michael@0: michael@0: rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); michael@0: PR_ASSERT(0 == rv); michael@0: michael@0: rv = pthread_attr_setstacksize(&tattr, 64 * 1024); michael@0: PR_ASSERT(0 == rv); michael@0: michael@0: rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object); michael@0: (void)_PT_PTHREAD_ATTR_DESTROY(&tattr); michael@0: return (0 == rv) ? PR_SUCCESS : PR_FAILURE; michael@0: } michael@0: #else michael@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); michael@0: rv = PR_FAILURE; michael@0: break; michael@0: #endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ michael@0: michael@0: case thread_sproc: michael@0: #if defined(IRIX) && !defined(_PR_PTHREADS) michael@0: { michael@0: PRInt32 pid; michael@0: StartObject *start_object; michael@0: start_object = PR_NEW(StartObject); michael@0: PR_ASSERT(NULL != start_object); michael@0: start_object->start = start; michael@0: start_object->arg = arg; michael@0: pid = sprocsp( michael@0: sproc_start, PR_SALL, start_object, NULL, 64 * 1024); michael@0: rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE; michael@0: } michael@0: #else michael@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); michael@0: rv = PR_FAILURE; michael@0: #endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ michael@0: break; michael@0: case thread_win32: michael@0: #if defined(WIN32) michael@0: { michael@0: void *th; michael@0: PRUintn id; michael@0: StartObject *start_object; michael@0: start_object = PR_NEW(StartObject); michael@0: PR_ASSERT(NULL != start_object); michael@0: start_object->start = start; michael@0: start_object->arg = arg; michael@0: th = (void*)_beginthreadex( michael@0: NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */ michael@0: 0U, /* DWORD - initial thread stack size, in bytes */ michael@0: windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */ michael@0: start_object, /* LPVOID - argument for new thread */ michael@0: STACK_SIZE_PARAM_IS_A_RESERVATION, /*DWORD dwCreationFlags - creation flags */ michael@0: &id /* LPDWORD - pointer to returned thread identifier */ ); michael@0: michael@0: rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS; michael@0: } michael@0: #else michael@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); michael@0: rv = PR_FAILURE; michael@0: #endif michael@0: break; michael@0: default: michael@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); michael@0: rv = PR_FAILURE; michael@0: } michael@0: return rv; michael@0: } /* NSPRPUB_TESTS_CreateThread */ michael@0: michael@0: static void PR_CALLBACK lazyEntry(void *arg) michael@0: { michael@0: PR_ASSERT(NULL == arg); michael@0: } /* lazyEntry */ michael@0: michael@0: michael@0: static void OneShot(void *arg) michael@0: { michael@0: PRUintn pdkey; michael@0: PRLock *lock; michael@0: PRFileDesc *fd; michael@0: PRDir *dir; michael@0: PRFileDesc *pair[2]; michael@0: PRIntn test = (PRIntn)arg; michael@0: michael@0: for (test = 0; test < 12; ++test) { michael@0: michael@0: switch (test) michael@0: { michael@0: case 0: michael@0: lock = PR_NewLock(); michael@0: DPRINTF((output,"Thread[0x%x] called PR_NewLock\n", michael@0: PR_GetCurrentThread())); michael@0: PR_DestroyLock(lock); michael@0: break; michael@0: michael@0: case 1: michael@0: (void)PR_SecondsToInterval(1); michael@0: DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n", michael@0: PR_GetCurrentThread())); michael@0: break; michael@0: michael@0: case 2: (void)PR_CreateThread( michael@0: PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL, michael@0: PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); michael@0: DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n", michael@0: PR_GetCurrentThread())); michael@0: break; michael@0: michael@0: case 3: michael@0: fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666); michael@0: DPRINTF((output,"Thread[0x%x] called PR_Open\n", michael@0: PR_GetCurrentThread())); michael@0: PR_Close(fd); michael@0: break; michael@0: michael@0: case 4: michael@0: fd = PR_NewUDPSocket(); michael@0: DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n", michael@0: PR_GetCurrentThread())); michael@0: PR_Close(fd); michael@0: break; michael@0: michael@0: case 5: michael@0: fd = PR_NewTCPSocket(); michael@0: DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n", michael@0: PR_GetCurrentThread())); michael@0: PR_Close(fd); michael@0: break; michael@0: michael@0: case 6: michael@0: #ifdef SYMBIAN michael@0: #define TEMP_DIR "c:\\data\\" michael@0: #else michael@0: #define TEMP_DIR "/tmp/" michael@0: #endif michael@0: dir = PR_OpenDir(TEMP_DIR); michael@0: DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n", michael@0: PR_GetCurrentThread())); michael@0: PR_CloseDir(dir); michael@0: break; michael@0: michael@0: case 7: michael@0: (void)PR_NewThreadPrivateIndex(&pdkey, NULL); michael@0: DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n", michael@0: PR_GetCurrentThread())); michael@0: break; michael@0: michael@0: case 8: michael@0: (void)PR_GetEnv("PATH"); michael@0: DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n", michael@0: PR_GetCurrentThread())); michael@0: break; michael@0: michael@0: case 9: michael@0: (void)PR_NewTCPSocketPair(pair); michael@0: DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n", michael@0: PR_GetCurrentThread())); michael@0: PR_Close(pair[0]); michael@0: PR_Close(pair[1]); michael@0: break; michael@0: michael@0: case 10: michael@0: PR_SetConcurrency(2); michael@0: DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n", michael@0: PR_GetCurrentThread())); michael@0: break; michael@0: michael@0: case 11: michael@0: PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH); michael@0: DPRINTF((output,"Thread[0x%x] called PR_SetThreadPriority\n", michael@0: PR_GetCurrentThread())); michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: } /* switch() */ michael@0: } michael@0: } /* OneShot */ michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PRStatus rv; michael@0: PRInt32 thread_cnt = DEFAULT_THREAD_COUNT; michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "dt:"); michael@0: michael@0: #if defined(WIN32) michael@0: thread_provider = thread_win32; michael@0: #elif defined(_PR_PTHREADS) michael@0: thread_provider = thread_pthread; michael@0: #elif defined(IRIX) michael@0: thread_provider = thread_sproc; michael@0: #else michael@0: thread_provider = thread_nspr; michael@0: #endif michael@0: michael@0: michael@0: while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) michael@0: { michael@0: if (PL_OPT_BAD == os) continue; michael@0: switch (opt->option) michael@0: { michael@0: case 'd': /* debug mode */ michael@0: _debug_on = 1; michael@0: break; michael@0: case 't': /* thread count */ michael@0: thread_cnt = atoi(opt->value); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: PL_DestroyOptState(opt); michael@0: michael@0: PR_SetConcurrency(2); michael@0: michael@0: output = PR_GetSpecialFD(PR_StandardOutput); michael@0: michael@0: while (thread_cnt-- > 0) michael@0: { michael@0: rv = NSPRPUB_TESTS_CreateThread(OneShot, (void*)thread_cnt); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: PR_Sleep(PR_MillisecondsToInterval(5)); michael@0: } michael@0: PR_Sleep(PR_SecondsToInterval(3)); michael@0: return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1; michael@0: } /* main */ michael@0: michael@0: /* foreign.c */