LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - nacl_tls_unittest.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 79 64 81.0 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : /*
       7                 :  * A stand-alone application that tests thread local storage (TLS) on the
       8                 :  * current platform.  It is written to avoid locks and condition variables.
       9                 :  * Since it is testing thread-specific stuff, it's good to use as little
      10                 :  * *other* thread-specific stuff as possible for these tests.
      11                 :  *
      12                 :  * Note that this test hangs in pthread_join() on ARM QEMU.
      13                 :  */
      14                 : 
      15                 : #if NACL_LINUX || NACL_OSX
      16                 : #include <pthread.h>
      17                 : #endif
      18                 : #include <stdio.h>
      19                 : #include <stdlib.h>
      20                 : #include <string.h>
      21                 : 
      22                 : #include "native_client/src/include/portability.h"
      23                 : #include "native_client/src/shared/platform/nacl_log.h"
      24                 : #include "native_client/src/shared/platform/nacl_time.h"
      25                 : 
      26                 : /* Constants. */
      27                 : static const int NSEC_PER_MSEC = 1000 * 1000;
      28                 : 
      29                 : /* A regular global variable, shared among all threads. */
      30                 : volatile int g_running_thread_count;
      31                 : 
      32                 : /*
      33                 :  * The TLS to be tested.
      34                 :  * This variable is used in only one function. Since we're testing that the
      35                 :  * memory is actually different for each thread, we need to make sure the
      36                 :  * compiler does not optimize out the store/load of this variable or
      37                 :  * rearrange when the store happens.  As such, make the TLS variable
      38                 :  * "volatile".
      39                 :  */
      40                 : THREAD volatile int tls_data;
      41                 : 
      42                 : /* Parameter block used when starting a thread. */
      43                 : struct ThreadData {
      44                 :   int thread_num;
      45                 :   int total_num_threads;
      46                 :   int *p_tls_data_return;
      47                 : };
      48                 : 
      49                 : /* Initializes NaCl modules. */
      50               1 : static void Init(void) {
      51               1 :   const char *nacl_verbosity = getenv("NACLVERBOSITY");
      52                 : 
      53               1 :   NaClLogModuleInit();
      54                 :   NaClLogSetVerbosity((NULL == nacl_verbosity)
      55                 :                       ? 0
      56               1 :                       : strtol(nacl_verbosity, (char **) 0, 0));
      57               1 :   NaClTimeInit();
      58               1 : }
      59                 : 
      60                 : /* Shuts down NaCl modules. */
      61               1 : static void Fini(void) {
      62               1 :   NaClTimeFini();
      63               1 :   NaClLogModuleFini();
      64               1 : }
      65                 : 
      66                 : /* Prints an error message and exits with "failure" status. */
      67               0 : static void ErrorExit(void) {
      68               0 :   NaClLog(LOG_ERROR, "TEST FAILED\n");
      69               0 :   Fini();
      70               0 :   exit(1);
      71                 : }
      72                 : 
      73                 : /*
      74                 :  * Waits for g_running_thread_count to exactly equal final_thread_count.
      75                 :  * Returns true if final_thread_count reached, false if timed out.
      76                 :  */
      77               1 : static int WaitForThreads(int final_thread_count) {
      78               1 :   const int SLEEP_NSEC = 10 * NSEC_PER_MSEC; /* 10ms */
      79               1 :   const int SLEEP_ITERATIONS = 1000;         /* *10ms = 10 sec */
      80                 : 
      81                 :   int i;
      82                 :   struct nacl_abi_timespec sleep_time;
      83                 : 
      84               1 :   sleep_time.tv_sec = 0;
      85               1 :   sleep_time.tv_nsec = SLEEP_NSEC;
      86                 : 
      87               1 :   for (i = 0; i < SLEEP_ITERATIONS; ++i) {
      88               1 :     if (final_thread_count == g_running_thread_count) {
      89               1 :       return 1;
      90                 :     }
      91               1 :     NaClNanosleep(&sleep_time, NULL);
      92               1 :   }
      93               0 :   return 0;
      94               1 : }
      95                 : 
      96                 : /* Executes the test of TLS for each thread. */
      97                 : #if NACL_LINUX || NACL_OSX
      98                 : typedef void *thread_param_t;
      99                 : typedef void *thread_return_t;
     100                 : #define OS_API_TYPE
     101                 : #elif NACL_WINDOWS
     102                 : typedef LPVOID thread_param_t;
     103                 : typedef DWORD thread_return_t;
     104                 : #define OS_API_TYPE WINAPI
     105                 : #endif
     106               1 : static thread_return_t OS_API_TYPE ThreadEntryPoint(thread_param_t p) {
     107               1 :   struct ThreadData *param = (struct ThreadData *) p;
     108               1 :   int my_thread_num = param->thread_num;
     109                 : 
     110                 :   /* Set our TLS to our expected value. */
     111               1 :   tls_data = my_thread_num * 2;
     112                 : 
     113                 :   /* Tell the main thread that we are running. */
     114               1 :   ++g_running_thread_count;
     115                 : 
     116                 :   /* Wait for all threads to be running. */
     117               1 :   WaitForThreads(param->total_num_threads);
     118                 : 
     119                 :   /*
     120                 :    * All of the threads have started and have written to their own TLS.
     121                 :    * Read our TLS and give it back to the main thread.
     122                 :    */
     123               1 :   param->p_tls_data_return[my_thread_num] = tls_data;
     124                 : 
     125               1 :   return 0;
     126               1 : }
     127                 : 
     128                 : #if NACL_LINUX || NACL_OSX
     129                 : /*
     130                 :  * Creates a thread on Linux.
     131                 :  * Returns 0 for success.
     132                 :  */
     133                 : static int MyCreateThread(pthread_t *p_pthread, void *p) {
     134                 :   return pthread_create(p_pthread, NULL, ThreadEntryPoint, p);
     135                 : }
     136                 : 
     137                 : /*
     138                 :  * Waits for a thread to finish on Linux.
     139                 :  * Returns 0 for success.
     140                 :  */
     141                 : static int MyWaitForThreadExit(pthread_t pthread) {
     142                 :   return pthread_join(pthread, NULL);
     143                 : }
     144                 : 
     145                 : #elif NACL_WINDOWS
     146                 : /*
     147                 :  * Creates a thread on Windows.
     148                 :  * Returns 0 for success.
     149                 :  */
     150               1 : static int MyCreateThread(HANDLE *p_handle, void *p) {
     151                 :   *p_handle = CreateThread(NULL,   /* security. */
     152                 :                            0,      /* <64K stack size. */
     153                 :                            ThreadEntryPoint,
     154                 :                            p,      /* Thread data. */
     155                 :                            0,      /* Thread runs immediately. */
     156               1 :                            NULL);  /* OS version of thread id. */
     157               1 :   return (NULL != *p_handle) ? 0 : 1;
     158               1 : }
     159                 : 
     160                 : /*
     161                 :  * Waits for a thread to finish on Windows.
     162                 :  * Returns 0 for success.
     163                 :  */
     164               1 : static int MyWaitForThreadExit(HANDLE handle) {
     165                 :   static const DWORD MAX_WAIT_MSEC = 5000;
     166                 : 
     167                 :   DWORD result = WaitForMultipleObjects(1,              /* Thread count. */
     168                 :                                         &handle,        /* Thread handle. */
     169                 :                                         TRUE,           /* Wait for all. */
     170               1 :                                         MAX_WAIT_MSEC); /* Max wait time */
     171               1 :   return (WAIT_OBJECT_0 == result) ? 0 : 1;
     172               1 : }
     173                 : #endif
     174                 : 
     175                 : /* Tests that threads can access TLS. */
     176               1 : int main(void) {
     177                 : #define NUM_THREADS (10)
     178                 : 
     179                 :   int i;
     180                 :   int rc;
     181                 : #if NACL_LINUX || NACL_OSX
     182                 :   pthread_t thread_id[NUM_THREADS];
     183                 : #elif NACL_WINDOWS
     184                 :   HANDLE thread_id[NUM_THREADS];
     185                 : #endif
     186                 :   int tls_data_return[NUM_THREADS];
     187                 :   struct ThreadData param;
     188                 :   int test_passed;
     189                 : 
     190                 :   /* Initialize NaCl. */
     191               1 :   Init();
     192                 : 
     193                 :   /* Initialize global variables. */
     194               1 :   g_running_thread_count = 0;
     195                 : 
     196                 :   /* Initialize the per-thread data. */
     197               1 :   memset(thread_id, 0x00, sizeof(thread_id));
     198               1 :   memset(tls_data_return, 0xff, sizeof(tls_data_return));
     199                 : 
     200                 :   /* Initialize the thread parameter block. */
     201               1 :   param.total_num_threads = NUM_THREADS;
     202               1 :   param.p_tls_data_return = tls_data_return;
     203                 : 
     204                 :   /* Start each thread and have it set its TLS. */
     205               1 :   for (i = 0; i < NUM_THREADS; ++i) {
     206               1 :     param.thread_num = i;
     207               1 :     rc = MyCreateThread(&thread_id[i], &param);
     208               1 :     if (0 != rc) {
     209               0 :       NaClLog(LOG_ERROR, "ERROR: Could not create thread %d, rc=%d.\n", i, rc);
     210               0 :       ErrorExit();
     211                 :     }
     212               1 :     if (!WaitForThreads(i + 1)) {
     213               0 :       NaClLog(LOG_ERROR, "ERROR: Timed out waiting for thread %d.\n", i);
     214               0 :       ErrorExit();
     215                 :     }
     216               1 :   }
     217                 : 
     218                 :   /*
     219                 :    * All threads have started and have written to their TLS.  As soon as the
     220                 :    * last thread was ready, all of the threads should have continued
     221                 :    * executing and exited.  Wait for each thread to exit, then validate its
     222                 :    * TLS data.
     223                 :    */
     224               1 :   test_passed = 1;
     225               1 :   for (i = 0; i < NUM_THREADS; ++i) {
     226               1 :     int expected = i * 2;
     227                 : 
     228                 :     /*
     229                 :      * Print the expected and actual data to the console. Don't abort
     230                 :      * immediately on error. This allows each thread's TLS to be examined so
     231                 :      * that all of the bad data gets printed to help show a failure pattern.
     232                 :      */
     233               1 :     rc = MyWaitForThreadExit(thread_id[i]);
     234               1 :     if (0 != rc) {
     235               0 :       NaClLog(LOG_ERROR, "ERROR: Thread %d did not exit, rc=%d.\n", i, rc);
     236               0 :       test_passed = 0;
     237               1 :     } else  if (expected != tls_data_return[i]) {
     238                 :       NaClLog(LOG_ERROR, "ERROR: Thread %d TLS data, expected=%d, actual=%d.\n",
     239               0 :                i, expected, tls_data_return[i]);
     240               0 :       test_passed = 0;
     241               0 :     } else {
     242                 :       NaClLog(LOG_INFO, "OK: Thread %d TLS data, expected=%d, actual=%d.\n",
     243               1 :                i, expected, tls_data_return[i]);
     244                 :     }
     245               1 :   }
     246               1 :   if (!test_passed) {
     247               0 :     ErrorExit();
     248                 :   }
     249                 : 
     250               1 :   NaClLog(LOG_INFO, "TEST PASSED\n");
     251               1 :   Fini();
     252               1 :   return 0;
     253               1 : }

Generated by: LCOV version 1.7