LTP GCOV extension - code coverage report
Current view: directory - trunk/libteredo - clock.c
Test: lcov.info
Date: 2007-05-09 Instrumented lines: 47
Code covered: 74.5 % Executed lines: 35

       1                 : /*
       2                 :  * clock.c - Fast-lookup 1Hz clock
       3                 :  * $Id: clock.c 1853 2006-12-15 17:49:53Z remi $
       4                 :  */
       5                 : 
       6                 : /***********************************************************************
       7                 :  *  Copyright © 2006 Rémi Denis-Courmont.                              *
       8                 :  *  This program is free software; you can redistribute and/or modify  *
       9                 :  *  it under the terms of the GNU General Public License as published  *
      10                 :  *  by the Free Software Foundation; version 2 of the license.         *
      11                 :  *                                                                     *
      12                 :  *  This program is distributed in the hope that it will be useful,    *
      13                 :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
      14                 :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               *
      15                 :  *  See the GNU General Public License for more details.               *
      16                 :  *                                                                     *
      17                 :  *  You should have received a copy of the GNU General Public License  *
      18                 :  *  along with this program; if not, you can get it from:              *
      19                 :  *  http://www.gnu.org/copyleft/gpl.html                               *
      20                 :  ***********************************************************************/
      21                 : 
      22                 : #ifdef HAVE_CONFIG_H
      23                 : # include <config.h>
      24                 : #endif
      25                 : 
      26                 : #include <time.h>
      27                 : #include <assert.h>
      28                 : #include <limits.h>
      29                 : 
      30                 : #include <sys/types.h>
      31                 : #include <sys/time.h>
      32                 : #include <unistd.h> // _POSIX_*
      33                 : #include <pthread.h>
      34                 : 
      35                 : #include "clock.h"
      36                 : #include "debug.h"
      37                 : 
      38                 : typedef struct clock_data_t
      39                 : {
      40                 :         unsigned long    value;
      41                 :         clockid_t        id;
      42                 :         pthread_rwlock_t lock;
      43                 :         pthread_t        thread;
      44                 : } clock_data_t;
      45                 : 
      46                 : 
      47                 : /**
      48                 :  * Userland low-precision (1 Hz) clock
      49                 :  *
      50                 :  * This is way faster than calling time() for every packet transmitted or
      51                 :  * received. The first implementation was using POSIX timers, but it might
      52                 :  * be a bit overkill to spawn a thread every second to simply increment an
      53                 :  * integer. Also, POSIX timers with thread event delivery has a terrible
      54                 :  * portability at the time of writing (June 2006). Basically, recent
      55                 :  * GNU/Linux have it, and that's about it... no uClibc support, only in
      56                 :  * -current for FreeBSD...
      57                 :  */
      58                 : static LIBTEREDO_NORETURN void *clock_thread (void *o)
      59               4 : {
      60               4 :         clock_data_t *context = (clock_data_t *)o;
      61               4 :         clockid_t id = context->id;
      62                 : 
      63                 :         for (;;)
      64                 :         {
      65                 :                 struct timespec ts;
      66               4 :                 clock_gettime (id, &ts);
      67                 : 
      68               4 :                 pthread_rwlock_wrlock (&context->lock);
      69               4 :                 context->value = ts.tv_sec;
      70               4 :                 pthread_rwlock_unlock (&context->lock);
      71                 : 
      72               4 :                 ts.tv_sec++;
      73               4 :                 ts.tv_nsec = 0;
      74                 : 
      75               4 :                 clock_nanosleep (id, TIMER_ABSTIME, &ts, NULL);
      76               0 :         }
      77                 : }
      78                 : 
      79                 : 
      80                 : static clock_data_t data;
      81                 : 
      82                 : 
      83                 : unsigned long teredo_clock (void)
      84               0 : {
      85               0 :         clock_data_t *context = (clock_data_t *)&data;
      86                 :         unsigned long value;
      87                 : 
      88               0 :         pthread_rwlock_rdlock (&context->lock);
      89               0 :         value = context->value;
      90               0 :         pthread_rwlock_unlock (&context->lock);
      91               0 :         return value;
      92                 : }
      93                 : 
      94                 : 
      95                 : static unsigned users = 0;
      96                 : static pthread_mutex_t user_mutex = PTHREAD_MUTEX_INITIALIZER;
      97                 : 
      98                 : /**
      99                 :  * Starts the clock. Thread-safe.
     100                 :  *
     101                 :  * @return 0 in case of success, an errno in case of error.
     102                 :  */
     103                 : int teredo_clock_create (void)
     104               4 : {
     105               4 :         int val = -1;
     106                 : 
     107               4 :         pthread_mutex_lock (&user_mutex);
     108                 : 
     109               4 :         if (users == 0)
     110                 :         {
     111               4 :                 clock_data_t *ctx = (clock_data_t *)&data;
     112                 :                 struct timespec ts;
     113                 : 
     114                 : #if (_POSIX_CLOCK_SELECTION - 0 >= 0) && (_POSIX_MONOTONIC_CLOCK - 0 >= 0)
     115                 :                 /* Run-time POSIX monotonic clock detection */
     116               4 :                 ctx->id = CLOCK_MONOTONIC;
     117               4 :                 if (clock_gettime (CLOCK_MONOTONIC, &ts))
     118                 : #endif
     119                 :                 {
     120               0 :                         ctx->id = CLOCK_REALTIME;
     121               0 :                         clock_gettime (CLOCK_REALTIME, &ts);
     122                 :                 }
     123                 :         
     124               4 :                 ctx->value = ts.tv_sec;
     125                 :         
     126               4 :                 val = pthread_rwlock_init (&ctx->lock, NULL);
     127               4 :                 if (val == 0)
     128                 :                 {
     129               4 :                         val = pthread_create (&ctx->thread, NULL, clock_thread, ctx);
     130               4 :                         if (val == 0)
     131               4 :                                 users = 1;
     132                 :                         else
     133               0 :                                 pthread_rwlock_destroy (&ctx->lock);
     134                 :                 }
     135                 :         }
     136                 :         else
     137               0 :         if (users < UINT_MAX)
     138               0 :                 users++;
     139                 : 
     140               4 :         pthread_mutex_unlock (&user_mutex);
     141               4 :         return val;
     142                 : }
     143                 : 
     144                 : 
     145                 : /**
     146                 :  * Stops the clock. Thread-safe.
     147                 :  *
     148                 :  * @return nothing (always succeeds when defined).
     149                 :  */
     150                 : void teredo_clock_destroy (void)
     151               4 : {
     152               4 :         pthread_mutex_lock (&user_mutex);
     153               4 :         assert (users > 0);
     154                 : 
     155               4 :         if (--users == 0)
     156                 :         {
     157               4 :                 clock_data_t *ctx = (clock_data_t *)&data;
     158                 : 
     159               4 :                 pthread_cancel (ctx->thread);
     160               4 :                 pthread_join (ctx->thread, NULL);
     161               4 :                 pthread_rwlock_destroy (&ctx->lock);
     162                 :         }
     163               4 :         pthread_mutex_unlock (&user_mutex);
     164               4 : }
     165                 : 
     166                 : 

Generated by: LTP GCOV extension version 1.5