diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index c34daef3c..ab48fb87f 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -108,3 +108,9 @@ __noreturn void __libc_init(void* raw_args, exit(slingshot(args.argc, args.argv, args.envp)); } + +extern "C" uint32_t android_get_application_target_sdk_version(); + +uint32_t bionic_get_application_target_sdk_version() { + return android_get_application_target_sdk_version(); +} diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp index 3cda1a278..d1494d7ca 100644 --- a/libc/bionic/libc_init_static.cpp +++ b/libc/bionic/libc_init_static.cpp @@ -26,6 +26,7 @@ * SUCH DAMAGE. */ +#include #include #include #include @@ -106,3 +107,7 @@ __noreturn void __libc_init(void* raw_args, exit(slingshot(args.argc, args.argv, args.envp)); } + +uint32_t bionic_get_application_target_sdk_version() { + return __ANDROID_API__; +} diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp index b30c0b06e..19816470f 100644 --- a/libc/bionic/semaphore.cpp +++ b/libc/bionic/semaphore.cpp @@ -41,6 +41,7 @@ #include "private/bionic_constants.h" #include "private/bionic_futex.h" +#include "private/bionic_sdk_version.h" #include "private/bionic_time_conversions.h" // In this implementation, a semaphore contains a @@ -220,7 +221,13 @@ int sem_wait(sem_t* sem) { return 0; } - __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr); + int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr); + if (bionic_get_application_target_sdk_version() > 23) { + if (result ==-EINTR) { + errno = EINTR; + return -1; + } + } } } diff --git a/libc/private/bionic_sdk_version.h b/libc/private/bionic_sdk_version.h new file mode 100644 index 000000000..871d25c9e --- /dev/null +++ b/libc/private/bionic_sdk_version.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 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_SDK_VERSION_H_ +#define _BIONIC_SDK_VERSION_H_ + +#include + +uint32_t bionic_get_application_target_sdk_version(); + +#endif // _BIONIC_SDK_VERSION_H_ diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp index 84343dadd..7dc72259a 100644 --- a/tests/semaphore_test.cpp +++ b/tests/semaphore_test.cpp @@ -24,6 +24,7 @@ #include #include "private/bionic_constants.h" +#include "ScopedSignalHandler.h" TEST(semaphore, sem_init) { sem_t s; @@ -158,3 +159,71 @@ TEST(semaphore, sem_getvalue) { ASSERT_EQ(0, sem_getvalue(&s, &i)); ASSERT_EQ(1, i); } + +extern "C" void android_set_application_target_sdk_version(uint32_t target); + +static void sem_wait_test_signal_handler(int) { +} + +static void* SemWaitEINTRThreadFn(void* arg) { + sem_t* sem = reinterpret_cast(arg); + uintptr_t have_eintr = 0; + uintptr_t have_error = 0; + while (true) { + int result = sem_wait(sem); + if (result == 0) { + break; + } + if (result == -1) { + if (errno == EINTR) { + have_eintr = 1; + } else { + have_error = 1; + break; + } + } + } + return reinterpret_cast((have_eintr << 1) | have_error); +} + +TEST(semaphore, sem_wait_no_EINTR_in_sdk_less_equal_than_23) { +#if defined(__BIONIC__) + android_set_application_target_sdk_version(23U); + sem_t s; + ASSERT_EQ(0, sem_init(&s, 0, 0)); + ScopedSignalHandler handler(SIGUSR1, sem_wait_test_signal_handler); + pthread_t thread; + ASSERT_EQ(0, pthread_create(&thread, nullptr, SemWaitEINTRThreadFn, &s)); + // Give some time for the thread to run sem_wait. + usleep(500000); + ASSERT_EQ(0, pthread_kill(thread, SIGUSR1)); + // Give some time for the thread to handle signal. + usleep(500000); + ASSERT_EQ(0, sem_post(&s)); + void* result; + ASSERT_EQ(0, pthread_join(thread, &result)); + ASSERT_EQ(0U, reinterpret_cast(result)); +#else + GTEST_LOG_(INFO) << "This test tests sem_wait's compatibility for old sdk versions"; +#endif +} + +TEST(semaphore, sem_wait_EINTR_in_sdk_greater_than_23) { +#if defined(__BIONIC__) + android_set_application_target_sdk_version(24U); +#endif + sem_t s; + ASSERT_EQ(0, sem_init(&s, 0, 0)); + ScopedSignalHandler handler(SIGUSR1, sem_wait_test_signal_handler); + pthread_t thread; + ASSERT_EQ(0, pthread_create(&thread, nullptr, SemWaitEINTRThreadFn, &s)); + // Give some time for the thread to run sem_wait. + usleep(500000); + ASSERT_EQ(0, pthread_kill(thread, SIGUSR1)); + // Give some time for the thread to handle signal. + usleep(500000); + ASSERT_EQ(0, sem_post(&s)); + void* result; + ASSERT_EQ(0, pthread_join(thread, &result)); + ASSERT_EQ(2U, reinterpret_cast(result)); +}