am 413de5b0: Merge "Add semaphore tests, fix sem_destroy."
				
					
				
			* commit '413de5b0d4ddcf039aaef8b40a5f02d41dbb06e6': Add semaphore tests, fix sem_destroy.
This commit is contained in:
		@@ -53,7 +53,6 @@ libc_common_src_files := \
 | 
				
			|||||||
    bionic/pututline.c \
 | 
					    bionic/pututline.c \
 | 
				
			||||||
    bionic/sched_cpualloc.c \
 | 
					    bionic/sched_cpualloc.c \
 | 
				
			||||||
    bionic/sched_cpucount.c \
 | 
					    bionic/sched_cpucount.c \
 | 
				
			||||||
    bionic/semaphore.c \
 | 
					 | 
				
			||||||
    bionic/sigblock.c \
 | 
					    bionic/sigblock.c \
 | 
				
			||||||
    bionic/siginterrupt.c \
 | 
					    bionic/siginterrupt.c \
 | 
				
			||||||
    bionic/sigsetmask.c \
 | 
					    bionic/sigsetmask.c \
 | 
				
			||||||
@@ -182,6 +181,7 @@ libc_bionic_src_files := \
 | 
				
			|||||||
    bionic/scandir.cpp \
 | 
					    bionic/scandir.cpp \
 | 
				
			||||||
    bionic/sched_getaffinity.cpp \
 | 
					    bionic/sched_getaffinity.cpp \
 | 
				
			||||||
    bionic/sched_getcpu.cpp \
 | 
					    bionic/sched_getcpu.cpp \
 | 
				
			||||||
 | 
					    bionic/semaphore.cpp \
 | 
				
			||||||
    bionic/send.cpp \
 | 
					    bionic/send.cpp \
 | 
				
			||||||
    bionic/setegid.cpp \
 | 
					    bionic/setegid.cpp \
 | 
				
			||||||
    bionic/__set_errno.cpp \
 | 
					    bionic/__set_errno.cpp \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "private/bionic_time_conversions.h"
 | 
					#include "private/bionic_time_conversions.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "private/bionic_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool timespec_from_timeval(timespec& ts, const timeval& tv) {
 | 
					bool timespec_from_timeval(timespec& ts, const timeval& tv) {
 | 
				
			||||||
  // Whole seconds can just be copied.
 | 
					  // Whole seconds can just be copied.
 | 
				
			||||||
  ts.tv_sec = tv.tv_sec;
 | 
					  ts.tv_sec = tv.tv_sec;
 | 
				
			||||||
@@ -49,3 +51,19 @@ void timeval_from_timespec(timeval& tv, const timespec& ts) {
 | 
				
			|||||||
  tv.tv_sec = ts.tv_sec;
 | 
					  tv.tv_sec = ts.tv_sec;
 | 
				
			||||||
  tv.tv_usec = ts.tv_nsec / 1000;
 | 
					  tv.tv_usec = ts.tv_nsec / 1000;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Initializes 'ts' with the difference between 'abs_ts' and the current time
 | 
				
			||||||
 | 
					// according to 'clock'. Returns false if abstime already expired, true otherwise.
 | 
				
			||||||
 | 
					bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock) {
 | 
				
			||||||
 | 
					  clock_gettime(clock, &ts);
 | 
				
			||||||
 | 
					  ts.tv_sec = abs_ts.tv_sec - ts.tv_sec;
 | 
				
			||||||
 | 
					  ts.tv_nsec = abs_ts.tv_nsec - ts.tv_nsec;
 | 
				
			||||||
 | 
					  if (ts.tv_nsec < 0) {
 | 
				
			||||||
 | 
					    ts.tv_sec--;
 | 
				
			||||||
 | 
					    ts.tv_nsec += NS_PER_S;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (ts.tv_nsec < 0 || ts.tv_sec < 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -163,12 +163,12 @@ int __pthread_cond_timedwait_relative(pthread_cond_t* cond, pthread_mutex_t* mut
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__LIBC_HIDDEN__
 | 
					__LIBC_HIDDEN__
 | 
				
			||||||
int __pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abstime, clockid_t clock) {
 | 
					int __pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abs_ts, clockid_t clock) {
 | 
				
			||||||
  timespec ts;
 | 
					  timespec ts;
 | 
				
			||||||
  timespec* tsp;
 | 
					  timespec* tsp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (abstime != NULL) {
 | 
					  if (abs_ts != NULL) {
 | 
				
			||||||
    if (__timespec_from_absolute(&ts, abstime, clock) < 0) {
 | 
					    if (!timespec_from_absolute_timespec(ts, *abs_ts, clock)) {
 | 
				
			||||||
      return ETIMEDOUT;
 | 
					      return ETIMEDOUT;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    tsp = &ts;
 | 
					    tsp = &ts;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,8 +117,6 @@ __LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread)
 | 
				
			|||||||
__LIBC_HIDDEN__ extern pthread_internal_t* g_thread_list;
 | 
					__LIBC_HIDDEN__ extern pthread_internal_t* g_thread_list;
 | 
				
			||||||
__LIBC_HIDDEN__ extern pthread_mutex_t g_thread_list_lock;
 | 
					__LIBC_HIDDEN__ extern pthread_mutex_t g_thread_list_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__LIBC_HIDDEN__ int __timespec_from_absolute(timespec*, const timespec*, clockid_t);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Needed by fork. */
 | 
					/* Needed by fork. */
 | 
				
			||||||
__LIBC_HIDDEN__ extern void __bionic_atfork_run_prepare();
 | 
					__LIBC_HIDDEN__ extern void __bionic_atfork_run_prepare();
 | 
				
			||||||
__LIBC_HIDDEN__ extern void __bionic_atfork_run_child();
 | 
					__LIBC_HIDDEN__ extern void __bionic_atfork_run_child();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,19 +67,3 @@ void _pthread_internal_add(pthread_internal_t* thread) {
 | 
				
			|||||||
pthread_internal_t* __get_thread(void) {
 | 
					pthread_internal_t* __get_thread(void) {
 | 
				
			||||||
  return reinterpret_cast<pthread_internal_t*>(__get_tls()[TLS_SLOT_THREAD_ID]);
 | 
					  return reinterpret_cast<pthread_internal_t*>(__get_tls()[TLS_SLOT_THREAD_ID]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// Initialize 'ts' with the difference between 'abstime' and the current time
 | 
					 | 
				
			||||||
// according to 'clock'. Returns -1 if abstime already expired, or 0 otherwise.
 | 
					 | 
				
			||||||
int __timespec_from_absolute(timespec* ts, const timespec* abstime, clockid_t clock) {
 | 
					 | 
				
			||||||
  clock_gettime(clock, ts);
 | 
					 | 
				
			||||||
  ts->tv_sec  = abstime->tv_sec - ts->tv_sec;
 | 
					 | 
				
			||||||
  ts->tv_nsec = abstime->tv_nsec - ts->tv_nsec;
 | 
					 | 
				
			||||||
  if (ts->tv_nsec < 0) {
 | 
					 | 
				
			||||||
    ts->tv_sec--;
 | 
					 | 
				
			||||||
    ts->tv_nsec += 1000000000;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if ((ts->tv_nsec < 0) || (ts->tv_sec < 0)) {
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,7 +36,9 @@
 | 
				
			|||||||
#include "pthread_internal.h"
 | 
					#include "pthread_internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "private/bionic_atomic_inline.h"
 | 
					#include "private/bionic_atomic_inline.h"
 | 
				
			||||||
 | 
					#include "private/bionic_constants.h"
 | 
				
			||||||
#include "private/bionic_futex.h"
 | 
					#include "private/bionic_futex.h"
 | 
				
			||||||
 | 
					#include "private/bionic_time_conversions.h"
 | 
				
			||||||
#include "private/bionic_tls.h"
 | 
					#include "private/bionic_tls.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "private/bionic_systrace.h"
 | 
					#include "private/bionic_systrace.h"
 | 
				
			||||||
@@ -615,7 +617,7 @@ int pthread_mutex_trylock(pthread_mutex_t* mutex) {
 | 
				
			|||||||
    return EBUSY;
 | 
					    return EBUSY;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs_timeout, clockid_t clock) {
 | 
					static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs_ts, clockid_t clock) {
 | 
				
			||||||
  timespec ts;
 | 
					  timespec ts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int mvalue = mutex->value;
 | 
					  int mvalue = mutex->value;
 | 
				
			||||||
@@ -638,7 +640,7 @@ static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Loop while needed.
 | 
					    // Loop while needed.
 | 
				
			||||||
    while (__bionic_swap(locked_contended, &mutex->value) != unlocked) {
 | 
					    while (__bionic_swap(locked_contended, &mutex->value) != unlocked) {
 | 
				
			||||||
      if (__timespec_from_absolute(&ts, abs_timeout, clock) < 0) {
 | 
					      if (!timespec_from_absolute_timespec(ts, *abs_ts, clock)) {
 | 
				
			||||||
        return ETIMEDOUT;
 | 
					        return ETIMEDOUT;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      __futex_wait_ex(&mutex->value, shared, locked_contended, &ts);
 | 
					      __futex_wait_ex(&mutex->value, shared, locked_contended, &ts);
 | 
				
			||||||
@@ -681,7 +683,7 @@ static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      // The value changed before we could lock it. We need to check
 | 
					      // The value changed before we could lock it. We need to check
 | 
				
			||||||
      // the time to avoid livelocks, reload the value, then loop again.
 | 
					      // the time to avoid livelocks, reload the value, then loop again.
 | 
				
			||||||
      if (__timespec_from_absolute(&ts, abs_timeout, clock) < 0) {
 | 
					      if (!timespec_from_absolute_timespec(ts, *abs_ts, clock)) {
 | 
				
			||||||
        return ETIMEDOUT;
 | 
					        return ETIMEDOUT;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -703,7 +705,7 @@ static int __pthread_mutex_timedlock(pthread_mutex_t* mutex, const timespec* abs
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Check time and update 'ts'.
 | 
					    // Check time and update 'ts'.
 | 
				
			||||||
    if (__timespec_from_absolute(&ts, abs_timeout, clock) < 0) {
 | 
					    if (timespec_from_absolute_timespec(ts, *abs_ts, clock)) {
 | 
				
			||||||
      return ETIMEDOUT;
 | 
					      return ETIMEDOUT;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -726,9 +728,9 @@ extern "C" int pthread_mutex_lock_timeout_np(pthread_mutex_t* mutex, unsigned ms
 | 
				
			|||||||
  clock_gettime(CLOCK_MONOTONIC, &abs_timeout);
 | 
					  clock_gettime(CLOCK_MONOTONIC, &abs_timeout);
 | 
				
			||||||
  abs_timeout.tv_sec  += ms / 1000;
 | 
					  abs_timeout.tv_sec  += ms / 1000;
 | 
				
			||||||
  abs_timeout.tv_nsec += (ms % 1000) * 1000000;
 | 
					  abs_timeout.tv_nsec += (ms % 1000) * 1000000;
 | 
				
			||||||
  if (abs_timeout.tv_nsec >= 1000000000) {
 | 
					  if (abs_timeout.tv_nsec >= NS_PER_S) {
 | 
				
			||||||
    abs_timeout.tv_sec++;
 | 
					    abs_timeout.tv_sec++;
 | 
				
			||||||
    abs_timeout.tv_nsec -= 1000000000;
 | 
					    abs_timeout.tv_nsec -= NS_PER_S;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int error = __pthread_mutex_timedlock(mutex, &abs_timeout, CLOCK_MONOTONIC);
 | 
					  int error = __pthread_mutex_timedlock(mutex, &abs_timeout, CLOCK_MONOTONIC);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "pthread_internal.h"
 | 
					#include "pthread_internal.h"
 | 
				
			||||||
#include "private/bionic_futex.h"
 | 
					#include "private/bionic_futex.h"
 | 
				
			||||||
 | 
					#include "private/bionic_time_conversions.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Technical note:
 | 
					/* Technical note:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -71,7 +72,7 @@ static inline bool rwlock_is_shared(const pthread_rwlock_t* rwlock) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static bool timespec_from_absolute(timespec* rel_timeout, const timespec* abs_timeout) {
 | 
					static bool timespec_from_absolute(timespec* rel_timeout, const timespec* abs_timeout) {
 | 
				
			||||||
  if (abs_timeout != NULL) {
 | 
					  if (abs_timeout != NULL) {
 | 
				
			||||||
    if (__timespec_from_absolute(rel_timeout, abs_timeout, CLOCK_REALTIME) < 0) {
 | 
					    if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout, CLOCK_REALTIME)) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,398 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2008 The Android Open Source Project
 | 
					 | 
				
			||||||
 * All rights reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Redistribution and use in source and binary forms, with or without
 | 
					 | 
				
			||||||
 * modification, are permitted provided that the following conditions
 | 
					 | 
				
			||||||
 * are met:
 | 
					 | 
				
			||||||
 *  * Redistributions of source code must retain the above copyright
 | 
					 | 
				
			||||||
 *    notice, this list of conditions and the following disclaimer.
 | 
					 | 
				
			||||||
 *  * Redistributions in binary form must reproduce the above copyright
 | 
					 | 
				
			||||||
 *    notice, this list of conditions and the following disclaimer in
 | 
					 | 
				
			||||||
 *    the documentation and/or other materials provided with the
 | 
					 | 
				
			||||||
 *    distribution.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
					 | 
				
			||||||
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
					 | 
				
			||||||
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
					 | 
				
			||||||
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
					 | 
				
			||||||
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
					 | 
				
			||||||
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
					 | 
				
			||||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 | 
					 | 
				
			||||||
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | 
					 | 
				
			||||||
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
					 | 
				
			||||||
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
					 | 
				
			||||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
					 | 
				
			||||||
 * SUCH DAMAGE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#include <semaphore.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <sys/time.h>
 | 
					 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <limits.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "private/bionic_atomic_inline.h"
 | 
					 | 
				
			||||||
#include "private/bionic_futex.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* In this implementation, a semaphore contains a
 | 
					 | 
				
			||||||
 * 31-bit signed value and a 1-bit 'shared' flag
 | 
					 | 
				
			||||||
 * (for process-sharing purpose).
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * We use the value -1 to indicate contention on the
 | 
					 | 
				
			||||||
 * semaphore, 0 or more to indicate uncontended state,
 | 
					 | 
				
			||||||
 * any value lower than -2 is invalid at runtime.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * State diagram:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * post(1)  ==> 2
 | 
					 | 
				
			||||||
 * post(0)  ==> 1
 | 
					 | 
				
			||||||
 * post(-1) ==> 1, then wake all waiters
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * wait(2)  ==> 1
 | 
					 | 
				
			||||||
 * wait(1)  ==> 0
 | 
					 | 
				
			||||||
 * wait(0)  ==> -1 then wait for a wake up + loop
 | 
					 | 
				
			||||||
 * wait(-1) ==> -1 then wait for a wake up + loop
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Use the upper 31-bits for the counter, and the lower one
 | 
					 | 
				
			||||||
 * for the shared flag.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define SEMCOUNT_SHARED_MASK      0x00000001
 | 
					 | 
				
			||||||
#define SEMCOUNT_VALUE_MASK       0xfffffffe
 | 
					 | 
				
			||||||
#define SEMCOUNT_VALUE_SHIFT      1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Maximum unsigned value that can be stored in the semaphore.
 | 
					 | 
				
			||||||
 * One bit is used for the shared flag, another one for the
 | 
					 | 
				
			||||||
 * sign bit, leaving us with only 30 bits.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define SEM_MAX_VALUE             0x3fffffff
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* convert a value into the corresponding sem->count bit pattern */
 | 
					 | 
				
			||||||
#define SEMCOUNT_FROM_VALUE(val)    (((val) << SEMCOUNT_VALUE_SHIFT) & SEMCOUNT_VALUE_MASK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* convert a sem->count bit pattern into the corresponding signed value */
 | 
					 | 
				
			||||||
#define SEMCOUNT_TO_VALUE(sval)  ((int)(sval) >> SEMCOUNT_VALUE_SHIFT)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* the value +1 as a sem->count bit-pattern. */
 | 
					 | 
				
			||||||
#define SEMCOUNT_ONE              SEMCOUNT_FROM_VALUE(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* the value -1 as a sem->count bit-pattern. */
 | 
					 | 
				
			||||||
#define SEMCOUNT_MINUS_ONE        SEMCOUNT_FROM_VALUE(-1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SEMCOUNT_DECREMENT(sval)    (((sval) - (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
 | 
					 | 
				
			||||||
#define SEMCOUNT_INCREMENT(sval)    (((sval) + (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* return the shared bitflag from a semaphore */
 | 
					 | 
				
			||||||
#define SEM_GET_SHARED(sem)       ((sem)->count & SEMCOUNT_SHARED_MASK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int sem_init(sem_t *sem, int pshared, unsigned int value)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (sem == NULL) {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* ensure that 'value' can be stored in the semaphore */
 | 
					 | 
				
			||||||
    if (value > SEM_MAX_VALUE) {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sem->count = SEMCOUNT_FROM_VALUE(value);
 | 
					 | 
				
			||||||
    if (pshared != 0)
 | 
					 | 
				
			||||||
        sem->count |= SEMCOUNT_SHARED_MASK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sem_t *sem_open(const char *name __unused, int oflag __unused, ...)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    errno = ENOSYS;
 | 
					 | 
				
			||||||
    return SEM_FAILED;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int sem_close(sem_t *sem)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (sem == NULL) {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    errno = ENOSYS;
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int sem_unlink(const char* name __unused)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    errno = ENOSYS;
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Decrement a semaphore's value atomically,
 | 
					 | 
				
			||||||
 * and return the old one. As a special case,
 | 
					 | 
				
			||||||
 * this returns immediately if the value is
 | 
					 | 
				
			||||||
 * negative (i.e. -1)
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
__sem_dec(volatile unsigned int *pvalue)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned int shared = (*pvalue & SEMCOUNT_SHARED_MASK);
 | 
					 | 
				
			||||||
    unsigned int old, new;
 | 
					 | 
				
			||||||
    int          ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    do {
 | 
					 | 
				
			||||||
        old = (*pvalue & SEMCOUNT_VALUE_MASK);
 | 
					 | 
				
			||||||
        ret = SEMCOUNT_TO_VALUE(old);
 | 
					 | 
				
			||||||
        if (ret < 0)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        new = SEMCOUNT_DECREMENT(old);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    while (__bionic_cmpxchg((int)(old|shared),
 | 
					 | 
				
			||||||
                            (int)(new|shared),
 | 
					 | 
				
			||||||
                            (volatile int *)pvalue) != 0);
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 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(volatile unsigned int *pvalue)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned int shared = (*pvalue & SEMCOUNT_SHARED_MASK);
 | 
					 | 
				
			||||||
    unsigned int old, new;
 | 
					 | 
				
			||||||
    int          ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    do {
 | 
					 | 
				
			||||||
        old = (*pvalue & SEMCOUNT_VALUE_MASK);
 | 
					 | 
				
			||||||
        ret = SEMCOUNT_TO_VALUE(old);
 | 
					 | 
				
			||||||
        if (ret <= 0)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        new = SEMCOUNT_DECREMENT(old);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    while (__bionic_cmpxchg((int)(old|shared),
 | 
					 | 
				
			||||||
                            (int)(new|shared),
 | 
					 | 
				
			||||||
                            (volatile int *)pvalue) != 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* "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(volatile unsigned int *pvalue)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned int  shared = (*pvalue & SEMCOUNT_SHARED_MASK);
 | 
					 | 
				
			||||||
    unsigned int  old, new;
 | 
					 | 
				
			||||||
    int           ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    do {
 | 
					 | 
				
			||||||
        old = (*pvalue & SEMCOUNT_VALUE_MASK);
 | 
					 | 
				
			||||||
        ret = SEMCOUNT_TO_VALUE(old);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Can't go higher than SEM_MAX_VALUE */
 | 
					 | 
				
			||||||
        if (ret == SEM_MAX_VALUE)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* If the counter is negative, go directly to +1,
 | 
					 | 
				
			||||||
         * otherwise just increment */
 | 
					 | 
				
			||||||
        if (ret < 0)
 | 
					 | 
				
			||||||
            new = SEMCOUNT_ONE;
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            new = SEMCOUNT_INCREMENT(old);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    while ( __bionic_cmpxchg((int)(old|shared),
 | 
					 | 
				
			||||||
                             (int)(new|shared),
 | 
					 | 
				
			||||||
                             (volatile int*)pvalue) != 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* lock a semaphore */
 | 
					 | 
				
			||||||
int sem_wait(sem_t *sem)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned shared;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (sem == NULL) {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    shared = SEM_GET_SHARED(sem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (;;) {
 | 
					 | 
				
			||||||
        if (__sem_dec(&sem->count) > 0)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        __futex_wait_ex(&sem->count, shared, shared|SEMCOUNT_MINUS_ONE, NULL);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    ANDROID_MEMBAR_FULL();
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned int shared;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (sem == NULL) {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* POSIX says we need to try to decrement the semaphore
 | 
					 | 
				
			||||||
     * before checking the timeout value. Note that if the
 | 
					 | 
				
			||||||
     * value is currently 0, __sem_trydec() does nothing.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    if (__sem_trydec(&sem->count) > 0) {
 | 
					 | 
				
			||||||
        ANDROID_MEMBAR_FULL();
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Check it as per Posix */
 | 
					 | 
				
			||||||
    if (abs_timeout == NULL    ||
 | 
					 | 
				
			||||||
        abs_timeout->tv_sec < 0 ||
 | 
					 | 
				
			||||||
        abs_timeout->tv_nsec < 0 ||
 | 
					 | 
				
			||||||
        abs_timeout->tv_nsec >= 1000000000)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    shared = SEM_GET_SHARED(sem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (;;) {
 | 
					 | 
				
			||||||
        struct timespec ts;
 | 
					 | 
				
			||||||
        int             ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Posix mandates CLOCK_REALTIME here */
 | 
					 | 
				
			||||||
        clock_gettime( CLOCK_REALTIME, &ts );
 | 
					 | 
				
			||||||
        ts.tv_sec  = abs_timeout->tv_sec - ts.tv_sec;
 | 
					 | 
				
			||||||
        ts.tv_nsec = abs_timeout->tv_nsec - ts.tv_nsec;
 | 
					 | 
				
			||||||
        if (ts.tv_nsec < 0) {
 | 
					 | 
				
			||||||
            ts.tv_nsec += 1000000000;
 | 
					 | 
				
			||||||
            ts.tv_sec  -= 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (ts.tv_sec < 0 || ts.tv_nsec < 0) {
 | 
					 | 
				
			||||||
            errno = ETIMEDOUT;
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Try to grab the semaphore. If the value was 0, this
 | 
					 | 
				
			||||||
         * will also change it to -1 */
 | 
					 | 
				
			||||||
        if (__sem_dec(&sem->count) > 0) {
 | 
					 | 
				
			||||||
            ANDROID_MEMBAR_FULL();
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Contention detected. wait for a wakeup event */
 | 
					 | 
				
			||||||
        ret = __futex_wait_ex(&sem->count, shared, shared|SEMCOUNT_MINUS_ONE, &ts);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* return in case of timeout or interrupt */
 | 
					 | 
				
			||||||
        if (ret == -ETIMEDOUT || ret == -EINTR) {
 | 
					 | 
				
			||||||
            errno = -ret;
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Unlock a semaphore */
 | 
					 | 
				
			||||||
int sem_post(sem_t *sem)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned int shared;
 | 
					 | 
				
			||||||
    int          old;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (sem == NULL)
 | 
					 | 
				
			||||||
        return EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    shared = SEM_GET_SHARED(sem);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ANDROID_MEMBAR_FULL();
 | 
					 | 
				
			||||||
    old = __sem_inc(&sem->count);
 | 
					 | 
				
			||||||
    if (old < 0) {
 | 
					 | 
				
			||||||
        /* contention on the semaphore, wake up all waiters */
 | 
					 | 
				
			||||||
        __futex_wake_ex(&sem->count, shared, INT_MAX);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else if (old == SEM_MAX_VALUE) {
 | 
					 | 
				
			||||||
        /* overflow detected */
 | 
					 | 
				
			||||||
        errno = EOVERFLOW;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int  sem_trywait(sem_t *sem)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (sem == NULL) {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (__sem_trydec(&sem->count) > 0) {
 | 
					 | 
				
			||||||
        ANDROID_MEMBAR_FULL();
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        errno = EAGAIN;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Note that Posix requires that sem_getvalue() returns, in
 | 
					 | 
				
			||||||
 * case of contention, the negative of the number of waiting
 | 
					 | 
				
			||||||
 * threads.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * However, code that depends on this negative value to be
 | 
					 | 
				
			||||||
 * meaningful is most probably racy. The GLibc sem_getvalue()
 | 
					 | 
				
			||||||
 * only returns the semaphore value, which is 0, in case of
 | 
					 | 
				
			||||||
 * contention, so we will mimick this behaviour here instead
 | 
					 | 
				
			||||||
 * for better compatibility.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int  sem_getvalue(sem_t *sem, int *sval)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int  val;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (sem == NULL || sval == NULL) {
 | 
					 | 
				
			||||||
        errno = EINVAL;
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val = SEMCOUNT_TO_VALUE(sem->count);
 | 
					 | 
				
			||||||
    if (val < 0)
 | 
					 | 
				
			||||||
        val = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    *sval = val;
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										322
									
								
								libc/bionic/semaphore.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								libc/bionic/semaphore.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,322 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2008 The Android Open Source Project
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions
 | 
				
			||||||
 | 
					 * are met:
 | 
				
			||||||
 | 
					 *  * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *  * Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer in
 | 
				
			||||||
 | 
					 *    the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					 *    distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
				
			||||||
 | 
					 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
				
			||||||
 | 
					 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 | 
				
			||||||
 | 
					 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | 
				
			||||||
 | 
					 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
				
			||||||
 | 
					 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
				
			||||||
 | 
					 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <semaphore.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <sys/time.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "private/bionic_atomic_inline.h"
 | 
				
			||||||
 | 
					#include "private/bionic_constants.h"
 | 
				
			||||||
 | 
					#include "private/bionic_futex.h"
 | 
				
			||||||
 | 
					#include "private/bionic_time_conversions.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// In this implementation, a semaphore contains a
 | 
				
			||||||
 | 
					// 31-bit signed value and a 1-bit 'shared' flag
 | 
				
			||||||
 | 
					// (for process-sharing purpose).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// We use the value -1 to indicate contention on the
 | 
				
			||||||
 | 
					// semaphore, 0 or more to indicate uncontended state,
 | 
				
			||||||
 | 
					// any value lower than -2 is invalid at runtime.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// State diagram:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// post(1)  ==> 2
 | 
				
			||||||
 | 
					// post(0)  ==> 1
 | 
				
			||||||
 | 
					// post(-1) ==> 1, then wake all waiters
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// wait(2)  ==> 1
 | 
				
			||||||
 | 
					// wait(1)  ==> 0
 | 
				
			||||||
 | 
					// wait(0)  ==> -1 then wait for a wake up + loop
 | 
				
			||||||
 | 
					// wait(-1) ==> -1 then wait for a wake up + loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Use the upper 31-bits for the counter, and the lower one
 | 
				
			||||||
 | 
					// for the shared flag.
 | 
				
			||||||
 | 
					#define SEMCOUNT_SHARED_MASK      0x00000001
 | 
				
			||||||
 | 
					#define SEMCOUNT_VALUE_MASK       0xfffffffe
 | 
				
			||||||
 | 
					#define SEMCOUNT_VALUE_SHIFT      1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convert a value into the corresponding sem->count bit pattern.
 | 
				
			||||||
 | 
					#define SEMCOUNT_FROM_VALUE(val)    (((val) << SEMCOUNT_VALUE_SHIFT) & SEMCOUNT_VALUE_MASK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convert a sem->count bit pattern into the corresponding signed value.
 | 
				
			||||||
 | 
					static inline int SEMCOUNT_TO_VALUE(uint32_t sval) {
 | 
				
			||||||
 | 
					  return (static_cast<int>(sval) >> SEMCOUNT_VALUE_SHIFT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The value +1 as a sem->count bit-pattern.
 | 
				
			||||||
 | 
					#define SEMCOUNT_ONE              SEMCOUNT_FROM_VALUE(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The value -1 as a sem->count bit-pattern.
 | 
				
			||||||
 | 
					#define SEMCOUNT_MINUS_ONE        SEMCOUNT_FROM_VALUE(-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SEMCOUNT_DECREMENT(sval)    (((sval) - (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
 | 
				
			||||||
 | 
					#define SEMCOUNT_INCREMENT(sval)    (((sval) + (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Return the shared bitflag from a semaphore.
 | 
				
			||||||
 | 
					static inline uint32_t SEM_GET_SHARED(sem_t* sem) {
 | 
				
			||||||
 | 
					  return (sem->count & SEMCOUNT_SHARED_MASK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_init(sem_t* sem, int pshared, unsigned int value) {
 | 
				
			||||||
 | 
					  if (sem == NULL) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Ensure that 'value' can be stored in the semaphore.
 | 
				
			||||||
 | 
					  if (value > SEM_VALUE_MAX) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  sem->count = SEMCOUNT_FROM_VALUE(value);
 | 
				
			||||||
 | 
					  if (pshared != 0) {
 | 
				
			||||||
 | 
					    sem->count |= SEMCOUNT_SHARED_MASK;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_destroy(sem_t* sem) {
 | 
				
			||||||
 | 
					  if (sem == NULL) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sem_t* sem_open(const char*, int, ...) {
 | 
				
			||||||
 | 
					  errno = ENOSYS;
 | 
				
			||||||
 | 
					  return SEM_FAILED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_close(sem_t*) {
 | 
				
			||||||
 | 
					  errno = ENOSYS;
 | 
				
			||||||
 | 
					  return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_unlink(const char*) {
 | 
				
			||||||
 | 
					  errno = ENOSYS;
 | 
				
			||||||
 | 
					  return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decrement a semaphore's value atomically,
 | 
				
			||||||
 | 
					// and return the old one. As a special case,
 | 
				
			||||||
 | 
					// this returns immediately if the value is
 | 
				
			||||||
 | 
					// negative (i.e. -1)
 | 
				
			||||||
 | 
					static int __sem_dec(volatile uint32_t* sem) {
 | 
				
			||||||
 | 
					  volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(sem);
 | 
				
			||||||
 | 
					  uint32_t shared = (*sem & SEMCOUNT_SHARED_MASK);
 | 
				
			||||||
 | 
					  uint32_t old_value, new_value;
 | 
				
			||||||
 | 
					  int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    old_value = (*sem & SEMCOUNT_VALUE_MASK);
 | 
				
			||||||
 | 
					    ret = SEMCOUNT_TO_VALUE(old_value);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_value = SEMCOUNT_DECREMENT(old_value);
 | 
				
			||||||
 | 
					  } while (__bionic_cmpxchg((old_value|shared), (new_value|shared), ptr) != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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(volatile uint32_t* sem) {
 | 
				
			||||||
 | 
					  volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(sem);
 | 
				
			||||||
 | 
					  uint32_t shared = (*sem & SEMCOUNT_SHARED_MASK);
 | 
				
			||||||
 | 
					  uint32_t old_value, new_value;
 | 
				
			||||||
 | 
					  int          ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    old_value = (*sem & SEMCOUNT_VALUE_MASK);
 | 
				
			||||||
 | 
					    ret = SEMCOUNT_TO_VALUE(old_value);
 | 
				
			||||||
 | 
					    if (ret <= 0) {
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_value = SEMCOUNT_DECREMENT(old_value);
 | 
				
			||||||
 | 
					  } while (__bionic_cmpxchg((old_value|shared), (new_value|shared), ptr) != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// "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(volatile uint32_t* sem) {
 | 
				
			||||||
 | 
					  volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(sem);
 | 
				
			||||||
 | 
					  uint32_t shared = (*sem & SEMCOUNT_SHARED_MASK);
 | 
				
			||||||
 | 
					  uint32_t old_value, new_value;
 | 
				
			||||||
 | 
					  int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    old_value = (*sem & SEMCOUNT_VALUE_MASK);
 | 
				
			||||||
 | 
					    ret = SEMCOUNT_TO_VALUE(old_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Can't go higher than SEM_VALUE_MAX.
 | 
				
			||||||
 | 
					    if (ret == SEM_VALUE_MAX) {
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If the counter is negative, go directly to +1, otherwise just increment.
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        new_value = SEMCOUNT_ONE;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      new_value = SEMCOUNT_INCREMENT(old_value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } while (__bionic_cmpxchg((old_value|shared), (new_value|shared), ptr) != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_wait(sem_t* sem) {
 | 
				
			||||||
 | 
					  if (sem == NULL) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t shared = SEM_GET_SHARED(sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (true) {
 | 
				
			||||||
 | 
					    if (__sem_dec(&sem->count) > 0) {
 | 
				
			||||||
 | 
					      ANDROID_MEMBAR_FULL();
 | 
				
			||||||
 | 
					      return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    __futex_wait_ex(&sem->count, shared, shared|SEMCOUNT_MINUS_ONE, NULL);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_timedwait(sem_t* sem, const timespec* abs_timeout) {
 | 
				
			||||||
 | 
					  if (sem == NULL) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // POSIX says we need to try to decrement the semaphore
 | 
				
			||||||
 | 
					  // before checking the timeout value. Note that if the
 | 
				
			||||||
 | 
					  // value is currently 0, __sem_trydec() does nothing.
 | 
				
			||||||
 | 
					  if (__sem_trydec(&sem->count) > 0) {
 | 
				
			||||||
 | 
					    ANDROID_MEMBAR_FULL();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Check it as per POSIX.
 | 
				
			||||||
 | 
					  if (abs_timeout == NULL || abs_timeout->tv_sec < 0 || abs_timeout->tv_nsec < 0 || abs_timeout->tv_nsec >= NS_PER_S) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t shared = SEM_GET_SHARED(sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (true) {
 | 
				
			||||||
 | 
					    // POSIX mandates CLOCK_REALTIME here.
 | 
				
			||||||
 | 
					    timespec ts;
 | 
				
			||||||
 | 
					    if (!timespec_from_absolute_timespec(ts, *abs_timeout, CLOCK_REALTIME)) {
 | 
				
			||||||
 | 
					      errno = ETIMEDOUT;
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Try to grab the semaphore. If the value was 0, this will also change it to -1.
 | 
				
			||||||
 | 
					    if (__sem_dec(&sem->count) > 0) {
 | 
				
			||||||
 | 
					      ANDROID_MEMBAR_FULL();
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Contention detected. Wait for a wakeup event.
 | 
				
			||||||
 | 
					    int ret = __futex_wait_ex(&sem->count, shared, shared|SEMCOUNT_MINUS_ONE, &ts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Return in case of timeout or interrupt.
 | 
				
			||||||
 | 
					    if (ret == -ETIMEDOUT || ret == -EINTR) {
 | 
				
			||||||
 | 
					      errno = -ret;
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_post(sem_t* sem) {
 | 
				
			||||||
 | 
					  if (sem == NULL) {
 | 
				
			||||||
 | 
					    return EINVAL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t shared = SEM_GET_SHARED(sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ANDROID_MEMBAR_FULL();
 | 
				
			||||||
 | 
					  int old_value = __sem_inc(&sem->count);
 | 
				
			||||||
 | 
					  if (old_value < 0) {
 | 
				
			||||||
 | 
					    // Contention on the semaphore. Wake up all waiters.
 | 
				
			||||||
 | 
					    __futex_wake_ex(&sem->count, shared, INT_MAX);
 | 
				
			||||||
 | 
					  } else if (old_value == SEM_VALUE_MAX) {
 | 
				
			||||||
 | 
					    // Overflow detected.
 | 
				
			||||||
 | 
					    errno = EOVERFLOW;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_trywait(sem_t* sem) {
 | 
				
			||||||
 | 
					  if (sem == NULL) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (__sem_trydec(&sem->count) > 0) {
 | 
				
			||||||
 | 
					    ANDROID_MEMBAR_FULL();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    errno = EAGAIN;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sem_getvalue(sem_t* sem, int* sval) {
 | 
				
			||||||
 | 
					  if (sem == NULL || sval == NULL) {
 | 
				
			||||||
 | 
					    errno = EINVAL;
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int val = SEMCOUNT_TO_VALUE(sem->count);
 | 
				
			||||||
 | 
					  if (val < 0) {
 | 
				
			||||||
 | 
					    val = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *sval = val;
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -49,7 +49,6 @@
 | 
				
			|||||||
#define  SYSTEM_MQ_OPEN_MAX     8
 | 
					#define  SYSTEM_MQ_OPEN_MAX     8
 | 
				
			||||||
#define  SYSTEM_MQ_PRIO_MAX     32768
 | 
					#define  SYSTEM_MQ_PRIO_MAX     32768
 | 
				
			||||||
#define  SYSTEM_SEM_NSEMS_MAX   256
 | 
					#define  SYSTEM_SEM_NSEMS_MAX   256
 | 
				
			||||||
#define  SYSTEM_SEM_VALUE_MAX   0x3fffffff  /* see bionic/semaphore.c */
 | 
					 | 
				
			||||||
#define  SYSTEM_SIGQUEUE_MAX    32
 | 
					#define  SYSTEM_SIGQUEUE_MAX    32
 | 
				
			||||||
#define  SYSTEM_TIMER_MAX       32
 | 
					#define  SYSTEM_TIMER_MAX       32
 | 
				
			||||||
#define  SYSTEM_LOGIN_NAME_MAX  256
 | 
					#define  SYSTEM_LOGIN_NAME_MAX  256
 | 
				
			||||||
@@ -152,32 +151,16 @@ static int __sysconf_monotonic_clock() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int sysconf(int name) {
 | 
					int sysconf(int name) {
 | 
				
			||||||
  switch (name) {
 | 
					  switch (name) {
 | 
				
			||||||
#ifdef _POSIX_ARG_MAX
 | 
					 | 
				
			||||||
    case _SC_ARG_MAX:           return _POSIX_ARG_MAX;
 | 
					    case _SC_ARG_MAX:           return _POSIX_ARG_MAX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX2_BC_BASE_MAX
 | 
					 | 
				
			||||||
    case _SC_BC_BASE_MAX:       return _POSIX2_BC_BASE_MAX;
 | 
					    case _SC_BC_BASE_MAX:       return _POSIX2_BC_BASE_MAX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX2_BC_DIM_MAX
 | 
					 | 
				
			||||||
    case _SC_BC_DIM_MAX:        return _POSIX2_BC_DIM_MAX;
 | 
					    case _SC_BC_DIM_MAX:        return _POSIX2_BC_DIM_MAX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX2_BC_SCALE_MAX
 | 
					 | 
				
			||||||
    case _SC_BC_SCALE_MAX:      return _POSIX2_BC_SCALE_MAX;
 | 
					    case _SC_BC_SCALE_MAX:      return _POSIX2_BC_SCALE_MAX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX2_BC_STRING_MAX
 | 
					 | 
				
			||||||
    case _SC_BC_STRING_MAX:     return _POSIX2_BC_STRING_MAX;
 | 
					    case _SC_BC_STRING_MAX:     return _POSIX2_BC_STRING_MAX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case _SC_CHILD_MAX:         return CHILD_MAX;
 | 
					    case _SC_CHILD_MAX:         return CHILD_MAX;
 | 
				
			||||||
    case _SC_CLK_TCK:           return SYSTEM_CLK_TCK;
 | 
					    case _SC_CLK_TCK:           return SYSTEM_CLK_TCK;
 | 
				
			||||||
#ifdef _POSIX2_COLL_WEIGHTS_MASK
 | 
					    case _SC_COLL_WEIGHTS_MAX:  return _POSIX2_COLL_WEIGHTS_MAX;
 | 
				
			||||||
    case _SC_COLL_WEIGHTS_MAX:  return _POSIX2_COLL_WEIGHTS_MASK;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX2_EXPR_NEST_MAX
 | 
					 | 
				
			||||||
    case _SC_EXPR_NEST_MAX:     return _POSIX2_EXPR_NEST_MAX;
 | 
					    case _SC_EXPR_NEST_MAX:     return _POSIX2_EXPR_NEST_MAX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX2_LINE_MAX
 | 
					 | 
				
			||||||
    case _SC_LINE_MAX:          return _POSIX2_LINE_MAX;
 | 
					    case _SC_LINE_MAX:          return _POSIX2_LINE_MAX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case _SC_NGROUPS_MAX:       return NGROUPS_MAX;
 | 
					    case _SC_NGROUPS_MAX:       return NGROUPS_MAX;
 | 
				
			||||||
    case _SC_OPEN_MAX:          return OPEN_MAX;
 | 
					    case _SC_OPEN_MAX:          return OPEN_MAX;
 | 
				
			||||||
    //case _SC_PASS_MAX:          return PASS_MAX;
 | 
					    //case _SC_PASS_MAX:          return PASS_MAX;
 | 
				
			||||||
@@ -191,42 +174,20 @@ int sysconf(int name) {
 | 
				
			|||||||
    case _SC_2_SW_DEV:          return SYSTEM_2_SW_DEV;
 | 
					    case _SC_2_SW_DEV:          return SYSTEM_2_SW_DEV;
 | 
				
			||||||
    case _SC_2_UPE:             return SYSTEM_2_UPE;
 | 
					    case _SC_2_UPE:             return SYSTEM_2_UPE;
 | 
				
			||||||
    case _SC_2_VERSION:         return SYSTEM_2_VERSION;
 | 
					    case _SC_2_VERSION:         return SYSTEM_2_VERSION;
 | 
				
			||||||
#ifdef _POSIX_JOB_CONTROL
 | 
					 | 
				
			||||||
    case _SC_JOB_CONTROL:       return _POSIX_JOB_CONTROL;
 | 
					    case _SC_JOB_CONTROL:       return _POSIX_JOB_CONTROL;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_SAVED_IDS
 | 
					 | 
				
			||||||
    case _SC_SAVED_IDS:         return _POSIX_SAVED_IDS;
 | 
					    case _SC_SAVED_IDS:         return _POSIX_SAVED_IDS;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_VERSION
 | 
					 | 
				
			||||||
    case _SC_VERSION:           return _POSIX_VERSION;
 | 
					    case _SC_VERSION:           return _POSIX_VERSION;
 | 
				
			||||||
#endif
 | 
					    case _SC_RE_DUP_MAX:        return _POSIX_RE_DUP_MAX;
 | 
				
			||||||
    //case _SC_RE_DUP_<AX:        return ;
 | 
					 | 
				
			||||||
    case _SC_STREAM_MAX:        return FOPEN_MAX;
 | 
					    case _SC_STREAM_MAX:        return FOPEN_MAX;
 | 
				
			||||||
    //case _SC_TZNAME_MAX:        return ;
 | 
					    case _SC_TZNAME_MAX:        return _POSIX_TZNAME_MAX;
 | 
				
			||||||
#if _XOPEN_CRYPT
 | 
					 | 
				
			||||||
    case _SC_XOPEN_CRYPT:       return _XOPEN_CRYPT;
 | 
					    case _SC_XOPEN_CRYPT:       return _XOPEN_CRYPT;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _XOPEN_ENH_I18N
 | 
					 | 
				
			||||||
    case _SC_XOPEN_ENH_I18N:    return _XOPEN_ENH_I18N;
 | 
					    case _SC_XOPEN_ENH_I18N:    return _XOPEN_ENH_I18N;
 | 
				
			||||||
#endif
 | 
					    //case _SC_XOPEN_SHM:         return _XOPEN_SHM;
 | 
				
			||||||
#ifdef _XOPEN_SHM
 | 
					 | 
				
			||||||
    case _SC_XOPEN_SHM:         return _XOPEN_SHM;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _XOPEN_VERSION
 | 
					 | 
				
			||||||
    case _SC_XOPEN_VERSION:     return _XOPEN_VERSION;
 | 
					    case _SC_XOPEN_VERSION:     return _XOPEN_VERSION;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _XOPEN_XCU_VERSION
 | 
					 | 
				
			||||||
    case _SC_XOPEN_XCU_VERSION: return _XOPEN_XCU_VERSION;
 | 
					    case _SC_XOPEN_XCU_VERSION: return _XOPEN_XCU_VERSION;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _XOPEN_REALTIME
 | 
					 | 
				
			||||||
    case _SC_XOPEN_REALTIME:    return _XOPEN_REALTIME;
 | 
					    case _SC_XOPEN_REALTIME:    return _XOPEN_REALTIME;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _XOPEN_REALTIME_THREADS
 | 
					 | 
				
			||||||
    case _SC_XOPEN_REALTIME_THREADS: return _XOPEN_REALTIME_THREADS;
 | 
					    case _SC_XOPEN_REALTIME_THREADS: return _XOPEN_REALTIME_THREADS;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _XOPEN_LEGACY
 | 
					 | 
				
			||||||
    case _SC_XOPEN_LEGACY:      return _XOPEN_LEGACY;
 | 
					    case _SC_XOPEN_LEGACY:      return _XOPEN_LEGACY;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case _SC_ATEXIT_MAX:        return SYSTEM_ATEXIT_MAX;
 | 
					    case _SC_ATEXIT_MAX:        return SYSTEM_ATEXIT_MAX;
 | 
				
			||||||
    case _SC_IOV_MAX:           return SYSTEM_IOV_MAX;
 | 
					    case _SC_IOV_MAX:           return SYSTEM_IOV_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -234,71 +195,35 @@ int sysconf(int name) {
 | 
				
			|||||||
    case _SC_PAGE_SIZE:
 | 
					    case _SC_PAGE_SIZE:
 | 
				
			||||||
        return PAGE_SIZE;
 | 
					        return PAGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _XOPEN_UNIX
 | 
					 | 
				
			||||||
    case _SC_XOPEN_UNIX:        return _XOPEN_UNIX;
 | 
					    case _SC_XOPEN_UNIX:        return _XOPEN_UNIX;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // XXX: TODO: XBS5 nonsense
 | 
					    // XXX: TODO: XBS5 nonsense
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef AIO_LISTIO_MAX
 | 
					    //case _SC_AIO_LISTIO_MAX:       return AIO_LISTIO_MAX;
 | 
				
			||||||
    case _SC_AIO_LISTIO_MAX:       return AIO_LISTIO_MAX;
 | 
					    //case _SC_AIO_MAX:              return AIO_MAX;
 | 
				
			||||||
#endif
 | 
					    //case _SC_AIO_PRIO_DELTA_MAX:   return AIO_PRIO_DELTA_MAX;
 | 
				
			||||||
#ifdef AIO_MAX
 | 
					 | 
				
			||||||
    case _SC_AIO_MAX:              return AIO_MAX;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef AIO_PRIO_DELTA_MAX
 | 
					 | 
				
			||||||
    case _SC_AIO_PRIO_DELTA_MAX:   return AIO_PRIO_DELTA_MAX;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case _SC_DELAYTIMER_MAX:    return SYSTEM_DELAYTIMER_MAX;
 | 
					    case _SC_DELAYTIMER_MAX:    return SYSTEM_DELAYTIMER_MAX;
 | 
				
			||||||
    case _SC_MQ_OPEN_MAX:       return SYSTEM_MQ_OPEN_MAX;
 | 
					    case _SC_MQ_OPEN_MAX:       return SYSTEM_MQ_OPEN_MAX;
 | 
				
			||||||
    case _SC_MQ_PRIO_MAX:       return SYSTEM_MQ_PRIO_MAX;
 | 
					    case _SC_MQ_PRIO_MAX:       return SYSTEM_MQ_PRIO_MAX;
 | 
				
			||||||
    case _SC_RTSIG_MAX:         return RTSIG_MAX;
 | 
					    case _SC_RTSIG_MAX:         return RTSIG_MAX;
 | 
				
			||||||
    case _SC_SEM_NSEMS_MAX:     return SYSTEM_SEM_NSEMS_MAX;
 | 
					    case _SC_SEM_NSEMS_MAX:     return SYSTEM_SEM_NSEMS_MAX;
 | 
				
			||||||
    case _SC_SEM_VALUE_MAX:     return SYSTEM_SEM_VALUE_MAX;
 | 
					    case _SC_SEM_VALUE_MAX:     return SEM_VALUE_MAX;
 | 
				
			||||||
    case _SC_SIGQUEUE_MAX:      return SYSTEM_SIGQUEUE_MAX;
 | 
					    case _SC_SIGQUEUE_MAX:      return SYSTEM_SIGQUEUE_MAX;
 | 
				
			||||||
    case _SC_TIMER_MAX:         return SYSTEM_TIMER_MAX;
 | 
					    case _SC_TIMER_MAX:         return SYSTEM_TIMER_MAX;
 | 
				
			||||||
#ifdef _POSIX_ASYNCHRONOUS_IO
 | 
					    //case _SC_ASYNCHRONOUS_IO:   return _POSIX_ASYNCHRONOUS_IO;
 | 
				
			||||||
    case _SC_ASYNCHRONOUS_IO:   return _POSIX_ASYNCHRONOUS_IO;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_FSYNC
 | 
					 | 
				
			||||||
    case _SC_FSYNC:             return _POSIX_FSYNC;
 | 
					    case _SC_FSYNC:             return _POSIX_FSYNC;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_MAPPED_FILES
 | 
					 | 
				
			||||||
    case _SC_MAPPED_FILES:      return _POSIX_MAPPED_FILES;
 | 
					    case _SC_MAPPED_FILES:      return _POSIX_MAPPED_FILES;
 | 
				
			||||||
#endif
 | 
					    //case _SC_MEMLOCK:           return _POSIX_MEMLOCK;
 | 
				
			||||||
#ifdef _POSIX_MEMLOCK
 | 
					    //case _SC_MEMLOCK_RANGE:     return _POSIX_MEMLOCK_RANGE;
 | 
				
			||||||
    case _SC_MEMLOCK:           return _POSIX_MEMLOCK;
 | 
					    //case _SC_MEMORY_PROTECTION: return _POSIX_MEMORY_PROTECTION;
 | 
				
			||||||
#endif
 | 
					    //case _SC_MESSAGE_PASSING:   return _POSIX_MESSAGE_PASSING;
 | 
				
			||||||
#ifdef _POSIX_MEMLOCK_RANGE
 | 
					    //case _SC_PRIORITIZED_IO:    return _POSIX_PRIORITIZED_IO;
 | 
				
			||||||
    case _SC_MEMLOCK_RANGE:     return _POSIX_MEMLOCK_RANGE
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_MEMORY_PROTECTION
 | 
					 | 
				
			||||||
    case _SC_MEMORY_PROTECTION: return _POSIX_MEMORY_PROTECTION;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_MESSAGE_PASSING
 | 
					 | 
				
			||||||
    case _SC_MESSAGE_PASSING:   return _POSIX_MESSAGE_PASSING;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_PRIORITIZED_IO
 | 
					 | 
				
			||||||
    case _SC_PRIORITIZED_IO:    return _POSIX_PRIORITIZED_IO;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_PRIORITY_SCHEDULING
 | 
					 | 
				
			||||||
    case _SC_PRIORITY_SCHEDULING:  return _POSIX_PRIORITY_SCHEDULING;
 | 
					    case _SC_PRIORITY_SCHEDULING:  return _POSIX_PRIORITY_SCHEDULING;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_REALTIME_SIGNALS
 | 
					 | 
				
			||||||
    case _SC_REALTIME_SIGNALS:  return _POSIX_REALTIME_SIGNALS;
 | 
					    case _SC_REALTIME_SIGNALS:  return _POSIX_REALTIME_SIGNALS;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_SEMAPHORES
 | 
					 | 
				
			||||||
    case _SC_SEMAPHORES:        return _POSIX_SEMAPHORES;
 | 
					    case _SC_SEMAPHORES:        return _POSIX_SEMAPHORES;
 | 
				
			||||||
#endif
 | 
					    //case _SC_SHARED_MEMORY_OBJECTS:  return _POSIX_SHARED_MEMORY_OBJECTS;
 | 
				
			||||||
#ifdef _POSIX_SHARED_MEMORY_OBJECTS
 | 
					 | 
				
			||||||
    case _SC_SHARED_MEMORY_OBJECTS:  return _POSIX_SHARED_MEMORY_OBJECTS;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_SYNCHRONIZED_IO
 | 
					 | 
				
			||||||
    case _SC_SYNCHRONIZED_IO:   return _POSIX_SYNCHRONIZED_IO;
 | 
					    case _SC_SYNCHRONIZED_IO:   return _POSIX_SYNCHRONIZED_IO;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_TIMERS
 | 
					 | 
				
			||||||
    case _SC_TIMERS:            return _POSIX_TIMERS;
 | 
					    case _SC_TIMERS:            return _POSIX_TIMERS;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case _SC_GETGR_R_SIZE_MAX: return 1024;
 | 
					    case _SC_GETGR_R_SIZE_MAX: return 1024;
 | 
				
			||||||
    case _SC_GETPW_R_SIZE_MAX: return 1024;
 | 
					    case _SC_GETPW_R_SIZE_MAX: return 1024;
 | 
				
			||||||
@@ -314,25 +239,15 @@ int sysconf(int name) {
 | 
				
			|||||||
    case _SC_THREAD_STACK_MIN:    return PTHREAD_STACK_MIN;
 | 
					    case _SC_THREAD_STACK_MIN:    return PTHREAD_STACK_MIN;
 | 
				
			||||||
    case _SC_THREAD_THREADS_MAX:  return SYSTEM_THREAD_THREADS_MAX;
 | 
					    case _SC_THREAD_THREADS_MAX:  return SYSTEM_THREAD_THREADS_MAX;
 | 
				
			||||||
    case _SC_TTY_NAME_MAX:        return SYSTEM_TTY_NAME_MAX;
 | 
					    case _SC_TTY_NAME_MAX:        return SYSTEM_TTY_NAME_MAX;
 | 
				
			||||||
#ifdef _POSIX_THREADS
 | 
					 | 
				
			||||||
    case _SC_THREADS:             return _POSIX_THREADS;
 | 
					    case _SC_THREADS:             return _POSIX_THREADS;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case _SC_THREAD_ATTR_STACKADDR:   return -1; // Removed in POSIX 2008
 | 
					    case _SC_THREAD_ATTR_STACKADDR:   return -1; // Removed in POSIX 2008
 | 
				
			||||||
    case _SC_THREAD_ATTR_STACKSIZE:   return -1; // Removed in POSIX 2008
 | 
					    case _SC_THREAD_ATTR_STACKSIZE:   return -1; // Removed in POSIX 2008
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
 | 
					    //case _SC_THREAD_PRIORITY_SCHEDULING:  return _POSIX_THREAD_PRIORITY_SCHEDULING;
 | 
				
			||||||
    case _SC_THREAD_PRIORITY_SCHEDULING:  return _POSIX_THREAD_PRIORITY_SCHEDULING;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_THREAD_PRIO_INHERIT
 | 
					 | 
				
			||||||
    case _SC_THREAD_PRIO_INHERIT:         return _POSIX_THREAD_PRIO_INHERIT;
 | 
					    case _SC_THREAD_PRIO_INHERIT:         return _POSIX_THREAD_PRIO_INHERIT;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _POSIX_THREAD_PRIO_PROTECT
 | 
					 | 
				
			||||||
    case _SC_THREAD_PRIO_PROTECT: return _POSIX_THREAD_PRIO_PROTECT;
 | 
					    case _SC_THREAD_PRIO_PROTECT: return _POSIX_THREAD_PRIO_PROTECT;
 | 
				
			||||||
#endif
 | 
					    //case _SC_THREAD_SAFE_FUNCTIONS:  return _POSIX_THREAD_SAFE_FUNCTIONS
 | 
				
			||||||
#ifdef _POSIX_THREAD_SAFE_FUNCTIONS
 | 
					 | 
				
			||||||
    case _SC_THREAD_SAFE_FUNCTIONS:  return _POSIX_THREAD_SAFE_FUNCTIONS
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case _SC_MONOTONIC_CLOCK:   return __sysconf_monotonic_clock();
 | 
					    case _SC_MONOTONIC_CLOCK:   return __sysconf_monotonic_clock();
 | 
				
			||||||
    case _SC_NPROCESSORS_CONF:  return __sysconf_nprocessors_conf();
 | 
					    case _SC_NPROCESSORS_CONF:  return __sysconf_nprocessors_conf();
 | 
				
			||||||
@@ -341,8 +256,8 @@ int sysconf(int name) {
 | 
				
			|||||||
    case _SC_AVPHYS_PAGES:      return __sysconf_avphys_pages();
 | 
					    case _SC_AVPHYS_PAGES:      return __sysconf_avphys_pages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
       /* Posix says EINVAL is the only error that shall be returned,
 | 
					      // Posix says EINVAL is the only error that shall be returned,
 | 
				
			||||||
        * but GLibc uses ENOSYS */
 | 
					      // but glibc uses ENOSYS.
 | 
				
			||||||
      errno = ENOSYS;
 | 
					      errno = ENOSYS;
 | 
				
			||||||
      return -1;
 | 
					      return -1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,6 +49,7 @@
 | 
				
			|||||||
#define	_POSIX_PATH_MAX		256
 | 
					#define	_POSIX_PATH_MAX		256
 | 
				
			||||||
#define _POSIX_PIPE_BUF		512
 | 
					#define _POSIX_PIPE_BUF		512
 | 
				
			||||||
#define	_POSIX_RE_DUP_MAX	255
 | 
					#define	_POSIX_RE_DUP_MAX	255
 | 
				
			||||||
 | 
					#define	_POSIX_SEM_VALUE_MAX	32767
 | 
				
			||||||
#define _POSIX_SSIZE_MAX	32767
 | 
					#define _POSIX_SSIZE_MAX	32767
 | 
				
			||||||
#define _POSIX_STREAM_MAX	8
 | 
					#define _POSIX_STREAM_MAX	8
 | 
				
			||||||
#define _POSIX_SYMLINK_MAX	255
 | 
					#define _POSIX_SYMLINK_MAX	255
 | 
				
			||||||
@@ -125,4 +126,7 @@
 | 
				
			|||||||
/* glibc's PAGE_MASK is the bitwise negation of BSD's! TODO: remove? */
 | 
					/* glibc's PAGE_MASK is the bitwise negation of BSD's! TODO: remove? */
 | 
				
			||||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
 | 
					#define PAGE_MASK (~(PAGE_SIZE - 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define _POSIX_SEMAPHORES 200809L
 | 
				
			||||||
 | 
					#define SEM_VALUE_MAX 0x3fffffff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* !_LIMITS_H_ */
 | 
					#endif /* !_LIMITS_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@
 | 
				
			|||||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
					 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 * SUCH DAMAGE.
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _SEMAPHORE_H
 | 
					#ifndef _SEMAPHORE_H
 | 
				
			||||||
#define _SEMAPHORE_H
 | 
					#define _SEMAPHORE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,6 +33,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__BEGIN_DECLS
 | 
					__BEGIN_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct timespec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
  volatile unsigned int count;
 | 
					  volatile unsigned int count;
 | 
				
			||||||
#ifdef __LP64__
 | 
					#ifdef __LP64__
 | 
				
			||||||
@@ -41,20 +44,18 @@ typedef struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define SEM_FAILED NULL
 | 
					#define SEM_FAILED NULL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int sem_init(sem_t *sem, int pshared, unsigned int value);
 | 
					int sem_destroy(sem_t*);
 | 
				
			||||||
 | 
					int sem_getvalue(sem_t*, int*);
 | 
				
			||||||
 | 
					int sem_init(sem_t*, int, unsigned int);
 | 
				
			||||||
 | 
					int sem_post(sem_t*);
 | 
				
			||||||
 | 
					int sem_timedwait(sem_t*, const struct timespec*);
 | 
				
			||||||
 | 
					int sem_trywait(sem_t*);
 | 
				
			||||||
 | 
					int sem_wait(sem_t*);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int    sem_close(sem_t *);
 | 
					/* These aren't actually implemented. */
 | 
				
			||||||
extern int    sem_destroy(sem_t *);
 | 
					sem_t* sem_open(const char*, int, ...);
 | 
				
			||||||
extern int    sem_getvalue(sem_t *, int *);
 | 
					int sem_close(sem_t*);
 | 
				
			||||||
extern int    sem_init(sem_t *, int, unsigned int);
 | 
					int sem_unlink(const char*);
 | 
				
			||||||
extern sem_t *sem_open(const char *, int, ...);
 | 
					 | 
				
			||||||
extern int    sem_post(sem_t *);
 | 
					 | 
				
			||||||
extern int    sem_trywait(sem_t *);
 | 
					 | 
				
			||||||
extern int    sem_unlink(const char *);
 | 
					 | 
				
			||||||
extern int    sem_wait(sem_t *);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct timespec;
 | 
					 | 
				
			||||||
extern int    sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
__END_DECLS
 | 
					__END_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								libc/private/bionic_constants.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								libc/private/bionic_constants.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 The Android Open Source Project
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _BIONIC_CONSTANTS_H_
 | 
				
			||||||
 | 
					#define _BIONIC_CONSTANTS_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NS_PER_S 1000000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // _BIONIC_CONSTANTS_H_
 | 
				
			||||||
@@ -39,6 +39,8 @@ __LIBC_HIDDEN__ void timespec_from_ms(timespec& ts, const int ms);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__LIBC_HIDDEN__ void timeval_from_timespec(timeval& tv, const timespec& ts);
 | 
					__LIBC_HIDDEN__ void timeval_from_timespec(timeval& tv, const timespec& ts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__LIBC_HIDDEN__ bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__END_DECLS
 | 
					__END_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,6 +86,7 @@ libBionicStandardTests_src_files := \
 | 
				
			|||||||
    regex_test.cpp \
 | 
					    regex_test.cpp \
 | 
				
			||||||
    sched_test.cpp \
 | 
					    sched_test.cpp \
 | 
				
			||||||
    search_test.cpp \
 | 
					    search_test.cpp \
 | 
				
			||||||
 | 
					    semaphore_test.cpp \
 | 
				
			||||||
    signal_test.cpp \
 | 
					    signal_test.cpp \
 | 
				
			||||||
    stack_protector_test.cpp \
 | 
					    stack_protector_test.cpp \
 | 
				
			||||||
    stdatomic_test.cpp \
 | 
					    stdatomic_test.cpp \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										143
									
								
								tests/semaphore_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								tests/semaphore_test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 The Android Open Source Project
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <semaphore.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <gtest/gtest.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "private/bionic_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(semaphore, sem_init) {
 | 
				
			||||||
 | 
					  sem_t s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Perfectly fine initial values.
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, 0));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, 1));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, 123));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Too small an initial value.
 | 
				
			||||||
 | 
					  errno = 0;
 | 
				
			||||||
 | 
					  ASSERT_EQ(-1, sem_init(&s, 0, -1));
 | 
				
			||||||
 | 
					  ASSERT_EQ(EINVAL, errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_EQ(SEM_VALUE_MAX, sysconf(_SC_SEM_VALUE_MAX));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The largest initial value.
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, SEM_VALUE_MAX));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Too large an initial value.
 | 
				
			||||||
 | 
					  errno = 0;
 | 
				
			||||||
 | 
					  ASSERT_EQ(-1, sem_init(&s, 0, SEM_VALUE_MAX + 1));
 | 
				
			||||||
 | 
					  ASSERT_EQ(EINVAL, errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_destroy(&s));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(semaphore, sem_trywait) {
 | 
				
			||||||
 | 
					  sem_t s;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, 3));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_trywait(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_trywait(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_trywait(&s));
 | 
				
			||||||
 | 
					  errno = 0;
 | 
				
			||||||
 | 
					  ASSERT_EQ(-1, sem_trywait(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(EAGAIN, errno);
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_destroy(&s));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SemWaitThreadTestFn(sem_t& sem) {
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_wait(&sem));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void* SemWaitThreadFn(void* arg) {
 | 
				
			||||||
 | 
					  SemWaitThreadTestFn(*reinterpret_cast<sem_t*>(arg));
 | 
				
			||||||
 | 
					  return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(semaphore, sem_wait__sem_post) {
 | 
				
			||||||
 | 
					  sem_t s;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pthread_t t1, t2, t3;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, pthread_create(&t1, NULL, SemWaitThreadFn, &s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, pthread_create(&t2, NULL, SemWaitThreadFn, &s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, pthread_create(&t3, NULL, SemWaitThreadFn, &s));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_post(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_post(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_post(&s));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void* result;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, pthread_join(t1, &result));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, pthread_join(t2, &result));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, pthread_join(t3, &result));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void timespec_add_ms(timespec& ts, size_t ms) {
 | 
				
			||||||
 | 
					  ts.tv_sec  += ms / 1000;
 | 
				
			||||||
 | 
					  ts.tv_nsec += (ms % 1000) * 1000000;
 | 
				
			||||||
 | 
					  if (ts.tv_nsec >= NS_PER_S) {
 | 
				
			||||||
 | 
					    ts.tv_sec++;
 | 
				
			||||||
 | 
					    ts.tv_nsec -= NS_PER_S;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(semaphore, sem_timedwait) {
 | 
				
			||||||
 | 
					  sem_t s;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  timespec ts;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
 | 
				
			||||||
 | 
					  timespec_add_ms(ts, 100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  errno = 0;
 | 
				
			||||||
 | 
					  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
 | 
				
			||||||
 | 
					  ASSERT_EQ(ETIMEDOUT, errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // A negative timeout is an error.
 | 
				
			||||||
 | 
					  errno = 0;
 | 
				
			||||||
 | 
					  ts.tv_nsec = -1;
 | 
				
			||||||
 | 
					  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
 | 
				
			||||||
 | 
					  ASSERT_EQ(EINVAL, errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_destroy(&s));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(semaphore, sem_getvalue) {
 | 
				
			||||||
 | 
					  sem_t s;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_init(&s, 0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int i;
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_getvalue(&s, &i));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_post(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_getvalue(&s, &i));
 | 
				
			||||||
 | 
					  ASSERT_EQ(1, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_post(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_getvalue(&s, &i));
 | 
				
			||||||
 | 
					  ASSERT_EQ(2, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_wait(&s));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0, sem_getvalue(&s, &i));
 | 
				
			||||||
 | 
					  ASSERT_EQ(1, i);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -26,6 +26,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "ScopedSignalHandler.h"
 | 
					#include "ScopedSignalHandler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "private/bionic_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(time, gmtime) {
 | 
					TEST(time, gmtime) {
 | 
				
			||||||
  time_t t = 0;
 | 
					  time_t t = 0;
 | 
				
			||||||
  tm* broken_down = gmtime(&t);
 | 
					  tm* broken_down = gmtime(&t);
 | 
				
			||||||
@@ -395,7 +397,7 @@ TEST(time, clock_gettime) {
 | 
				
			|||||||
  ts2.tv_nsec -= ts1.tv_nsec;
 | 
					  ts2.tv_nsec -= ts1.tv_nsec;
 | 
				
			||||||
  if (ts2.tv_nsec < 0) {
 | 
					  if (ts2.tv_nsec < 0) {
 | 
				
			||||||
    --ts2.tv_sec;
 | 
					    --ts2.tv_sec;
 | 
				
			||||||
    ts2.tv_nsec += 1000000000;
 | 
					    ts2.tv_nsec += NS_PER_S;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Should be less than (a very generous, to try to avoid flakiness) 1000000ns.
 | 
					  // Should be less than (a very generous, to try to avoid flakiness) 1000000ns.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user