DD_CacheLock.c 3.82 KB
/*=====================================================================
 *                DD SYSTEM base package
 *                  DD_Server library
 *                    DD_CacheLock.c
 *                      V.1.0
 * Last revision:
 *   May 29 2015: Version 1.0. First implementation of a lock system for concurrent access to a virtual instrument
 */

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <pthread.h>

typedef struct
{
  char VIID[30];
  pthread_mutex_t mutex;
} CacheLockVI;

#define NB_CACHELOCK_VI 30
typedef struct
{
  CacheLockVI cacheLockVI[NB_CACHELOCK_VI];
  pthread_mutex_t mutex;
} CacheLockData;

extern int Verbose;

static CacheLockData* cachelock_data = NULL;

/*
 * Init the shared memory used by the lock system
 */
void CacheLock_Init()
{
   if (cachelock_data != NULL)
      return;

   if(Verbose) fprintf(stderr,"CacheLock_Init\n");

   // place our shared data in shared memory
   int prot = PROT_READ | PROT_WRITE;
   int flags = MAP_SHARED | MAP_ANONYMOUS;
   cachelock_data = mmap(NULL, sizeof(CacheLockData), prot, flags, -1, 0);

   // initialise mutex so it works properly in shared memory

   // global mutex
   pthread_mutexattr_t attr;
   pthread_mutexattr_init(&attr);
   pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
   pthread_mutex_init(&cachelock_data->mutex, &attr);

   int i;
   for (i = 0; i < NB_CACHELOCK_VI; ++i)
   {
      // virtual instrument mutex
      pthread_mutexattr_t attr;
      pthread_mutexattr_init(&attr);
      pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
      pthread_mutex_init(&cachelock_data->cacheLockVI[i].mutex, &attr);
   }
}

/*
 * Free the shared memory used by the lock system
 */
void CacheLock_Free()
{
   if(Verbose) fprintf(stderr,"CacheLock_Free\n");
   if (cachelock_data != NULL)
     munmap(cachelock_data, sizeof(CacheLockData));
   cachelock_data = NULL;
}

/*
 * Get and lock the access to a virtual instrument
 */
void CacheLock_Lock(char* VIID)
{
   if (cachelock_data == NULL)
      return;

   int i;
   pthread_mutex_lock(&cachelock_data->mutex);
   for (i = 0; i < NB_CACHELOCK_VI; ++i)
   {
      if (strcmp(VIID, cachelock_data->cacheLockVI[i].VIID) == 0)
      {
        //A cache lock already exist for this VI
        //Try to get access
        pthread_mutex_lock(&cachelock_data->cacheLockVI[i].mutex);
        if(Verbose) fprintf(stderr,"CacheLock_Lock. %s is locked\n", VIID);
        pthread_mutex_unlock(&cachelock_data->mutex);
        return;
      }
   }
   pthread_mutex_unlock(&cachelock_data->mutex);

   //No cache lock exist for this VI
   //Try to find an available cache lock
   while (1)
   {
     pthread_mutex_lock(&cachelock_data->mutex);
     for (i = 0; i < NB_CACHELOCK_VI; ++i)
     {
        if (pthread_mutex_trylock(&cachelock_data->cacheLockVI[i].mutex) == 0)
        {
           //This cache lock is now used for this VIID
           strcpy(cachelock_data->cacheLockVI[i].VIID, VIID);
           if(Verbose) fprintf(stderr,"CacheLock_Lock. %s is locked\n", VIID);
           pthread_mutex_unlock(&cachelock_data->mutex);
           return;
        }
     }
     //No available cache lock for the moment
     if(Verbose) fprintf(stderr,"CacheLock_Lock. Cannot find an available cache lock for %s => Wait and retry later\n", VIID);
     pthread_mutex_unlock(&cachelock_data->mutex);
     sleep(2);
   }
}

/*
 * Unlock the access to a virtual instrument
 */
void CacheLock_Unlock(char* VIID)
{
   if (cachelock_data == NULL)
      return;

   int i;
   for (i = 0; i < NB_CACHELOCK_VI; ++i)
   {
      if (strcmp(VIID, cachelock_data->cacheLockVI[i].VIID) == 0)
      {
        if(Verbose) fprintf(stderr,"CacheLock_Unlock. %s is unlocked\n", VIID);
        pthread_mutex_unlock(&cachelock_data->cacheLockVI[i].mutex);
        return;
      }
   }
   if(Verbose) fprintf(stderr,"CacheLock_Unlock. Cannot unlock %s\n", VIID);
}