LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sys_futex.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 57 57 100.0 %
Date: 2014-07-02 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2013 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                 : #include "native_client/src/trusted/service_runtime/sys_futex.h"
       8                 : 
       9                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      10                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      11                 : #include "native_client/src/trusted/service_runtime/nacl_copy.h"
      12                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      13                 : 
      14                 : /*
      15                 :  * This is a simple futex implementation that is based on the
      16                 :  * untrusted-code futex implementation from the NaCl IRT
      17                 :  * (irt_futex.c), which in turn was based on futex_emulation.c from
      18                 :  * nacl-glibc.
      19                 :  *
      20                 :  * There are some ways the performance of this implementation could be
      21                 :  * improved:
      22                 :  *
      23                 :  *  * On Linux, use the kernel's futex() syscall with
      24                 :  *    FUTEX_PRIVATE_FLAG.
      25                 :  *
      26                 :  *  * The current futex_wake() implementation does a linear search
      27                 :  *    while holding a global lock, which could perform poorly if there
      28                 :  *    are large numbers of waiting threads.
      29                 :  *
      30                 :  *    We could use a hash table rather than a single linked list for
      31                 :  *    looking up wait addresses.  Furthermore, to reduce lock
      32                 :  *    contention, we could use one lock per hash bucket rather than a
      33                 :  *    single lock.
      34                 :  */
      35                 : 
      36                 : 
      37           51046 : static void ListAddNodeAtEnd(struct NaClListNode *new_node,
      38                 :                              struct NaClListNode *head) {
      39           51046 :   head->prev->next = new_node;
      40           51046 :   new_node->prev = head->prev;
      41           51046 :   new_node->next = head;
      42           51046 :   head->prev = new_node;
      43           51046 : }
      44                 : 
      45           51042 : static void ListRemoveNode(struct NaClListNode *node) {
      46           51042 :   node->next->prev = node->prev;
      47           51042 :   node->prev->next = node->next;
      48           51042 : }
      49                 : 
      50                 : /*
      51                 :  * Given a pointer to a NaClAppThread's futex_wait_list_node, this
      52                 :  * returns a pointer to the NaClAppThread.
      53                 :  */
      54           51526 : static struct NaClAppThread *GetNaClAppThreadFromListNode(
      55                 :     struct NaClListNode *node) {
      56           51526 :   return (struct NaClAppThread *)
      57           51526 :          ((uintptr_t) node -
      58                 :           offsetof(struct NaClAppThread, futex_wait_list_node));
      59                 : }
      60                 : 
      61           51101 : int32_t NaClSysFutexWaitAbs(struct NaClAppThread *natp, uint32_t addr,
      62                 :                             uint32_t value, uint32_t abstime_ptr) {
      63           51101 :   struct NaClApp *nap = natp->nap;
      64                 :   struct nacl_abi_timespec abstime;
      65                 :   uint32_t read_value;
      66                 :   int32_t result;
      67                 :   NaClSyncStatus sync_status;
      68                 : 
      69           51101 :   if (abstime_ptr != 0) {
      70               9 :     if (!NaClCopyInFromUser(nap, &abstime, abstime_ptr, sizeof(abstime))) {
      71               1 :       return -NACL_ABI_EFAULT;
      72                 :     }
      73                 :   }
      74                 : 
      75           51100 :   NaClXMutexLock(&nap->futex_wait_list_mu);
      76                 : 
      77                 :   /*
      78                 :    * Note about lock ordering: NaClCopyInFromUser() can claim the
      79                 :    * mutex nap->mu.  nap->mu may be claimed after
      80                 :    * nap->futex_wait_list_mu but never before it.
      81                 :    */
      82           51100 :   if (!NaClCopyInFromUser(nap, &read_value, addr, sizeof(uint32_t))) {
      83               1 :     result = -NACL_ABI_EFAULT;
      84               1 :     goto cleanup;
      85                 :   }
      86           51099 :   if (read_value != value) {
      87              53 :     result = -NACL_ABI_EWOULDBLOCK;
      88              53 :     goto cleanup;
      89                 :   }
      90                 : 
      91                 :   /* Add the current thread onto the futex wait list. */
      92           51046 :   natp->futex_wait_addr = addr;
      93           51046 :   ListAddNodeAtEnd(&natp->futex_wait_list_node, &nap->futex_wait_list_head);
      94                 : 
      95           51046 :   if (abstime_ptr == 0) {
      96           51038 :     sync_status = NaClCondVarWait(
      97                 :         &natp->futex_condvar, &nap->futex_wait_list_mu);
      98                 :   } else {
      99               8 :     sync_status = NaClCondVarTimedWaitAbsolute(
     100                 :         &natp->futex_condvar, &nap->futex_wait_list_mu, &abstime);
     101                 :   }
     102           51042 :   result = -NaClXlateNaClSyncStatus(sync_status);
     103                 : 
     104                 :   /*
     105                 :    * In case a timeout or spurious wakeup occurs, remove this thread
     106                 :    * from the wait queue.
     107                 :    */
     108           51042 :   if (natp->futex_wait_list_node.next != NULL) {
     109               8 :     ListRemoveNode(&natp->futex_wait_list_node);
     110                 :   }
     111                 :   /* Clear these fields to prevent their accidental use. */
     112           51042 :   natp->futex_wait_list_node.next = NULL;
     113           51042 :   natp->futex_wait_list_node.prev = NULL;
     114           51042 :   natp->futex_wait_addr = 0;
     115                 : 
     116                 : cleanup:
     117           51096 :   NaClXMutexUnlock(&nap->futex_wait_list_mu);
     118           51096 :   return result;
     119                 : }
     120                 : 
     121          807903 : int32_t NaClSysFutexWake(struct NaClAppThread *natp, uint32_t addr,
     122                 :                          uint32_t nwake) {
     123          807903 :   struct NaClApp *nap = natp->nap;
     124                 :   struct NaClListNode *entry;
     125          807903 :   uint32_t woken_count = 0;
     126                 : 
     127          807903 :   NaClXMutexLock(&nap->futex_wait_list_mu);
     128                 : 
     129                 :   /* We process waiting threads in FIFO order. */
     130          807903 :   entry = nap->futex_wait_list_head.next;
     131         1667332 :   while (nwake > 0 && entry != &nap->futex_wait_list_head) {
     132           51526 :     struct NaClListNode *next = entry->next;
     133           51526 :     struct NaClAppThread *waiting_thread = GetNaClAppThreadFromListNode(entry);
     134                 : 
     135           51526 :     if (waiting_thread->futex_wait_addr == addr) {
     136           51034 :       ListRemoveNode(entry);
     137                 :       /*
     138                 :        * Mark the thread as having been removed from the wait queue:
     139                 :        * tell it not to try to remove itself from the queue.
     140                 :        */
     141           51034 :       entry->next = NULL;
     142                 : 
     143                 :       /* Also clear these fields to prevent their accidental use. */
     144           51034 :       entry->prev = NULL;
     145           51034 :       waiting_thread->futex_wait_addr = 0;
     146                 : 
     147           51034 :       NaClXCondVarSignal(&waiting_thread->futex_condvar);
     148           51034 :       woken_count++;
     149           51034 :       nwake--;
     150                 :     }
     151           51526 :     entry = next;
     152                 :   }
     153                 : 
     154          807903 :   NaClXMutexUnlock(&nap->futex_wait_list_mu);
     155                 : 
     156          807903 :   return woken_count;
     157                 : }

Generated by: LCOV version 1.7