LCOV - code coverage report
Current view: directory - src/shared/platform/posix - nacl_file_lock.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 98 92 93.9 %
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 <errno.h>
       8                 : #include <sys/file.h>
       9                 : 
      10                 : #include "native_client/src/shared/platform/posix/nacl_file_lock_intern.h"
      11                 : 
      12                 : #include "native_client/src/shared/platform/nacl_check.h"
      13                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      14                 : #include "native_client/src/shared/platform/nacl_log.h"
      15                 : #include "native_client/src/shared/platform/nacl_sync.h"
      16                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      17                 : 
      18                 : 
      19           36894 : static struct NaClFileLockEntry **NaClFileLockManagerFindEntryMu(
      20                 :     struct NaClFileLockManager *self,
      21                 :     struct NaClFileLockEntry const *key) {
      22                 :   struct NaClFileLockEntry **pptr;
      23                 :   struct NaClFileLockEntry *ptr;
      24                 : 
      25           36916 :   for (pptr = &self->head; NULL != (ptr = *pptr); pptr = &ptr->next) {
      26           36970 :     if (ptr->file_dev == key->file_dev &&
      27           18485 :         ptr->file_ino == key->file_ino) {
      28           18463 :       return pptr;
      29                 :     }
      30                 :   }
      31           18431 :   return NULL;
      32                 : }
      33                 : 
      34           18431 : static struct NaClFileLockEntry *NaClFileLockManagerEntryFactory(
      35                 :     struct NaClFileLockManager *self,
      36                 :     int desc) {
      37                 :   struct NaClFileLockEntry *result;
      38                 : 
      39           18431 :   result = malloc(sizeof *result);
      40           18431 :   CHECK(NULL != result);
      41           18431 :   (*self->set_file_identity_data)(result, desc);
      42           18431 :   result->next = NULL;
      43           18431 :   NaClXMutexCtor(&result->mu);
      44           18431 :   NaClXCondVarCtor(&result->cv);
      45           18431 :   result->holding_lock = 1;  /* caller is creating to hold the lock */
      46           18431 :   result->num_waiting = 0;
      47           18431 :   return result;
      48                 : }
      49                 : 
      50           18431 : static void NaClFileLockManagerFileEntryRecycler(
      51                 :     struct NaClFileLockEntry **entryp) {
      52                 :   struct NaClFileLockEntry *entry;
      53           18431 :   CHECK(NULL != entryp);
      54           18431 :   entry = *entryp;
      55           18431 :   CHECK(0 == entry->holding_lock);
      56           18431 :   CHECK(0 == entry->num_waiting);
      57           18431 :   entry->file_dev = 0;
      58           18431 :   entry->file_ino = 0;
      59           18431 :   entry->next = NULL;
      60           18431 :   NaClMutexDtor(&entry->mu);
      61           18431 :   NaClCondVarDtor(&entry->cv);
      62           18431 :   entry->holding_lock = 0;
      63           18431 :   entry->num_waiting = 0;
      64           18431 :   free(entry);
      65           18431 :   *entryp = NULL;
      66           18431 : }
      67                 : 
      68           55288 : static void NaClFileLockManagerSetFileIdentityData(
      69                 :     struct NaClFileLockEntry *entry,
      70                 :     int desc) {
      71                 :   nacl_host_stat_t stbuf;
      72           55288 :   if (0 != NACL_HOST_FSTAT64(desc, &stbuf)) {
      73               0 :     NaClLog(LOG_FATAL,
      74                 :             "NaClFileLockManagerSetFileIdentityData: fstat failed, desc %d,"
      75               0 :             " errno %d\n", desc, errno);
      76                 :   }
      77           55288 :   entry->file_dev = stbuf.st_dev;
      78           55288 :   entry->file_ino = stbuf.st_ino;
      79           55288 : }
      80                 : 
      81           18432 : static void NaClFileLockManagerTakeLock(int desc) {
      82           18432 :   if (0 != flock(desc, LOCK_EX)) {
      83               0 :     NaClLog(LOG_FATAL,
      84               0 :             "NaClFileLockManagerTakeLock: flock failed: errno %d\n", errno);
      85                 :   }
      86           18432 : }
      87                 : 
      88           18432 : static void NaClFileLockManagerDropLock(int desc) {
      89           18432 :   if (0 != flock(desc, LOCK_UN)) {
      90               0 :     NaClLog(LOG_FATAL,
      91               0 :             "NaClFileLockManagerDropLock: flock failed: errno %d\n", errno);
      92                 :   }
      93           18432 : }
      94                 : 
      95             322 : void NaClFileLockManagerCtor(struct NaClFileLockManager *self) {
      96             322 :   NaClXMutexCtor(&self->mu);
      97             322 :   self->head = NULL;
      98             322 :   self->set_file_identity_data = NaClFileLockManagerSetFileIdentityData;
      99             322 :   self->take_file_lock = NaClFileLockManagerTakeLock;
     100             322 :   self->drop_file_lock = NaClFileLockManagerDropLock;
     101             322 : }
     102                 : 
     103               8 : void NaClFileLockManagerDtor(struct NaClFileLockManager *self) {
     104               8 :   CHECK(NULL == self->head);
     105               8 :   NaClMutexDtor(&self->mu);
     106               8 : }
     107                 : 
     108           18447 : void NaClFileLockManagerLock(struct NaClFileLockManager *self,
     109                 :                              int desc) {
     110                 :   struct NaClFileLockEntry key;
     111                 :   struct NaClFileLockEntry **existing;
     112                 :   struct NaClFileLockEntry *entry;
     113                 : 
     114           18447 :   (*self->set_file_identity_data)(&key, desc);
     115                 : 
     116           18447 :   NaClXMutexLock(&self->mu);
     117           18447 :   existing = NaClFileLockManagerFindEntryMu(self, &key);
     118           18447 :   if (NULL == existing) {
     119                 :     /* make new entry */
     120           18431 :     entry = NaClFileLockManagerEntryFactory(self, desc);
     121           18431 :     entry->next = self->head;
     122           18431 :     self->head = entry;
     123           18431 :     NaClXMutexUnlock(&self->mu);
     124                 :   } else {
     125              16 :     entry = *existing;
     126              16 :     NaClXMutexLock(&entry->mu);
     127              16 :     entry->num_waiting++;
     128                 :     /* arithmetic overflow */
     129              16 :     CHECK(0 != entry->num_waiting);
     130                 :     /* drop container lock after ensuring that the entry will not be deleted */
     131              16 :     NaClXMutexUnlock(&self->mu);
     132              52 :     while (entry->holding_lock) {
     133              20 :       NaClXCondVarWait(&entry->cv, &entry->mu);
     134                 :     }
     135              16 :     entry->holding_lock = 1;
     136              16 :     entry->num_waiting--;
     137              16 :     NaClXMutexUnlock(&entry->mu);
     138                 :   }
     139           18447 :   (*self->take_file_lock)(desc);
     140           18447 : }
     141                 : 
     142           18447 : void NaClFileLockManagerUnlock(struct NaClFileLockManager *self,
     143                 :                                int desc) {
     144                 :   struct NaClFileLockEntry key;
     145                 :   struct NaClFileLockEntry **existing;
     146                 :   struct NaClFileLockEntry *entry;
     147                 : 
     148           18447 :   (*self->set_file_identity_data)(&key, desc);
     149                 : 
     150           18447 :   NaClXMutexLock(&self->mu);
     151           18447 :   existing = NaClFileLockManagerFindEntryMu(self, &key);
     152           18447 :   CHECK(NULL != existing);
     153           18447 :   entry = *existing;
     154           18447 :   NaClXMutexLock(&entry->mu);
     155           18447 :   entry->holding_lock = 0;
     156           18447 :   if (0 == entry->num_waiting) {
     157           18431 :     *existing = entry->next;
     158           18431 :     NaClXMutexUnlock(&entry->mu);
     159           18431 :     NaClXMutexUnlock(&self->mu);
     160           18431 :     NaClFileLockManagerFileEntryRecycler(&entry);
     161                 :   } else {
     162              16 :     NaClXMutexUnlock(&self->mu);
     163                 :     /* tell waiting threads that they can now compete for the lock */
     164              16 :     NaClXCondVarBroadcast(&entry->cv);
     165              16 :     NaClXMutexUnlock(&entry->mu);
     166                 :   }
     167           18447 :   (*self->drop_file_lock)(desc);
     168           18447 : }

Generated by: LCOV version 1.7