packages feed

interprocess-0.2.1.0: src/Control/Concurrent/Process/QSem.c

#include <common.h>


typedef struct QSem QSem;

QSem *qsem_new(HsInt count);
QSem *qsem_lookup(const char *name);
void  qsem_close(QSem *qsem);
int   qsem_signal(QSem *qsem);
int   qsem_wait(QSem *qsem);
int   qsem_trywait(QSem *qsem);
void  qsem_name(QSem *qsem, char * const name);



#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(mingw32_HOST_OS)
#include <windows.h>
#include <limits.h>

typedef struct QSem {
  HANDLE            mainSem;
  SharedObjectName  mainName;
} QSem;

QSem *qsem_new(HsInt count) {
  QSem *r = malloc(sizeof(QSem));
  if (r == NULL) {
    return NULL;
  }
  genSharedObjectName(r->mainName);

  HANDLE semPtr = CreateSemaphoreA( NULL, (LONG)count, LONG_MAX, r->mainName );

  if (semPtr == NULL) {
    free(r);
    return NULL;
  }

  r->mainSem = semPtr;
  return r;
}

QSem *qsem_lookup(const char *name) {
  QSem *r = malloc(sizeof(QSem));
  if (r == NULL) {
    return NULL;
  }

  HANDLE semPtr = OpenSemaphoreA( SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, TRUE, name );

  if (semPtr == NULL) {
    free(r);
    return NULL;
  }

  r->mainSem = semPtr;
  strcpy(r->mainName, name);
  return r;
}

void qsem_close(QSem *qsem) {
  CloseHandle(qsem->mainSem);
  free(qsem);
}

int qsem_signal(QSem *qsem) {
  return (ReleaseSemaphore(qsem->mainSem, 1, NULL) == 0);
}

int qsem_wait(QSem *qsem) {
  return (WaitForSingleObject(qsem->mainSem, INFINITE) != WAIT_OBJECT_0);
}

int qsem_trywait(QSem *qsem) {
  return (WaitForSingleObject(qsem->mainSem, 0) != WAIT_OBJECT_0);
}


void qsem_name(QSem *qsem, char * const name) {
  strcpy(name, qsem->mainName);
}


#else
#include <fcntl.h>           /* For O_* constants */
#include <semaphore.h>
#include <string.h>

#define GuardNameSuffix "X"

typedef struct QSem {
  sem_t            *mainSem;
  sem_t            *guardSem;
  /*  Second semaphore is used to count number of
      extra users.
      That is, the quantity of a guardSem is (N-1) where N is number of processes
      currently having the semaphore initialized.
      When executing qsem_close, sem_trywait result defines if the semaphore
      should be unlinked or not.
   */
  SharedObjectName  mainName;
} QSem;

QSem *qsem_new(HsInt count) {
  QSem *r = malloc(sizeof(QSem));
  if (r == NULL) {
    return NULL;
  }
  genSharedObjectName(r->mainName);

  sem_t *mPtr = sem_open (r->mainName, O_CREAT | O_EXCL, 0600, count);
  if (mPtr == SEM_FAILED) {
    free(r);
    return NULL;
  }
  SharedObjectName guardName = {0};
  strcpy (guardName, r->mainName);
  strcat (guardName, GuardNameSuffix);
  sem_t *cPtr = sem_open (guardName, O_CREAT | O_EXCL, 0600, 0);
  if (mPtr == SEM_FAILED) {
    free(r);
    if (sem_close(mPtr) == 0){
      sem_unlink(r->mainName);
    }
    return NULL;
  }
  r->mainSem = mPtr;
  r->guardSem = cPtr;
  return r;
}

QSem *qsem_lookup(const char *name) {
  QSem *r = malloc(sizeof(QSem));
  if (r == NULL) {
    return NULL;
  }
  sem_t *mPtr = sem_open (name, 0);
  if (mPtr == SEM_FAILED) {
    free(r);
    return NULL;
  }
  SharedObjectName guardName = {0};
  strcpy (guardName, name);
  strcat (guardName, GuardNameSuffix);
  sem_t *cPtr = sem_open (guardName, 0);
  if (mPtr == SEM_FAILED || sem_post(cPtr) != 0) {
    free(r);
    sem_close(mPtr); // don't unlink semaphore in case it is used somewhere else.
    return NULL;
  }
  r->mainSem = mPtr;
  r->guardSem = cPtr;
  strcpy(r->mainName, name);
  return r;
}

void qsem_close(QSem *qsem) {
  sem_close(qsem->mainSem);
  if ( sem_trywait(qsem->guardSem) != 0 ) {
    sem_unlink(qsem->mainName);
    sem_close(qsem->guardSem);
    SharedObjectName guardName = {0};
    strcpy (guardName, qsem->mainName);
    strcat (guardName, GuardNameSuffix);
    sem_unlink(guardName);
  } else {
    sem_close(qsem->guardSem);
  }
  free(qsem);
}

int qsem_signal(QSem *qsem) {
  return sem_post(qsem->mainSem);
}

int qsem_wait(QSem *qsem) {
  return sem_wait(qsem->mainSem);
}

int qsem_trywait(QSem *qsem) {
  return sem_trywait(qsem->mainSem);
}

void qsem_name(QSem *qsem, char * const name) {
  strcpy(name, qsem->mainName);
}


#endif