Newer
Older
invertedlogic / InvertedLogic / iLPlatform / iLSemaphore.inl
@John Ryland John Ryland on 10 Nov 2019 3 KB rename
#if 0 // 1

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */

typedef pthread_mutex_t iLMutex;
typedef sem_t           iLSemaphore;

static inline iLResult iLMutex_Create(iLMutex* a_mutex)
{
  pthread_mutex_init(a_mutex, NULL);
  return iLR_OK;
}

static inline iLResult iLMutex_Lock(iLMutex* a_mutex)
{
  pthread_mutex_lock(a_mutex);
  return iLR_OK;
}

static inline iLResult iLMutex_Unlock(iLMutex* a_mutex)
{
  pthread_mutex_unlock(a_mutex);
  return iLR_OK;
}

static inline iLResult iLSemaphore_Create(iLSemaphore* a_sem, uint32_t a_initCount, uint32_t a_maxCount)
{
  a_sem = sem_open("/sem", O_CREAT, S_IRWXU, a_initCount);
  return iLR_OK;
}

static inline iLResult iLSemaphore_Wait(iLSemaphore* a_sem)
{
  sem_wait(a_sem);
  return iLR_OK;
}

static inline iLResult iLSemaphore_Signal(iLSemaphore* a_sem, uint32_t a_count)
{
  for (int i = 0; i < a_count; i++)
    sem_post(a_sem);
  return iLR_OK;
}

#else // My mutex and semaphores

#include "iLAtomics.h"
#include <assert.h>

static inline iLResult iLMutex_Create(iLMutex* a_mutex)
{
  *a_mutex = 0;
  return iLR_OK;
}

//static inline iLResult iLMutex_Lock(iLMutex* a_mutex, int32_t a_maxSpinCount = 100000)
static inline iLResult iLMutex_Lock(iLMutex* a_mutex)
{
  int spinCount = 0;
  while (iLAtomic_CompareAndSwap32(a_mutex, 0, 1) != 0) // keep trying to set a_mutex to 1 until it is zero
  {
    spinCount++;
    if (spinCount > 100000) // a_maxSpinCount)
    {
      spinCount = 0;
      iLThread_Yield();
    }
  }
  return iLR_OK;
}

static inline iLResult iLMutex_Unlock(iLMutex* a_mutex)
{
  uint32_t oldVal = iLAtomic_CompareAndSwap32(a_mutex, 1, 0);
  assert(oldVal == 1); // unlocking a mutex which isn't locked?
  return iLR_OK;
}

static inline iLResult iLCondition_Create(iLCondition* a_cond)
{
  a_cond->waiters = 0;
  a_cond->signaled = 0;
  return iLR_OK;
}

static inline iLResult iLCondition_Wait(iLCondition* a_cond, iLMutex* a_mutex)
{
  // Basically this unlocks the mutex, and then waits for cond to be signaled, then locks the mutex again
  iLAtomic_Increment32(&a_cond->waiters);
  iLMutex_Unlock(a_mutex);
  // waiting here to be signaled - need to be woken but that is not something we can do ourselves
  iLThread_Yield();
  iLMutex_Lock(a_mutex);
  return iLR_OK;
}

static inline iLResult iLCondition_Signal(iLCondition* /*a_cond*/)
{
  // TODO: check there is a waiter to be signalled, if there is, set one signaled, then wait for
  // the waiters to decrease. Really this is a threads implementation feature, but not really
  // implemented as you can plainly see
  return iLR_OK;
}

// Despite condition variables not being fully implemented, this semaphore implementation
// will still work, just somewhat inefficiently as it basically busy waits to be signalled
static inline iLResult iLSemaphore_Create(iLSemaphore* a_sem, uint32_t a_initCount, uint32_t a_maxCount)
{
  a_sem->count = a_initCount;
  a_sem->maxCount = a_maxCount;
  a_sem->waitCount = 0;
  iLMutex_Create(&a_sem->mutex);
  iLCondition_Create(&a_sem->cond);
  return iLR_OK;
}

static inline iLResult iLSemaphore_Wait(iLSemaphore* a_sem)
{
  iLMutex_Lock(&a_sem->mutex);
  while (a_sem->count == 0)
  {
    ++a_sem->waitCount;
    iLCondition_Wait(&a_sem->cond, &a_sem->mutex);
    --a_sem->waitCount;
  }
  --a_sem->count;
  iLMutex_Unlock(&a_sem->mutex);
  return iLR_OK;
}

static inline iLResult iLSemaphore_Signal(iLSemaphore* a_sem, uint32_t a_count)
{
  iLMutex_Lock(&a_sem->mutex);
  a_sem->count += a_count;
  if (a_sem->count > a_sem->maxCount)
  {
    a_sem->count = a_sem->maxCount;
  }
  if (a_sem->waitCount > 0)
  {   
    iLCondition_Signal(&a_sem->cond);
  }
  iLMutex_Unlock(&a_sem->mutex);
  return iLR_OK;
}

#endif