Ejemplo n.º 1
0
// "Increment" the value of a semaphore atomically and
// return its old value. Note that this implements
// the special case of "incrementing" any negative
// value to +1 directly.
//
// NOTE: The value will _not_ wrap above SEM_VALUE_MAX
static int __sem_inc(atomic_uint* sem_count_ptr) {
  unsigned int old_value = atomic_load_explicit(sem_count_ptr, memory_order_relaxed);
  unsigned int shared = old_value  & SEMCOUNT_SHARED_MASK;
  unsigned int new_value;

  // Use memory_order_seq_cst in atomic_compare_exchange operation to ensure all
  // memory access made before can be seen in other threads.
  // A release fence may be sufficient, but it is still in discussion whether
  // POSIX semaphores should provide sequential consistency.
  do {
    // Can't go higher than SEM_VALUE_MAX.
    if (SEMCOUNT_TO_VALUE(old_value) == SEM_VALUE_MAX) {
      break;
    }

    // If the counter is negative, go directly to one, otherwise just increment.
    if (SEMCOUNT_TO_VALUE(old_value) < 0) {
      new_value = SEMCOUNT_ONE | shared;
    } else {
      new_value = SEMCOUNT_INCREMENT(old_value) | shared;
    }
  } while (!atomic_compare_exchange_weak(sem_count_ptr, &old_value,
           new_value));

  return SEMCOUNT_TO_VALUE(old_value);
}
Ejemplo n.º 2
0
// Same as __sem_dec, but will not touch anything if the
// value is already negative *or* 0. Returns the old value.
static int __sem_trydec(atomic_uint* sem_count_ptr) {
  unsigned int old_value = atomic_load_explicit(sem_count_ptr, memory_order_relaxed);
  unsigned int shared = old_value & SEMCOUNT_SHARED_MASK;

  // Use memory_order_seq_cst in atomic_compare_exchange operation to ensure all
  // memory access made by other threads can be seen in current thread.
  // An acquire fence may be sufficient, but it is still in discussion whether
  // POSIX semaphores should provide sequential consistency.
  do {
    if (SEMCOUNT_TO_VALUE(old_value) <= 0) {
      break;
    }
  } while (!atomic_compare_exchange_weak(sem_count_ptr, &old_value,
           SEMCOUNT_DECREMENT(old_value) | shared));

  return SEMCOUNT_TO_VALUE(old_value);
}
Ejemplo n.º 3
0
int sem_getvalue(sem_t* sem, int* sval) {
  atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem);

  // Use memory_order_seq_cst in atomic_load operation.
  // memory_order_relaxed may be fine here, but it is still in discussion
  // whether POSIX semaphores should provide sequential consistency.
  int val = SEMCOUNT_TO_VALUE(atomic_load(sem_count_ptr));
  if (val < 0) {
    val = 0;
  }

  *sval = val;
  return 0;
}
Ejemplo n.º 4
0
int sem_destroy(sem_t *sem)
{
    int count;

    if (sem == NULL) {
        errno = EINVAL;
        return -1;
    }
    count = SEMCOUNT_TO_VALUE(sem->count);
    if (count < 0) {
        errno = EBUSY;
        return -1;
    }
    sem->count = 0;
    return 0;
}