dd586f2ebd
It actually means "crash immediately". Well, it's an error. And callers are much more likely to realize their mistake if we crash immediately rather than return EINVAL. Historically, glibc has crashed and bionic -- before the recent changes -- returned EINVAL, so this is a behavior change. Change-Id: I0c2373a6703b20b8a97aacc1e66368a5885e8c51
161 lines
3.8 KiB
C++
161 lines
3.8 KiB
C++
/*
|
|
* 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);
|
|
errno = 0;
|
|
ts.tv_nsec = NS_PER_S;
|
|
ASSERT_EQ(-1, sem_timedwait(&s, &ts));
|
|
ASSERT_EQ(EINVAL, errno);
|
|
|
|
errno = 0;
|
|
ts.tv_nsec = NS_PER_S - 1;
|
|
ts.tv_sec = -1;
|
|
ASSERT_EQ(-1, sem_timedwait(&s, &ts));
|
|
ASSERT_EQ(ETIMEDOUT, errno);
|
|
|
|
ASSERT_EQ(0, sem_destroy(&s));
|
|
}
|
|
|
|
TEST(semaphore_DeathTest, sem_timedwait_null_timeout) {
|
|
sem_t s;
|
|
ASSERT_EQ(0, sem_init(&s, 0, 0));
|
|
|
|
ASSERT_EXIT(sem_timedwait(&s, nullptr), testing::KilledBySignal(SIGSEGV), "");
|
|
}
|
|
|
|
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);
|
|
}
|