[vdr] vdr-xine: is this code thread safe?

Reinhard Nissl rnissl at gmx.de
Wed Mar 30 22:33:14 CEST 2005


Hi,

while facing deadlocks in xine I've written an emulation of an recursive 
mutex, as xine cannot use non posix extensions to be portable.

The code below seems to work but are there any errors left?
What happens if the thread owning the lock is cancelled?

Feel free to send me your improvements. Thanks!

/*
  * xine_rmutex - xine's recursive mutex emulation
  */

struct xine_rmutex_s {
   pthread_mutex_t            access_rmutex;
   pthread_cond_t             unlock_cond;
   int                        lock_count;
   pthread_t                  lock_owner;
};

typedef struct xine_rmutex_s xine_rmutex_t;

int _x_rmutex_init(xine_rmutex_t *rmutex);
int _x_rmutex_lock(xine_rmutex_t *rmutex);
int _x_rmutex_timedlock(xine_rmutex_t *rmutex, int ms_to_time_out);
int _x_rmutex_unlock(xine_rmutex_t *rmutex);
int _x_rmutex_destroy(xine_rmutex_t *rmutex);

#include "assert.h"

int _x_rmutex_init(xine_rmutex_t *rmutex)
{
   pthread_mutex_init(&rmutex->access_rmutex, 0);
   pthread_cond_init(&rmutex->unlock_cond, 0);
   rmutex->lock_count = 0;

   return 0;
}

int _x_rmutex_lock(xine_rmutex_t *rmutex)
{
   return _x_rmutex_timedlock(rmutex, -1);
}

int _x_rmutex_timedlock(xine_rmutex_t *rmutex, int ms_to_time_out)
{
   int r = 0;

   struct timespec abstime;
   {
     struct timeval now;
     gettimeofday(&now, 0);

     abstime.tv_sec = now.tv_sec + ms_to_time_out / 1000;
     abstime.tv_nsec = now.tv_usec * 1000 + (ms_to_time_out % 1000) * 1e6;

     if (abstime.tv_nsec > 1e9)
     {
       abstime.tv_nsec -= 1e9;
       abstime.tv_sec++;
     }
   }

   pthread_mutex_lock(&rmutex->access_rmutex);

   assert(rmutex->lock_count >= 0);

   while (0 == r
          && rmutex->lock_count > 0
          && !pthread_equal(rmutex->lock_owner, pthread_self()))
   {
     if (ms_to_time_out < 0)
       pthread_cond_wait(&rmutex->unlock_cond, &rmutex->access_rmutex);
     else
       r = pthread_cond_timedwait(&rmutex->unlock_cond, 
&rmutex->access_rmutex, &abstime);
   }

   if (0 == r)
   {
     rmutex->lock_owner = pthread_self();
     rmutex->lock_count++;
   }

   pthread_mutex_unlock(&rmutex->access_rmutex);

   return r;
}

int _x_rmutex_unlock(xine_rmutex_t *rmutex)
{
   int r = 0;

   pthread_mutex_lock(&rmutex->access_rmutex);

   assert(rmutex->lock_count > 0);
   assert(pthread_equal(rmutex->lock_owner, pthread_self()));

   rmutex->lock_count--;

   if (rmutex->lock_count == 0)
     pthread_cond_broadcast(&rmutex->unlock_cond);

   pthread_mutex_unlock(&rmutex->access_rmutex);

   return r;
}

int _x_rmutex_destroy(xine_rmutex_t *rmutex)
{
   pthread_cond_destroy(&rmutex->unlock_cond);
   pthread_mutex_destroy(&rmutex->access_rmutex);

   return 0;
}

Bye.
-- 
Dipl.-Inform. (FH) Reinhard Nissl
mailto:rnissl at gmx.de



More information about the vdr mailing list