LCOV - code coverage report
Current view: directory - tests/lock_manager - nacl_file_lock_test.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 273 199 72.9 %
Date: 2014-06-18 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 <ctype.h>
       8                 : #include <errno.h>
       9                 : #include <stdint.h>
      10                 : #include <stdio.h>
      11                 : #include <stdlib.h>
      12                 : #include <string.h>
      13                 : #include <pthread.h>
      14                 : 
      15                 : #include "native_client/src/include/portability.h"
      16                 : #include "native_client/src/include/portability_io.h"
      17                 : #include "native_client/src/include/portability_string.h"
      18                 : #include "native_client/src/include/nacl_macros.h"
      19                 : #include "native_client/src/shared/platform/nacl_check.h"
      20                 : #include "native_client/src/shared/platform/posix/nacl_file_lock.h"
      21                 : #include "native_client/src/shared/platform/posix/nacl_file_lock_intern.h"
      22                 : #include "native_client/tests/lock_manager/nacl_test_util_repl.h"
      23                 : #include "native_client/tests/lock_manager/nacl_test_util_sexp.h"
      24                 : 
      25                 : static int g_test_driver_verbosity = 0;
      26                 : 
      27                 : struct NaClExitCleanupList {
      28                 :   struct NaClExitCleanupList *next;
      29                 :   void (*fn)(void *arg);
      30                 :   void *arg;
      31                 : } *g_NaCl_exit_cleanup_list = NULL;
      32                 : 
      33               0 : void NaClExitCleanupRmdir(void *arg) {
      34               0 :   char *dirname = (char *) arg;
      35               0 :   if (g_test_driver_verbosity) {
      36               0 :     printf("cleanup rmdir %s\n", dirname);
      37               0 :   }
      38               0 :   (void) rmdir(dirname);
      39               0 :   free(arg);
      40               0 : }
      41                 : 
      42               7 : void NaClExitCleanupUnlink(void *arg) {
      43               7 :   char *fname = (char *) arg;
      44               7 :   if (g_test_driver_verbosity) {
      45               0 :     printf("cleanup unlink %s\n", fname);
      46               0 :   }
      47               7 :   (void) unlink(fname);
      48               7 :   free(arg);
      49               7 : }
      50                 : 
      51               7 : void NaClExitCleanupPush(void (*fn)(void *), void *arg) {
      52               7 :   struct NaClExitCleanupList *new_top;
      53                 : 
      54               7 :   new_top = (struct NaClExitCleanupList *) malloc(sizeof *new_top);
      55              21 :   CHECK(NULL != new_top);
      56               7 :   new_top->fn = fn;
      57               7 :   new_top->arg = arg;
      58               7 :   new_top->next = g_NaCl_exit_cleanup_list;
      59               7 :   g_NaCl_exit_cleanup_list = new_top;
      60               7 : }
      61                 : 
      62                 : void NaClExitCleanupDoCleanup(void) {
      63               8 :   struct NaClExitCleanupList *p;
      64               8 :   struct NaClExitCleanupList *next;
      65                 : 
      66              30 :   for (p = g_NaCl_exit_cleanup_list; NULL != p; p = next) {
      67               7 :     (*p->fn)(p->arg);
      68               7 :     next = p->next;
      69               7 :     free(p);
      70               7 :   }
      71               8 :   g_NaCl_exit_cleanup_list = NULL;
      72               8 : }
      73                 : 
      74                 : struct NaClFileLockTestImpl {
      75                 :   struct NaClFileLockTestInterface base;
      76                 :   pthread_mutex_t mu;
      77                 :   pthread_cond_t cv;
      78                 :   size_t num_files;
      79                 :   int *file_locks;
      80                 : };
      81                 : 
      82               4 : static int NaClFileLockTestSetNumFiles(struct NaClFileLockTestInterface *vself,
      83               4 :                                        size_t num_files) {
      84               4 :   struct NaClFileLockTestImpl *self = (struct NaClFileLockTestImpl *) vself;
      85               4 :   size_t ix;
      86               4 :   int rv = 0;
      87                 : 
      88               4 :   pthread_mutex_lock(&self->mu);
      89               8 :   for (ix = (size_t) num_files; ix < self->num_files; ++ix) {
      90               0 :     if (-1 != self->file_locks[ix]) {
      91               0 :       rv = 0;
      92                 :       /* fatal error */
      93               0 :       goto quit;
      94                 :     }
      95               0 :   }
      96               4 :   self->file_locks = realloc(self->file_locks,
      97                 :                              num_files * sizeof *self->file_locks);
      98              12 :   CHECK(NULL != self->file_locks);
      99                 :   /* cast to size_t is safe, due to < MAX_FILE pre-condition */
     100              22 :   for (ix = self->num_files; ix < (size_t) num_files; ++ix) {
     101               7 :     self->file_locks[ix] = -1;  /* not taken; no owner thread-id */
     102               7 :   }
     103               4 :   self->num_files = (size_t) num_files;
     104               4 :   rv = 1;
     105                 :  quit:
     106               4 :   pthread_mutex_unlock(&self->mu);
     107               4 :   return rv;
     108                 : }
     109                 : 
     110                 : static void NaClFileLockTestSetFileIdentityData(
     111              37 :     struct NaClFileLockTestInterface *vself,
     112              37 :     void (*orig)(struct NaClFileLockEntry *entry,
     113                 :                  int desc),
     114              37 :     struct NaClFileLockEntry *entry,
     115              37 :     int desc) {
     116              74 :   UNREFERENCED_PARAMETER(vself);
     117              74 :   UNREFERENCED_PARAMETER(orig);
     118              37 :   entry->file_dev = 0;
     119              37 :   entry->file_ino = desc;
     120              37 : }
     121                 : 
     122              15 : static int NaClFileLockTestTakeFileLock(struct NaClFileLockTestInterface *vself,
     123              15 :                                         void (*orig)(int desc),
     124              15 :                                         int thread_number,
     125              15 :                                         int desc) {
     126              15 :   struct NaClFileLockTestImpl *self = (struct NaClFileLockTestImpl *) vself;
     127              15 :   int success = 0;
     128                 : 
     129              30 :   UNREFERENCED_PARAMETER(orig);
     130              15 :   pthread_mutex_lock(&self->mu);
     131              15 :   for (;;) {
     132              15 :     if (self->num_files <= (size_t) desc) {
     133               0 :       printf("Bad descriptor %d, num_files = %d\n",
     134                 :              desc, (int) self->num_files);
     135               0 :       goto quit;
     136                 :     }
     137              15 :     if (-1 == self->file_locks[desc]) {
     138                 :       /* available -- take it! */
     139              15 :       self->file_locks[desc] = thread_number;
     140              15 :       success = 1;
     141              15 :       goto quit;
     142                 :     }
     143               0 :     pthread_cond_wait(&self->cv, &self->mu);
     144               0 :   }
     145                 :  quit:
     146              15 :   pthread_mutex_unlock(&self->mu);
     147              15 :   return success;
     148                 : }
     149                 : 
     150              15 : static int NaClFileLockTestDropFileLock(struct NaClFileLockTestInterface *vself,
     151              15 :                                         void (*orig)(int desc),
     152              15 :                                         int thread_number,
     153              15 :                                         int desc) {
     154              15 :   struct NaClFileLockTestImpl *self = (struct NaClFileLockTestImpl *) vself;
     155              15 :   int success = 0;
     156                 : 
     157              30 :   UNREFERENCED_PARAMETER(orig);
     158              15 :   pthread_mutex_lock(&self->mu);
     159              15 :   if (self->num_files <= (size_t) desc) {
     160               0 :     printf("Bad descriptor %d, num_files = %d\n",
     161                 :            desc, (int) self->num_files);
     162               0 :     goto quit;
     163                 :   }
     164              15 :   if (thread_number != self->file_locks[desc]) {
     165               0 :     printf("Unlock when thread %d is not holding lock on %d\n",
     166                 :            thread_number, desc);
     167               0 :     goto quit;
     168                 :   }
     169              15 :   self->file_locks[desc] = -1;
     170              15 :   success = 1;
     171              15 :   pthread_cond_broadcast(&self->cv);
     172                 :  quit:
     173              15 :   pthread_mutex_unlock(&self->mu);
     174              15 :   return success;
     175                 : }
     176                 : 
     177               4 : void NaClFileLockTestImplCtor(struct NaClFileLockTestImpl *self) {
     178               4 :   self->base.set_num_files = NaClFileLockTestSetNumFiles;
     179               4 :   self->base.set_identity = NaClFileLockTestSetFileIdentityData;
     180               4 :   self->base.take_lock = NaClFileLockTestTakeFileLock;
     181               4 :   self->base.drop_lock = NaClFileLockTestDropFileLock;
     182               4 :   pthread_mutex_init(&self->mu, (pthread_mutexattr_t const *) NULL);
     183               4 :   pthread_cond_init(&self->cv, (pthread_condattr_t const *) NULL);
     184               4 :   self->num_files = 0;
     185               4 :   self->file_locks = NULL;
     186               4 : }
     187                 : 
     188                 : struct NaClFileLockTestRealFileImpl {
     189                 :   struct NaClFileLockTestInterface base;
     190                 :   char const *tmp_dir;  /* basename for temporary files */
     191                 :   pthread_mutex_t mu;
     192                 :   size_t num_files;  /* monotonically non-decreasing */
     193                 :   int *desc_map;  /* test uses [0..num_files), which maps to real descriptors */
     194                 : };
     195                 : 
     196                 : static int NaClFileLockTestRealFileSetNumFiles(
     197               4 :     struct NaClFileLockTestInterface *vself,
     198               4 :     size_t num_files) {
     199               4 :   struct NaClFileLockTestRealFileImpl *self =
     200                 :       (struct NaClFileLockTestRealFileImpl *) vself;
     201               4 :   size_t ix;
     202               4 :   char file_path[4096];
     203               4 :   int rv = 0;
     204               4 :   int desc;
     205                 : 
     206               4 :   pthread_mutex_lock(&self->mu);
     207               4 :   if (num_files < self->num_files) {
     208               0 :     printf("RealFile set-files must be monotonically non-decreasing\n");
     209               0 :     rv = 0;
     210               0 :     goto quit;
     211                 :   }
     212               4 :   self->desc_map = realloc(self->desc_map,
     213                 :                            num_files * sizeof *self->desc_map);
     214              12 :   CHECK(NULL != self->desc_map);
     215              22 :   for (ix = self->num_files; ix < num_files; ++ix) {
     216               7 :     if ((size_t) SNPRINTF(file_path, sizeof file_path, "%s/%"NACL_PRIdS,
     217                 :                           self->tmp_dir, ix) >= sizeof file_path) {
     218               0 :       printf("RealFile path too long\n");
     219               0 :       rv = 0;
     220               0 :       goto quit;
     221                 :     }
     222               7 :     if (g_test_driver_verbosity > 0) {
     223               0 :       printf("creating file %s\n", file_path);
     224               0 :     }
     225               7 :     desc = OPEN(file_path, O_CREAT | O_WRONLY, 0777);
     226               7 :     if (-1 == desc) {
     227               0 :       printf("RealFile tmp file creation problem: %s\n", file_path);
     228               0 :       rv = 0;
     229               0 :       goto quit;
     230                 :     }
     231               7 :     NaClExitCleanupPush(NaClExitCleanupUnlink, STRDUP(file_path));
     232               7 :     if (1 != write(desc, "0", 1)) {
     233               0 :       printf("RealFile tmp file (%s) write failed\n", file_path);
     234               0 :       rv = 0;
     235               0 :       goto quit;
     236                 :     }
     237                 :     /* save desc in lookup table */
     238               7 :     self->desc_map[ix] = desc;
     239               7 :   }
     240               4 :   self->num_files = num_files;
     241               4 :   rv = 1;
     242                 :  quit:
     243               4 :   pthread_mutex_unlock(&self->mu);
     244               4 :   return rv;
     245                 : }
     246                 : 
     247                 : static int NaClFileLockTestRealFileGetDesc(
     248              67 :     struct NaClFileLockTestRealFileImpl *self,
     249              67 :     int desc) {
     250              67 :   int real_desc;
     251                 : 
     252              67 :   pthread_mutex_lock(&self->mu);
     253             134 :   if (desc < 0 || (size_t) desc >= self->num_files) {
     254               0 :     printf("RealFiles: bad desc %d\n", desc);
     255               0 :     real_desc = -1;
     256               0 :   } else {
     257              67 :     real_desc = self->desc_map[desc];
     258                 :   }
     259              67 :   pthread_mutex_unlock(&self->mu);
     260              67 :   return real_desc;
     261                 : }
     262                 : 
     263                 : static void NaClFileLockTestRealFileSetFileIdentityData(
     264              37 :     struct NaClFileLockTestInterface *vself,
     265              37 :     void (*orig)(struct NaClFileLockEntry *entry,
     266                 :                  int desc),
     267              37 :     struct NaClFileLockEntry *entry,
     268              37 :     int desc) {
     269              37 :   struct NaClFileLockTestRealFileImpl *self =
     270                 :       (struct NaClFileLockTestRealFileImpl *) vself;
     271              37 :   int real_desc = NaClFileLockTestRealFileGetDesc(self, desc);
     272              37 :   if (-1 != real_desc) {
     273                 :     /*
     274                 :      * This is done w/o self->mu because we never close except at Dtor.
     275                 :      * This is also why num_files is monotonic non-decreasing.
     276                 :      */
     277              37 :     if (g_test_driver_verbosity) {
     278               0 :       printf("real identity %d\n", real_desc);
     279               0 :     }
     280              37 :     (*orig)(entry, real_desc);
     281              37 :   }
     282              37 : }
     283                 : 
     284                 : static int NaClFileLockTestRealFileTakeFileLock(
     285              15 :     struct NaClFileLockTestInterface *vself,
     286              15 :     void (*orig)(int desc),
     287              15 :     int thread_number,
     288              15 :     int desc) {
     289              15 :   struct NaClFileLockTestRealFileImpl *self =
     290                 :       (struct NaClFileLockTestRealFileImpl *) vself;
     291              15 :   int real_desc = NaClFileLockTestRealFileGetDesc(self, desc);
     292                 : 
     293              30 :   UNREFERENCED_PARAMETER(thread_number);
     294              15 :   if (-1 == real_desc) {
     295               0 :     printf("RealFileTakeFileLock: Bad descriptor %d\n", desc);
     296               0 :     return 0;
     297                 :   }
     298              15 :   if (g_test_driver_verbosity) {
     299               0 :     printf("real lock %d\n", real_desc);
     300               0 :   }
     301              15 :   (*orig)(real_desc);
     302              15 :   return 1;
     303              15 : }
     304                 : 
     305                 : static int NaClFileLockTestRealFileDropFileLock(
     306              15 :     struct NaClFileLockTestInterface *vself,
     307              15 :     void (*orig)(int desc),
     308              15 :     int thread_number,
     309              15 :     int desc) {
     310              15 :   struct NaClFileLockTestRealFileImpl *self =
     311                 :       (struct NaClFileLockTestRealFileImpl *) vself;
     312              15 :   int real_desc = NaClFileLockTestRealFileGetDesc(self, desc);
     313                 : 
     314              30 :   UNREFERENCED_PARAMETER(thread_number);
     315              15 :   if (-1 == real_desc) {
     316               0 :     printf("RealFileDropFileLock: Bad descriptor %d\n", desc);
     317               0 :     return 0;
     318                 :   }
     319              15 :   if (g_test_driver_verbosity) {
     320               0 :     printf("real unlock %d\n", real_desc);
     321               0 :   }
     322              15 :   (*orig)(real_desc);
     323              15 :   return 1;
     324              15 : }
     325                 : 
     326                 : void NaClFileLockTestRealFileImplCtor(
     327               4 :     struct NaClFileLockTestRealFileImpl *self,
     328               4 :     char const *tmp_dir) {
     329               4 :   self->base.set_num_files = NaClFileLockTestRealFileSetNumFiles;
     330               4 :   self->base.set_identity = NaClFileLockTestRealFileSetFileIdentityData;
     331               4 :   self->base.take_lock = NaClFileLockTestRealFileTakeFileLock;
     332               4 :   self->base.drop_lock = NaClFileLockTestRealFileDropFileLock;
     333               4 :   self->tmp_dir = tmp_dir;
     334               4 :   pthread_mutex_init(&self->mu, (pthread_mutexattr_t const *) NULL);
     335               4 :   self->num_files = 0;
     336               4 :   self->desc_map = NULL;
     337               4 : }
     338                 : 
     339               0 : static void read_crash(struct NaClSexpIo *p, char const *reason) {
     340               0 :   fprintf(stderr, "Syntax error at line %d: %s\n", p->line_num, reason);
     341               0 :   exit(1);
     342               0 : }
     343                 : 
     344               8 : int main(int ac, char **av) {
     345               8 :   int opt;
     346               8 :   struct NaClSexpIo input;
     347               8 :   FILE *iob;
     348               8 :   int interactive = 0;
     349               8 :   int verbosity = 0;
     350                 :   /*
     351                 :    * See build.scons for actual delay settings; default: 10
     352                 :    * millisecond
     353                 :    */
     354               8 :   size_t epsilon_delay_nanos = 10 * NACL_NANOS_PER_MILLI;
     355               8 :   struct NaClFileLockTestImpl test_impl;
     356               8 :   struct NaClFileLockTestRealFileImpl test_real_file_impl;
     357               8 :   struct NaClFileLockTestInterface *test_interface = NULL;
     358               8 :   char const *tmp_dir = NULL;
     359                 : 
     360               8 :   NaClSexpIoCtor(&input, stdin, read_crash);
     361              28 :   while (-1 != (opt = getopt(ac, av, "d:D:f:ivVt"))) {
     362              12 :     switch (opt) {
     363                 :       case 'd':
     364                 :         epsilon_delay_nanos =
     365               8 :             strtoul(optarg, (char **) NULL, 0) * NACL_NANOS_PER_MILLI;
     366               8 :         break;
     367                 :       case 'D':
     368               4 :         tmp_dir = optarg;
     369               4 :         break;
     370                 :       case 'f':
     371               0 :         iob = fopen(optarg, "r");
     372               0 :         if (NULL == iob) {
     373               0 :           perror("nacl_file_lock_test");
     374               0 :           fprintf(stderr,
     375                 :                   "nacl_file_lock_test: -f test file %s could not be opened\n",
     376                 :                   optarg);
     377               0 :           return 1;
     378                 :         }
     379               0 :         NaClSexpIoSetIob(&input, iob);
     380               0 :         break;
     381                 :       case 'i':
     382               0 :         interactive = 1;
     383               0 :         break;
     384                 :       case 't':
     385               0 :         g_test_driver_verbosity++;
     386               0 :         break;
     387                 :       case 'v':
     388               0 :         verbosity++;
     389               0 :         break;
     390                 :       case 'V':
     391               0 :         NaClSexpIncVerbosity();
     392               0 :         break;
     393                 :       default:
     394               0 :         fprintf(stderr,
     395                 :                 "Usage: nacl_file_lock_test [-vV] [-f fn] [-d ms]\n"
     396                 :                 "                           [-D directory]\n"
     397                 :                 "       where the flags\n\n"
     398                 :                 "       -v increases the test framework verbosity level\n"
     399                 :                 "       -V increases the s-expression parser verbosity level\n"
     400                 :                 "\nand\n"
     401                 :                 "       -f specifies the file containing the test script\n"
     402                 :                 "          (default in standard input)\n"
     403                 :                 "       -d specifies the no-event transition delay in ms\n"
     404                 :                 "       -D specifies the temporary directory in which test\n"
     405                 :                 "          temporary files would be created\n"
     406                 :                 );
     407               0 :         return 1;
     408                 :     }
     409              12 :   }
     410               8 :   if (NULL == input.iob) {
     411               0 :     input.iob = stdin;
     412               0 :   }
     413                 : 
     414               8 :   atexit(NaClExitCleanupDoCleanup);
     415                 : 
     416               8 :   if (NULL == tmp_dir) {
     417               4 :     NaClFileLockTestImplCtor(&test_impl);
     418               4 :     test_interface = (struct NaClFileLockTestInterface *) &test_impl;
     419               4 :   } else {
     420               4 :     if (mkdir(tmp_dir, 0777) == 0) {
     421               0 :       NaClExitCleanupPush(NaClExitCleanupRmdir, STRDUP(tmp_dir));
     422               0 :     }
     423               4 :     NaClFileLockTestRealFileImplCtor(&test_real_file_impl, tmp_dir);
     424               4 :     test_interface = (struct NaClFileLockTestInterface *) &test_real_file_impl;
     425                 :   }
     426                 : 
     427               8 :   ReadEvalPrintLoop(&input,
     428                 :                     interactive,
     429                 :                     verbosity,
     430                 :                     epsilon_delay_nanos,
     431                 :                     test_interface);
     432                 : 
     433               8 :   return 0;
     434               8 : }

Generated by: LCOV version 1.7