tor-browser

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

intrupt.c (8666B)


      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:        intrupt.c
      8 * Purpose:     testing thread interrupts
      9 */
     10 
     11 #include "plgetopt.h"
     12 #include "prcvar.h"
     13 #include "prerror.h"
     14 #include "prinit.h"
     15 #include "prinrval.h"
     16 #include "prio.h"
     17 #include "prlock.h"
     18 #include "prlog.h"
     19 #include "prthread.h"
     20 #include "prtypes.h"
     21 #include "prnetdb.h"
     22 
     23 #include <stdio.h>
     24 #include <string.h>
     25 
     26 #define DEFAULT_TCP_PORT 12500
     27 
     28 static PRLock* ml = NULL;
     29 static PRCondVar* cv = NULL;
     30 
     31 static PRBool passed = PR_TRUE;
     32 static PRBool debug_mode = PR_FALSE;
     33 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
     34 
     35 static void PR_CALLBACK AbortCV(void* arg) {
     36  PRStatus rv;
     37  PRThread* me = PR_GetCurrentThread();
     38 
     39  /* some other thread (main) is doing the interrupt */
     40  PR_Lock(ml);
     41  rv = PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
     42  if (debug_mode) {
     43    printf("Expected interrupt on wait CV and ");
     44  }
     45  if (PR_FAILURE == rv) {
     46    if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) {
     47      if (debug_mode) {
     48        printf("got it\n");
     49      }
     50    } else {
     51      if (debug_mode) {
     52        printf("got random error\n");
     53      }
     54      passed = PR_FALSE;
     55    }
     56  } else {
     57    if (debug_mode) {
     58      printf("got a successful completion\n");
     59    }
     60    passed = PR_FALSE;
     61  }
     62 
     63  rv = PR_WaitCondVar(cv, 10);
     64  if (debug_mode) {
     65    printf("Expected success on wait CV and %s\n",
     66           (PR_SUCCESS == rv) ? "got it" : "failed");
     67  }
     68  passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
     69 
     70  /* interrupt myself, then clear */
     71  PR_Interrupt(me);
     72  PR_ClearInterrupt();
     73  rv = PR_WaitCondVar(cv, 10);
     74  if (debug_mode) {
     75    printf("Expected success on wait CV and ");
     76    if (PR_FAILURE == rv) {
     77      printf("%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError())
     78                         ? "got interrupted"
     79                         : "a random failure");
     80    }
     81    printf("got it\n");
     82  }
     83  passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
     84 
     85  /* set, then wait - interrupt - then wait again */
     86  PR_Interrupt(me);
     87  rv = PR_WaitCondVar(cv, 10);
     88  if (debug_mode) {
     89    printf("Expected interrupt on wait CV and ");
     90  }
     91  if (PR_FAILURE == rv) {
     92    if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) {
     93      if (debug_mode) {
     94        printf("got it\n");
     95      }
     96    } else {
     97      if (debug_mode) {
     98        printf("failed\n");
     99      }
    100      passed = PR_FALSE;
    101    }
    102  } else {
    103    if (debug_mode) {
    104      printf("got a successful completion\n");
    105    }
    106    passed = PR_FALSE;
    107  }
    108 
    109  rv = PR_WaitCondVar(cv, 10);
    110  if (debug_mode) {
    111    printf("Expected success on wait CV and %s\n",
    112           (PR_SUCCESS == rv) ? "got it" : "failed");
    113  }
    114  passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
    115 
    116  PR_Unlock(ml);
    117 
    118 } /* AbortCV */
    119 
    120 static void PR_CALLBACK AbortIO(void* arg) {
    121  PRStatus rv;
    122  PR_Sleep(PR_SecondsToInterval(2));
    123  rv = PR_Interrupt((PRThread*)arg);
    124  PR_ASSERT(PR_SUCCESS == rv);
    125 } /* AbortIO */
    126 
    127 static void PR_CALLBACK AbortJoin(void* arg) {} /* AbortJoin */
    128 
    129 static void setup_listen_socket(PRFileDesc** listner, PRNetAddr* netaddr) {
    130  PRStatus rv;
    131  PRInt16 port = DEFAULT_TCP_PORT;
    132 
    133  *listner = PR_NewTCPSocket();
    134  PR_ASSERT(*listner != NULL);
    135  memset(netaddr, 0, sizeof(*netaddr));
    136  (*netaddr).inet.ip = PR_htonl(PR_INADDR_ANY);
    137  (*netaddr).inet.family = PR_AF_INET;
    138  do {
    139    (*netaddr).inet.port = PR_htons(port);
    140    rv = PR_Bind(*listner, netaddr);
    141    port += 1;
    142    PR_ASSERT(port < (DEFAULT_TCP_PORT + 10));
    143  } while (PR_FAILURE == rv);
    144 
    145  rv = PR_Listen(*listner, 5);
    146 
    147  if (PR_GetSockName(*listner, netaddr) < 0) {
    148    if (debug_mode) {
    149      printf("intrupt: ERROR - PR_GetSockName failed\n");
    150    }
    151    passed = PR_FALSE;
    152    return;
    153  }
    154 }
    155 
    156 static void PR_CALLBACK IntrBlock(void* arg) {
    157  PRStatus rv;
    158  PRNetAddr netaddr;
    159  PRFileDesc* listner;
    160 
    161  /* some other thread (main) is doing the interrupt */
    162  /* block the interrupt */
    163  PR_BlockInterrupt();
    164  PR_Lock(ml);
    165  rv = PR_WaitCondVar(cv, PR_SecondsToInterval(4));
    166  PR_Unlock(ml);
    167  if (debug_mode) {
    168    printf("Expected success on wait CV and ");
    169    if (PR_FAILURE == rv) {
    170      printf("%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError())
    171                         ? "got interrupted"
    172                         : "got a random failure");
    173    } else {
    174      printf("got it\n");
    175    }
    176  }
    177  passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
    178 
    179  setup_listen_socket(&listner, &netaddr);
    180  PR_UnblockInterrupt();
    181  if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) {
    182    PRInt32 error = PR_GetError();
    183    if (debug_mode) {
    184      printf("Expected interrupt on PR_Accept() and ");
    185    }
    186    if (PR_PENDING_INTERRUPT_ERROR == error) {
    187      if (debug_mode) {
    188        printf("got it\n");
    189      }
    190    } else {
    191      if (debug_mode) {
    192        printf("failed\n");
    193      }
    194      passed = PR_FALSE;
    195    }
    196  } else {
    197    if (debug_mode) {
    198      printf("Failed to interrupt PR_Accept()\n");
    199    }
    200    passed = PR_FALSE;
    201  }
    202 
    203  (void)PR_Close(listner);
    204  listner = NULL;
    205 } /* TestIntrBlock */
    206 
    207 void PR_CALLBACK Intrupt(void* arg) {
    208  PRStatus rv;
    209  PRNetAddr netaddr;
    210  PRFileDesc* listner;
    211  PRThread *abortCV, *abortIO, *abortJoin, *intrBlock;
    212 
    213  ml = PR_NewLock();
    214  cv = PR_NewCondVar(ml);
    215 
    216  /* Part I */
    217  if (debug_mode) {
    218    printf("Part I\n");
    219  }
    220  abortCV = PR_CreateThread(PR_USER_THREAD, AbortCV, 0, PR_PRIORITY_NORMAL,
    221                            thread_scope, PR_JOINABLE_THREAD, 0);
    222 
    223  PR_Sleep(PR_SecondsToInterval(2));
    224  rv = PR_Interrupt(abortCV);
    225  PR_ASSERT(PR_SUCCESS == rv);
    226  rv = PR_JoinThread(abortCV);
    227  PR_ASSERT(PR_SUCCESS == rv);
    228 
    229  /* Part II */
    230  if (debug_mode) {
    231    printf("Part II\n");
    232  }
    233  abortJoin = PR_CreateThread(PR_USER_THREAD, AbortJoin, 0, PR_PRIORITY_NORMAL,
    234                              thread_scope, PR_JOINABLE_THREAD, 0);
    235  PR_Sleep(PR_SecondsToInterval(2));
    236  if (debug_mode) {
    237    printf("Expecting to interrupt an exited thread ");
    238  }
    239  rv = PR_Interrupt(abortJoin);
    240  PR_ASSERT(PR_SUCCESS == rv);
    241  rv = PR_JoinThread(abortJoin);
    242  PR_ASSERT(PR_SUCCESS == rv);
    243  if (debug_mode) {
    244    printf("and succeeded\n");
    245  }
    246 
    247  /* Part III */
    248  if (debug_mode) {
    249    printf("Part III\n");
    250  }
    251  setup_listen_socket(&listner, &netaddr);
    252  abortIO =
    253      PR_CreateThread(PR_USER_THREAD, AbortIO, PR_GetCurrentThread(),
    254                      PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
    255 
    256  if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) {
    257    PRInt32 error = PR_GetError();
    258    if (debug_mode) {
    259      printf("Expected interrupt on PR_Accept() and ");
    260    }
    261    if (PR_PENDING_INTERRUPT_ERROR == error) {
    262      if (debug_mode) {
    263        printf("got it\n");
    264      }
    265    } else {
    266      if (debug_mode) {
    267        printf("failed\n");
    268      }
    269      passed = PR_FALSE;
    270    }
    271  } else {
    272    if (debug_mode) {
    273      printf("Failed to interrupt PR_Accept()\n");
    274    }
    275    passed = PR_FALSE;
    276  }
    277 
    278  (void)PR_Close(listner);
    279  listner = NULL;
    280 
    281  rv = PR_JoinThread(abortIO);
    282  PR_ASSERT(PR_SUCCESS == rv);
    283  /* Part VI */
    284  if (debug_mode) {
    285    printf("Part VI\n");
    286  }
    287  intrBlock = PR_CreateThread(PR_USER_THREAD, IntrBlock, 0, PR_PRIORITY_NORMAL,
    288                              thread_scope, PR_JOINABLE_THREAD, 0);
    289 
    290  PR_Sleep(PR_SecondsToInterval(2));
    291  rv = PR_Interrupt(intrBlock);
    292  PR_ASSERT(PR_SUCCESS == rv);
    293  rv = PR_JoinThread(intrBlock);
    294  PR_ASSERT(PR_SUCCESS == rv);
    295 
    296  PR_DestroyCondVar(cv);
    297  PR_DestroyLock(ml);
    298 } /* Intrupt */
    299 
    300 int main(int argc, char** argv) {
    301  PRThread* intrupt;
    302  PLOptStatus os;
    303  PLOptState* opt = PL_CreateOptState(argc, argv, "dG");
    304  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    305    if (PL_OPT_BAD == os) {
    306      continue;
    307    }
    308    switch (opt->option) {
    309      case 'd': /* debug mode */
    310        debug_mode = PR_TRUE;
    311        break;
    312      case 'G': /* use global threads */
    313        thread_scope = PR_GLOBAL_THREAD;
    314        break;
    315    }
    316  }
    317  PL_DestroyOptState(opt);
    318  intrupt = PR_CreateThread(PR_USER_THREAD, Intrupt, NULL, PR_PRIORITY_NORMAL,
    319                            thread_scope, PR_JOINABLE_THREAD, 0);
    320  if (intrupt == NULL) {
    321    fprintf(stderr, "cannot create thread\n");
    322    passed = PR_FALSE;
    323  } else {
    324    PRStatus rv;
    325    rv = PR_JoinThread(intrupt);
    326    PR_ASSERT(rv == PR_SUCCESS);
    327  }
    328  printf("%s\n", ((passed) ? "PASSED" : "FAILED"));
    329  return ((passed) ? 0 : 1);
    330 } /* main */
    331 
    332 /* intrupt.c */