LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - nacl_app_thread.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 109 91 83.5 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 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                 : /*
       8                 :  * NaCl Server Runtime user thread state.
       9                 :  */
      10                 : #include "native_client/src/shared/platform/nacl_check.h"
      11                 : #include "native_client/src/shared/platform/nacl_exit.h"
      12                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      13                 : 
      14                 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
      15                 : #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
      16                 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
      17                 : #include "native_client/src/trusted/service_runtime/nacl_oop_debugger_hooks.h"
      18                 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
      19                 : #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
      20                 : #include "native_client/src/trusted/service_runtime/nacl_stack_safety.h"
      21                 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
      22                 : 
      23                 : 
      24                 : void NaClAppThreadSetSuspendState(struct NaClAppThread *natp,
      25                 :                                   enum NaClSuspendState old_state,
      26            1124 :                                   enum NaClSuspendState new_state) {
      27                 : #if NACL_WINDOWS
      28                 :   NaClXMutexLock(&natp->mu);
      29                 :   while ((natp->suspend_state & NACL_APP_THREAD_SUSPENDING) != 0) {
      30                 :     /*
      31                 :      * We are being suspended, but SuspendThread() has not taken effect yet.
      32                 :      */
      33                 :     NaClXCondVarWait(&natp->cv, &natp->mu);
      34                 :   }
      35                 :   DCHECK(natp->suspend_state == old_state);
      36                 :   natp->suspend_state = new_state;
      37                 :   NaClXMutexUnlock(&natp->mu);
      38                 : #else
      39                 :   UNREFERENCED_PARAMETER(natp);
      40                 :   UNREFERENCED_PARAMETER(old_state);
      41                 :   UNREFERENCED_PARAMETER(new_state);
      42                 : #endif
      43            1124 : }
      44                 : 
      45                 : 
      46               3 : void WINAPI NaClThreadLauncher(void *state) {
      47               3 :   struct NaClAppThread *natp = (struct NaClAppThread *) state;
      48                 :   uint32_t thread_idx;
      49               3 :   NaClLog(4, "NaClThreadLauncher: entered\n");
      50                 : 
      51               3 :   NaClSignalStackRegister(natp->signal_stack);
      52                 : 
      53               3 :   NaClLog(4, "      natp = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) natp);
      54               3 :   NaClLog(4, " prog_ctr  = 0x%016"NACL_PRIxNACL_REG"\n", natp->user.prog_ctr);
      55               3 :   NaClLog(4, "stack_ptr  = 0x%016"NACL_PRIxPTR"\n",
      56                 :           NaClGetThreadCtxSp(&natp->user));
      57                 : 
      58               3 :   thread_idx = NaClGetThreadIdx(natp);
      59               3 :   CHECK(0 < thread_idx);
      60               3 :   CHECK(thread_idx < NACL_THREAD_MAX);
      61               3 :   NaClTlsSetIdx(thread_idx);
      62               3 :   nacl_thread[thread_idx] = natp;
      63               3 :   nacl_user[thread_idx] = &natp->user;
      64               3 :   nacl_sys[thread_idx] = &natp->sys;
      65                 : #if NACL_WINDOWS
      66                 :   nacl_thread_ids[thread_idx] = GetCurrentThreadId();
      67                 : #endif
      68               3 :   nacl_tls[thread_idx] = (uint32_t) NaClSysToUser(natp->nap, natp->sys_tls);
      69               3 :   natp->usr_tlsp = &nacl_tls[thread_idx];
      70                 : 
      71                 :   /*
      72                 :    * We have to hold the threads_mu lock until after thread_num field
      73                 :    * in this thread has been initialized.  All other threads can only
      74                 :    * find and examine this natp through the threads table, so the fact
      75                 :    * that natp is not consistent (no thread_num) will not be visible.
      76                 :    */
      77               3 :   NaClXMutexLock(&natp->nap->threads_mu);
      78               3 :   natp->thread_num = NaClAddThreadMu(natp->nap, natp);
      79               3 :   NaClXMutexUnlock(&natp->nap->threads_mu);
      80                 : 
      81               3 :   NaClVmHoleThreadStackIsSafe(natp->nap);
      82                 : 
      83               3 :   NaClStackSafetyNowOnUntrustedStack();
      84                 : 
      85                 :   /*
      86                 :    * Notify the debug stub, that a new thread is availible.
      87                 :    */
      88               3 :   if (NULL != natp->nap->debug_stub_callbacks) {
      89               0 :     natp->nap->debug_stub_callbacks->thread_create_hook(natp);
      90                 :   }
      91                 : 
      92               3 :   NaClOopDebuggerThreadCreateHook(natp);
      93                 : 
      94                 :   /*
      95                 :    * After this NaClAppThreadSetSuspendState() call, we should not
      96                 :    * claim any mutexes, otherwise we risk deadlock.
      97                 :    */
      98               3 :   NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED,
      99                 :                                NACL_APP_THREAD_UNTRUSTED);
     100                 : 
     101               3 :   NaClStartThreadInApp(natp, natp->user.prog_ctr);
     102                 : }
     103                 : 
     104                 : 
     105                 : /*
     106                 :  * natp should be thread_self(), called while holding no locks.
     107                 :  */
     108               3 : void NaClAppThreadTeardown(struct NaClAppThread *natp) {
     109                 :   struct NaClApp  *nap;
     110                 :   size_t          thread_idx;
     111                 :   int             process_exit_status;
     112                 : 
     113                 :   /*
     114                 :    * mark this thread as dead; doesn't matter if some other thread is
     115                 :    * asking us to commit suicide.
     116                 :    */
     117               3 :   NaClLog(3, "NaClAppThreadTeardown(0x%08"NACL_PRIxPTR")\n",
     118                 :           (uintptr_t) natp);
     119               3 :   nap = natp->nap;
     120               3 :   NaClLog(3, " getting thread table lock\n");
     121               3 :   NaClXMutexLock(&nap->threads_mu);
     122               3 :   NaClLog(3, " getting thread lock\n");
     123               3 :   NaClXMutexLock(&natp->mu);
     124               3 :   natp->state = NACL_APP_THREAD_DEAD;
     125                 :   /*
     126                 :    * Remove ourselves from the ldt-indexed global tables.  The ldt
     127                 :    * entry is released as part of NaClAppThreadDtor (via
     128                 :    * NaClAppThreadDecRef), and if another thread is immediately
     129                 :    * created (from some other running thread) we want to be sure that
     130                 :    * any ldt-based lookups will not reach this dying thread's data.
     131                 :    */
     132               3 :   thread_idx = NaClGetThreadIdx(natp);
     133               3 :   nacl_sys[thread_idx] = NULL;
     134               3 :   nacl_user[thread_idx] = NULL;
     135               3 :   nacl_thread[thread_idx] = NULL;
     136                 : #if NACL_WINDOWS
     137                 :   nacl_thread_ids[thread_idx] = 0;
     138                 : #endif
     139               3 :   NaClLog(3, " removing thread from thread table\n");
     140               3 :   NaClRemoveThreadMu(nap, natp->thread_num);
     141               3 :   NaClLog(3, " unlocking thread\n");
     142               3 :   NaClXMutexUnlock(&natp->mu);
     143               3 :   NaClLog(3, " announcing thread count change\n");
     144               3 :   NaClXCondVarBroadcast(&nap->threads_cv);
     145               3 :   NaClLog(3, " unlocking thread table\n");
     146               3 :   NaClXMutexUnlock(&nap->threads_mu);
     147               3 :   if (NULL != nap->debug_stub_callbacks) {
     148               0 :     NaClLog(3, " notifying the debug stub of the thread exit\n");
     149               0 :     nap->debug_stub_callbacks->thread_exit_hook(natp);
     150                 :   }
     151               3 :   NaClLog(3, " unregistering signal stack\n");
     152               3 :   NaClSignalStackUnregister();
     153               3 :   NaClLog(3, " freeing thread object\n");
     154               3 :   NaClAppThreadDtor(natp);
     155               3 :   NaClLog(3, " NaClThreadExit\n");
     156                 : 
     157               3 :   NaClXMutexLock(&nap->mu);
     158               3 :   process_exit_status = nap->exit_status;
     159               3 :   NaClXMutexUnlock(&nap->mu);
     160                 :   /*
     161                 :    * There appears to be a race on Windows where the process can sometimes
     162                 :    * return a thread exit status instead of the process exit status when
     163                 :    * they occur near simultaneously on two separate threads.  Since this is
     164                 :    * non-deterministic, we always exit a thread with the current value of the
     165                 :    * process exit status to mitigate the possibility of exiting with an
     166                 :    * incorrect value.
     167                 :    * See http://code.google.com/p/nativeclient/issues/detail?id=1715
     168                 :    */
     169               3 :   NaClThreadExit(process_exit_status);
     170               0 :   NaClLog(LOG_FATAL,
     171                 :           "NaClAppThreadTeardown: NaClThreadExit() should not return\n");
     172                 :   /* NOTREACHED */
     173               0 : }
     174                 : 
     175                 : 
     176                 : int NaClAppThreadCtor(struct NaClAppThread  *natp,
     177                 :                       struct NaClApp        *nap,
     178                 :                       uintptr_t             usr_entry,
     179                 :                       uintptr_t             usr_stack_ptr,
     180                 :                       uint32_t              tls_idx,
     181                 :                       uintptr_t             sys_tls,
     182               3 :                       uint32_t              user_tls2) {
     183                 :   int                         rv;
     184                 : 
     185               3 :   NaClLog(4, "         natp = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) natp);
     186               3 :   NaClLog(4, "          nap = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) nap);
     187               3 :   NaClLog(4, "usr_stack_ptr = 0x%016"NACL_PRIxPTR"\n", usr_stack_ptr);
     188                 : 
     189               3 :   NaClThreadContextCtor(&natp->user, nap, usr_entry, usr_stack_ptr, tls_idx);
     190                 : 
     191               3 :   natp->signal_stack = NULL;
     192                 : 
     193               3 :   if (!NaClMutexCtor(&natp->mu)) {
     194               0 :     return 0;
     195                 :   }
     196               3 :   if (!NaClCondVarCtor(&natp->cv)) {
     197               0 :     goto cleanup_mutex;
     198                 :   }
     199                 : 
     200               3 :   natp->sysret = 0;
     201               3 :   natp->nap = nap;
     202                 : 
     203               3 :   if (!NaClSignalStackAllocate(&natp->signal_stack)) {
     204               0 :     goto cleanup_cv;
     205                 :   }
     206                 : 
     207                 : #if NACL_WINDOWS
     208                 :   natp->suspend_state = NACL_APP_THREAD_TRUSTED;
     209                 : #endif
     210                 : 
     211               3 :   natp->state = NACL_APP_THREAD_ALIVE;
     212                 : 
     213               3 :   natp->thread_num = -1;  /* illegal index */
     214               3 :   natp->sys_tls = sys_tls;
     215               3 :   natp->tls2 = user_tls2;
     216               3 :   natp->usr_tlsp = NULL;
     217                 : 
     218               3 :   natp->dynamic_delete_generation = 0;
     219                 : 
     220               3 :   rv = NaClThreadCtor(&natp->thread,
     221                 :                       NaClThreadLauncher,
     222                 :                       (void *) natp,
     223                 :                       NACL_KERN_STACK_SIZE);
     224               3 :   if (rv != 0) {
     225               3 :     return rv; /* Success */
     226                 :   }
     227                 : 
     228               0 :  cleanup_cv:
     229               0 :   NaClCondVarDtor(&natp->cv);
     230               0 :  cleanup_mutex:
     231               0 :   NaClMutexDtor(&natp->mu);
     232               0 :   if (NULL != natp->signal_stack) {
     233               0 :     NaClSignalStackFree(&natp->signal_stack);
     234               0 :     natp->signal_stack = NULL;
     235                 :   }
     236               0 :   return 0;
     237                 : }
     238                 : 
     239                 : 
     240               3 : void NaClAppThreadDtor(struct NaClAppThread *natp) {
     241                 :   /*
     242                 :    * the thread must not be still running, else this crashes the system
     243                 :    */
     244                 : 
     245               3 :   NaClThreadDtor(&natp->thread);
     246               3 :   NaClSignalStackFree(natp->signal_stack);
     247               3 :   natp->signal_stack = NULL;
     248               3 :   NaClTlsFree(natp);
     249               3 :   NaClCondVarDtor(&natp->cv);
     250               3 :   NaClMutexDtor(&natp->mu);
     251               3 : }
     252                 : 
     253                 : 
     254                 : int NaClAppThreadAllocSegCtor(struct NaClAppThread  *natp,
     255                 :                               struct NaClApp        *nap,
     256                 :                               uintptr_t             usr_entry,
     257                 :                               uintptr_t             usr_stack_ptr,
     258                 :                               uintptr_t             sys_tls,
     259               3 :                               uint32_t              user_tls2) {
     260                 :   uint32_t  tls_idx;
     261                 : 
     262                 :   /*
     263                 :    * Set this early, in case NaClTlsAllocate wants to examine it.
     264                 :    */
     265               3 :   natp->nap = nap;
     266                 : 
     267                 :   /*
     268                 :    * Even though we don't know what segment base/range should gs/r9/nacl_tls_idx
     269                 :    * select, we still need one, since it identifies the thread when we context
     270                 :    * switch back.  This use of a dummy tls is only needed for the main thread,
     271                 :    * which is expected to invoke the tls_init syscall from its crt code (before
     272                 :    * main or much of libc can run).  Other threads are spawned with the thread
     273                 :    * pointer address as a parameter.
     274                 :    */
     275               3 :   tls_idx = NaClTlsAllocate(natp, (void *) sys_tls);
     276                 : 
     277               3 :   NaClLog(4,
     278                 :         "NaClAppThreadAllocSegCtor: stack_ptr 0x%08"NACL_PRIxPTR", "
     279                 :         "tls_idx 0x%02"NACL_PRIx32"\n",
     280                 :          usr_stack_ptr, tls_idx);
     281                 : 
     282               3 :   if (NACL_TLS_INDEX_INVALID == tls_idx) {
     283               0 :     NaClLog(LOG_ERROR, "No tls for thread, num_thread %d\n", nap->num_threads);
     284               0 :     return 0;
     285                 :   }
     286                 : 
     287               3 :   return NaClAppThreadCtor(natp,
     288                 :                            nap,
     289                 :                            usr_entry,
     290                 :                            usr_stack_ptr,
     291                 :                            tls_idx,
     292                 :                            sys_tls,
     293                 :                            user_tls2);
     294                 : }

Generated by: LCOV version 1.7