tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */