LCOV - code coverage report
Current view: directory - tests/unittests/shared/platform - atomic_ops_test.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 75 59 78.7 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /* Copyright (c) 2011 The Native Client Authors. All rights reserved.
       2                 :  * Use of this source code is governed by a BSD-style license that can be
       3                 :  * found in the LICENSE file.
       4                 :  */
       5                 : 
       6                 : #include <stdio.h>
       7                 : 
       8                 : #include "native_client/src/include/atomic_ops.h"
       9                 : #include "native_client/src/shared/platform/nacl_threads.h"
      10                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      11                 : #include "native_client/src/shared/platform/nacl_sync.h"
      12                 : 
      13                 : 
      14                 : #define THREAD_STACK_SIZE  (128*1024)
      15                 : 
      16                 : int32_t gIncrementsPerThread = 1000;
      17                 : int32_t gNumThreads;
      18                 : 
      19                 : struct NaClMutex gMutex;
      20                 : 
      21                 : 
      22                 : /* For atomic counter test */
      23                 : Atomic32 gCounter = 0;
      24                 : 
      25               1 : static void IncrementTest(void) {
      26                 :   /* Increment the counter, gIncrementsPerThread times,
      27                 :    * with the values 1...gIncrementsPerThread
      28                 :    */
      29                 :   Atomic32 i;
      30               1 :   for (i=1; i <= gIncrementsPerThread; i++) {
      31               1 :     AtomicIncrement(&gCounter, i);
      32               1 :   }
      33               1 : }
      34                 : 
      35               1 : static void DecrementTest(void) {
      36                 :   /* Decrement the counter gIncrementsPerThread times,
      37                 :    * with the values 1...gIncrementsPerThread-1
      38                 :    */
      39                 :   Atomic32 i;
      40               1 :   for (i=1; i < gIncrementsPerThread; i++) {
      41               1 :     AtomicIncrement(&gCounter, -i);
      42               1 :   }
      43               1 : }
      44                 : 
      45                 : /* Atomic exchange test
      46                 :  * Each thread exchanges gExchange for its tid.
      47                 :  * It takes the returned value and adds it to gExchangeSum.
      48                 :  * When finished, gExchangeSum + gExchange will contain
      49                 :  * 1 + ... + gNumThreads
      50                 :  */
      51                 : Atomic32 gExchange = 0;
      52                 : Atomic32 gExchangeSum = 0;
      53                 : 
      54               1 : static void ExchangeTest(int32_t tid) {
      55                 :   Atomic32 i;
      56               1 :   i = AtomicExchange(&gExchange, tid);
      57               1 :   if (i == tid) {
      58                 :     fprintf(stderr,
      59               0 :             "Error: AtomicExchange returned the new value instead of old.\n");
      60               0 :     exit(EXIT_FAILURE);
      61                 :   }
      62               1 :   AtomicIncrement(&gExchangeSum, i);
      63               1 : }
      64                 : 
      65                 : /*
      66                 :  * Atomic compare and swap test.
      67                 :  *
      68                 :  * Each thread spins until gSwap == tid, and then exchanges it for tid + 1.
      69                 :  *
      70                 :  * If the threads are scheduled in the order they are launched, the
      71                 :  * CompareAndSwap() loops will complete quickly.  However, if they are
      72                 :  * scheduled out-of-order, these loops could take a long time to
      73                 :  * complete.  Yielding the CPU here improves that significantly.
      74                 :  */
      75                 : Atomic32 gSwap = 1;
      76               1 : static void CompareAndSwapTest(int32_t tid) {
      77               1 :   while (CompareAndSwap(&gSwap, tid, tid + 1) != tid) {
      78               1 :     NaClThreadYield();
      79               1 :   }
      80               1 : }
      81                 : 
      82               1 : void WINAPI ThreadMain(void *state) {
      83               1 :   int32_t tid = (int32_t) (intptr_t) state;
      84                 : 
      85                 :   /* Wait for the signal to begin */
      86               1 :   NaClXMutexLock(&gMutex);
      87               1 :   NaClXMutexUnlock(&gMutex);
      88                 : 
      89                 :   /* Swap the order to shake things up a bit */
      90               1 :   if (tid % 2 == 0) {
      91               1 :     IncrementTest();
      92               1 :     DecrementTest();
      93               1 :   } else {
      94               1 :     DecrementTest();
      95               1 :     IncrementTest();
      96                 :   }
      97                 : 
      98               1 :   ExchangeTest(tid);
      99                 : 
     100               1 :   CompareAndSwapTest(tid);
     101               1 : }
     102                 : 
     103               1 : int main(int argc, const char *argv[]) {
     104                 :   struct NaClThread *threads;
     105                 :   int rv;
     106                 :   int32_t tid;
     107                 :   int32_t tmp;
     108                 : 
     109               1 :   if (argc != 2) {
     110               0 :     fprintf(stderr, "Usage: %s <NumThreads>\n", argv[0]);
     111               0 :     exit(EXIT_FAILURE);
     112                 :   }
     113                 : 
     114               1 :   gNumThreads = strtol(argv[1], NULL, 10);
     115                 : 
     116               1 :   threads = (struct NaClThread*)malloc(gNumThreads*sizeof(struct NaClThread));
     117               1 :   if (threads == NULL) {
     118               0 :     fprintf(stderr, "malloc returned NULL\n");
     119               0 :     exit(EXIT_FAILURE);
     120                 :   }
     121                 : 
     122               1 :   if (!NaClMutexCtor(&gMutex)) {
     123               0 :     fprintf(stderr, "NaClMutexCtor failed\n");
     124               0 :     exit(EXIT_FAILURE);
     125                 :   }
     126                 : 
     127               1 :   NaClXMutexLock(&gMutex);
     128                 : 
     129               1 :   for (tid = 1; tid <= gNumThreads; ++tid) {
     130               1 :     fprintf(stderr, "Creating thread %d\n", (int)tid);
     131                 : 
     132                 :     rv = NaClThreadCreateJoinable(&threads[tid-1],
     133                 :                                   ThreadMain,
     134                 :                                   (void*) (intptr_t) tid,
     135               1 :                                   THREAD_STACK_SIZE);
     136               1 :     if (!rv) {
     137               0 :       fprintf(stderr, "NaClThreadCtor failed\n");
     138               0 :       exit(EXIT_FAILURE);
     139                 :     }
     140               1 :   }
     141                 : 
     142               1 :   NaClXMutexUnlock(&gMutex);
     143                 : 
     144               1 :   for (tid = 1; tid <= gNumThreads; ++tid) {
     145               1 :     NaClThreadJoin(&threads[tid-1]);
     146               1 :   }
     147                 : 
     148                 :   /* Check the results */
     149               1 :   tmp = gIncrementsPerThread * gNumThreads;
     150               1 :   if (gCounter != tmp) {
     151                 :     fprintf(stderr, "ERROR: gCounter is wrong. Expected %d, got %d\n",
     152               0 :            (int)tmp, (int)gCounter);
     153               0 :     exit(EXIT_FAILURE);
     154                 :   }
     155                 : 
     156               1 :   tmp = gNumThreads*(gNumThreads+1)/2;
     157               1 :   if (gExchange + gExchangeSum != tmp) {
     158                 :     fprintf(stderr,
     159                 :             "ERROR: gExchange+gExchangeSum is wrong. Expected %d, got %d\n",
     160               0 :             (int)tmp, (int)(gExchange + gExchangeSum));
     161               0 :     exit(EXIT_FAILURE);
     162                 :   }
     163                 : 
     164               1 :   if (gSwap != gNumThreads+1) {
     165                 :     fprintf(stderr, "ERROR: gSwap is wrong. Expected %d, got %d\n",
     166               0 :             (int)(gNumThreads+1), (int)gSwap);
     167               0 :     exit(EXIT_FAILURE);
     168                 :   }
     169                 : 
     170               1 :   fprintf(stderr, "PASSED\n");
     171               1 :   NaClMutexDtor(&gMutex);
     172               1 :   free(threads);
     173               1 :   return 0;
     174               1 : }

Generated by: LCOV version 1.7