foreign.c (8384B)
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 ** File: foreign.c 8 ** Description: Testing various functions w/ foreign threads 9 ** 10 ** We create a thread and get it to call exactly one runtime function. 11 ** The thread is allowed to be created by some other environment that 12 ** NSPR, but it does not announce itself to the runtime prior to calling 13 ** in. 14 ** 15 ** The goal: try to survive. 16 ** 17 */ 18 19 #include "prcvar.h" 20 #include "prenv.h" 21 #include "prerror.h" 22 #include "prinit.h" 23 #include "prinrval.h" 24 #include "prio.h" 25 #include "prlock.h" 26 #include "prlog.h" 27 #include "prmem.h" 28 #include "prthread.h" 29 #include "prtypes.h" 30 #include "prprf.h" 31 #include "plgetopt.h" 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 36 static enum { 37 thread_nspr, 38 thread_pthread, 39 thread_sproc, 40 thread_win32 41 } thread_provider; 42 43 typedef void (*StartFn)(void*); 44 typedef struct StartObject { 45 StartFn start; 46 void* arg; 47 } StartObject; 48 49 static PRFileDesc* output; 50 51 static int _debug_on = 0; 52 53 #define DEFAULT_THREAD_COUNT 10 54 55 #define DPRINTF(arg) \ 56 if (_debug_on) PR_fprintf arg 57 58 #if defined(_PR_PTHREADS) 59 # include <pthread.h> 60 # include "md/_pth.h" 61 static void* pthread_start(void* arg) { 62 StartFn start = ((StartObject*)arg)->start; 63 void* data = ((StartObject*)arg)->arg; 64 PR_Free(arg); 65 start(data); 66 return NULL; 67 } /* pthread_start */ 68 #endif /* defined(_PR_PTHREADS) */ 69 70 #if defined(WIN32) 71 # include <windows.h> 72 # include <process.h> /* for _beginthreadex() */ 73 74 static PRUintn __stdcall windows_start(void* arg) { 75 StartObject* so = (StartObject*)arg; 76 StartFn start = so->start; 77 void* data = so->arg; 78 PR_Free(so); 79 start(data); 80 return 0; 81 } /* windows_start */ 82 #endif /* defined(WIN32) */ 83 84 static PRStatus NSPRPUB_TESTS_CreateThread(StartFn start, void* arg) { 85 PRStatus rv; 86 87 switch (thread_provider) { 88 case thread_nspr: { 89 PRThread* thread = 90 PR_CreateThread(PR_USER_THREAD, start, arg, PR_PRIORITY_NORMAL, 91 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); 92 rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS; 93 } break; 94 case thread_pthread: 95 #if defined(_PR_PTHREADS) 96 { 97 int rv; 98 pthread_t id; 99 pthread_attr_t tattr; 100 StartObject* start_object; 101 start_object = PR_NEW(StartObject); 102 PR_ASSERT(NULL != start_object); 103 start_object->start = start; 104 start_object->arg = arg; 105 106 rv = _PT_PTHREAD_ATTR_INIT(&tattr); 107 PR_ASSERT(0 == rv); 108 109 rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 110 PR_ASSERT(0 == rv); 111 112 rv = pthread_attr_setstacksize(&tattr, 64 * 1024); 113 PR_ASSERT(0 == rv); 114 115 rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object); 116 (void)_PT_PTHREAD_ATTR_DESTROY(&tattr); 117 return (0 == rv) ? PR_SUCCESS : PR_FAILURE; 118 } 119 #else 120 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 121 rv = PR_FAILURE; 122 break; 123 #endif /* defined(_PR_PTHREADS) */ 124 125 case thread_sproc: 126 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 127 rv = PR_FAILURE; 128 break; 129 case thread_win32: 130 #if defined(WIN32) 131 { 132 void* th; 133 PRUintn id; 134 StartObject* start_object; 135 start_object = PR_NEW(StartObject); 136 PR_ASSERT(NULL != start_object); 137 start_object->start = start; 138 start_object->arg = arg; 139 th = (void*)_beginthreadex( 140 NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes 141 */ 142 0U, /* DWORD - initial thread stack size, in bytes */ 143 windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function 144 */ 145 start_object, /* LPVOID - argument for new thread */ 146 STACK_SIZE_PARAM_IS_A_RESERVATION, /*DWORD dwCreationFlags - creation 147 flags */ 148 &id /* LPDWORD - pointer to returned thread identifier */); 149 150 rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS; 151 } 152 #else 153 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 154 rv = PR_FAILURE; 155 #endif 156 break; 157 default: 158 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 159 rv = PR_FAILURE; 160 } 161 return rv; 162 } /* NSPRPUB_TESTS_CreateThread */ 163 164 static void PR_CALLBACK lazyEntry(void* arg) { 165 PR_ASSERT(NULL == arg); 166 } /* lazyEntry */ 167 168 static void OneShot(void* arg) { 169 PRUintn pdkey; 170 PRLock* lock; 171 PRFileDesc* fd; 172 PRDir* dir; 173 PRFileDesc* pair[2]; 174 PRIntn test = (PRIntn)arg; 175 176 for (test = 0; test < 12; ++test) { 177 switch (test) { 178 case 0: 179 lock = PR_NewLock(); 180 DPRINTF((output, "Thread[0x%x] called PR_NewLock\n", 181 PR_GetCurrentThread())); 182 PR_DestroyLock(lock); 183 break; 184 185 case 1: 186 (void)PR_SecondsToInterval(1); 187 DPRINTF((output, "Thread[0x%x] called PR_SecondsToInterval\n", 188 PR_GetCurrentThread())); 189 break; 190 191 case 2: 192 (void)PR_CreateThread(PR_USER_THREAD, lazyEntry, NULL, 193 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, 194 PR_UNJOINABLE_THREAD, 0); 195 DPRINTF((output, "Thread[0x%x] called PR_CreateThread\n", 196 PR_GetCurrentThread())); 197 break; 198 199 case 3: 200 fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666); 201 DPRINTF( 202 (output, "Thread[0x%x] called PR_Open\n", PR_GetCurrentThread())); 203 PR_Close(fd); 204 break; 205 206 case 4: 207 fd = PR_NewUDPSocket(); 208 DPRINTF((output, "Thread[0x%x] called PR_NewUDPSocket\n", 209 PR_GetCurrentThread())); 210 PR_Close(fd); 211 break; 212 213 case 5: 214 fd = PR_NewTCPSocket(); 215 DPRINTF((output, "Thread[0x%x] called PR_NewTCPSocket\n", 216 PR_GetCurrentThread())); 217 PR_Close(fd); 218 break; 219 220 case 6: 221 #define TEMP_DIR "./tmp" 222 PR_MkDir(TEMP_DIR, 0700); 223 dir = PR_OpenDir(TEMP_DIR); 224 DPRINTF((output, "Thread[0x%x] called PR_OpenDir\n", 225 PR_GetCurrentThread())); 226 PR_CloseDir(dir); 227 break; 228 229 case 7: 230 (void)PR_NewThreadPrivateIndex(&pdkey, NULL); 231 DPRINTF((output, "Thread[0x%x] called PR_NewThreadPrivateIndex\n", 232 PR_GetCurrentThread())); 233 break; 234 235 case 8: 236 (void)PR_GetEnv("PATH"); 237 DPRINTF( 238 (output, "Thread[0x%x] called PR_GetEnv\n", PR_GetCurrentThread())); 239 break; 240 241 case 9: 242 (void)PR_NewTCPSocketPair(pair); 243 DPRINTF((output, "Thread[0x%x] called PR_NewTCPSocketPair\n", 244 PR_GetCurrentThread())); 245 PR_Close(pair[0]); 246 PR_Close(pair[1]); 247 break; 248 249 case 10: 250 PR_SetConcurrency(2); 251 DPRINTF((output, "Thread[0x%x] called PR_SetConcurrency\n", 252 PR_GetCurrentThread())); 253 break; 254 255 case 11: 256 PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH); 257 DPRINTF((output, "Thread[0x%x] called PR_SetThreadPriority\n", 258 PR_GetCurrentThread())); 259 break; 260 261 default: 262 break; 263 } /* switch() */ 264 } 265 } /* OneShot */ 266 267 int main(int argc, char** argv) { 268 PRStatus rv; 269 PRInt32 thread_cnt = DEFAULT_THREAD_COUNT; 270 PLOptStatus os; 271 PLOptState* opt = PL_CreateOptState(argc, argv, "dt:"); 272 273 #if defined(WIN32) 274 thread_provider = thread_win32; 275 #elif defined(_PR_PTHREADS) 276 thread_provider = thread_pthread; 277 #else 278 thread_provider = thread_nspr; 279 #endif 280 281 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 282 if (PL_OPT_BAD == os) { 283 continue; 284 } 285 switch (opt->option) { 286 case 'd': /* debug mode */ 287 _debug_on = 1; 288 break; 289 case 't': /* thread count */ 290 thread_cnt = atoi(opt->value); 291 break; 292 default: 293 break; 294 } 295 } 296 PL_DestroyOptState(opt); 297 298 PR_SetConcurrency(2); 299 300 output = PR_GetSpecialFD(PR_StandardOutput); 301 302 while (thread_cnt-- > 0) { 303 rv = NSPRPUB_TESTS_CreateThread(OneShot, (void*)thread_cnt); 304 PR_ASSERT(PR_SUCCESS == rv); 305 PR_Sleep(PR_MillisecondsToInterval(5)); 306 } 307 PR_Sleep(PR_SecondsToInterval(3)); 308 return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1; 309 } /* main */ 310 311 /* foreign.c */