static std::vector<void*> example_key_destructor_data; static pthread_key_t example_key; staticvoid example_key_destructor(void *data) { // By the time the destructor function is running, // this thread's value for the key should have been zeroed.
ASSERT_EQ(NULL, pthread_getspecific(example_key));
// Store the value so we can check we got the expected result.
example_key_destructor_data.push_back(data);
}
// Check that the destructor isn't called for a default null value.
std::thread([]() {}).join();
ASSERT_TRUE(example_key_destructor_data.empty());
// Check that the destructor isn't called for an explicit null value.
std::thread([]() {
ASSERT_EQ(0, pthread_setspecific(example_key, (void*) 1234));
ASSERT_EQ(0, pthread_setspecific(example_key, nullptr));
}).join();
ASSERT_TRUE(example_key_destructor_data.empty());
// Check that the destructor is called for a non-null value.
std::thread([]() { ASSERT_EQ(0, pthread_setspecific(example_key, (void*) 1234)); }).join();
ASSERT_EQ(1u, example_key_destructor_data.size());
ASSERT_EQ((void*) 1234, example_key_destructor_data[0]);
ASSERT_EQ(0, pthread_key_delete(example_key));
}
TEST(pthread, pthread_keys_max) { // POSIX says PTHREAD_KEYS_MAX should be at least _POSIX_THREAD_KEYS_MAX.
ASSERT_GE(PTHREAD_KEYS_MAX, _POSIX_THREAD_KEYS_MAX);
}
TEST(pthread, sysconf_SC_THREAD_KEYS_MAX_eq_PTHREAD_KEYS_MAX) { int sysconf_max = sysconf(_SC_THREAD_KEYS_MAX);
ASSERT_EQ(sysconf_max, PTHREAD_KEYS_MAX);
}
TEST(pthread, pthread_key_many_distinct) { // As gtest uses pthread keys, we can't allocate exactly PTHREAD_KEYS_MAX // pthread keys, but We should be able to allocate at least this many keys. int nkeys = PTHREAD_KEYS_MAX / 2;
std::vector<pthread_key_t> keys;
auto scope_guard = android::base::make_scope_guard([&keys] { for (constauto& key : keys) {
EXPECT_EQ(0, pthread_key_delete(key));
}
});
for (int i = 0; i < nkeys; ++i) {
pthread_key_t key; // If this fails, it's likely that LIBC_PTHREAD_KEY_RESERVED_COUNT is wrong.
ASSERT_EQ(0, pthread_key_create(&key, nullptr)) << i << " of " << nkeys;
keys.push_back(key);
ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void*>(i)));
}
for (int i = keys.size() - 1; i >= 0; --i) {
ASSERT_EQ(reinterpret_cast<void*>(i), pthread_getspecific(keys.back()));
pthread_key_t key = keys.back();
keys.pop_back();
ASSERT_EQ(0, pthread_key_delete(key));
}
}
TEST(pthread, pthread_key_not_exceed_PTHREAD_KEYS_MAX) {
std::vector<pthread_key_t> keys; int rv = 0;
// Pthread keys are used by gtest, so PTHREAD_KEYS_MAX should // be more than we are allowed to allocate now. for (int i = 0; i < PTHREAD_KEYS_MAX; i++) {
pthread_key_t key;
rv = pthread_key_create(&key, nullptr); if (rv == EAGAIN) { break;
}
EXPECT_EQ(0, rv);
keys.push_back(key);
}
TEST(pthread, static_pthread_key_used_before_creation) { #ifdefined(__BIONIC__) // See http://b/19625804. The bug is about a static/global pthread key being used before creation. // So here tests if the static/global default value 0 can be detected as invalid key. static pthread_key_t key;
ASSERT_EQ(nullptr, pthread_getspecific(key));
ASSERT_EQ(EINVAL, pthread_setspecific(key, nullptr));
ASSERT_EQ(EINVAL, pthread_key_delete(key)); #else
GTEST_SKIP() << "bionic-only test"; #endif
}
staticvoid* IdFn(void* arg) { return arg;
}
class SpinFunctionHelper { public:
SpinFunctionHelper() {
SpinFunctionHelper::spin_flag_ = true;
}
~SpinFunctionHelper() {
UnSpin();
}
auto GetFunction() -> void* (*)(void*) { return SpinFunctionHelper::SpinFn;
}
// It doesn't matter if spin_flag_ is used in several tests, // because it is always set to false after each test. Each thread // loops on spin_flag_ can find it becomes false at some time.
std::atomic<bool> SpinFunctionHelper::spin_flag_;
TEST(pthread, pthread_create) { void* expected_result = reinterpret_cast<void*>(123); // Can we create a thread?
pthread_t t;
ASSERT_EQ(0, pthread_create(&t, nullptr, IdFn, expected_result)); // If we join, do we get the expected value back? void* result;
ASSERT_EQ(0, pthread_join(t, &result));
ASSERT_EQ(expected_result, result);
}
// ...but t2's join on t1 still goes ahead (which we can tell because our join on t2 finishes). void* join_result;
ASSERT_EQ(0, pthread_join(t2, &join_result));
ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(join_result));
}
// Wait for the thread to be running...
ASSERT_EQ(0, pthread_mutex_lock(&data.mutex));
ASSERT_EQ(0, pthread_mutex_unlock(&data.mutex));
// ...and exit.
pthread_exit(nullptr);
}
private: staticvoid* thread_fn(void* arg) {
TestBug37410* data = reinterpret_cast<TestBug37410*>(arg);
// Unlocking data->mutex will cause the main thread to exit, invalidating *data. Save the handle.
pthread_t main_thread = data->main_thread;
// Let the main thread know we're running.
pthread_mutex_unlock(&data->mutex);
// And wait for the main thread to exit.
pthread_join(main_thread, nullptr);
return nullptr;
}
};
// Even though this isn't really a death test, we have to say "DeathTest" here so gtest knows to // run this test (which exits normally) in its own process.
TEST_F(pthread_DeathTest, pthread_bug_37410) { // http://code.google.com/p/android/issues/detail?id=37410
ASSERT_EXIT(TestBug37410::main(), ::testing::ExitedWithCode(0), "");
}
// Check that SIGUSR1 is blocked.
sigset_t final_set;
sigemptyset(&final_set);
ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, nullptr, &final_set));
ASSERT_TRUE(sigismember(&final_set, SIGUSR1)); // ...and that sigprocmask agrees with pthread_sigmask.
sigemptyset(&final_set);
ASSERT_EQ(0, sigprocmask(SIG_BLOCK, nullptr, &final_set));
ASSERT_TRUE(sigismember(&final_set, SIGUSR1));
// Spawn a thread that calls sigwait and tells us what it received.
pthread_t signal_thread; int received_signal = -1;
ASSERT_EQ(0, pthread_create(&signal_thread, nullptr, SignalHandlerFn, &received_signal));
// Send that thread SIGUSR1.
pthread_kill(signal_thread, SIGUSR1);
// See what it got. void* join_result;
ASSERT_EQ(0, pthread_join(signal_thread, &join_result));
ASSERT_EQ(SIGUSR1, received_signal);
ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(join_result));
// Restore the original signal mask.
ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &original_set, nullptr));
}
// Check that SIGRTMIN is blocked.
sigset64_t final_set;
sigemptyset64(&final_set);
ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, nullptr, &final_set));
ASSERT_TRUE(sigismember64(&final_set, SIGRTMIN)); // ...and that sigprocmask64 agrees with pthread_sigmask64.
sigemptyset64(&final_set);
ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, nullptr, &final_set));
ASSERT_TRUE(sigismember64(&final_set, SIGRTMIN));
// Spawn a thread that calls sigwait64 and tells us what it received.
pthread_t signal_thread; int received_signal = -1;
ASSERT_EQ(0, pthread_create(&signal_thread, nullptr, SignalHandlerFn, &received_signal));
// Send that thread SIGRTMIN.
pthread_kill(signal_thread, SIGRTMIN);
// See what it got. void* join_result;
ASSERT_EQ(0, pthread_join(signal_thread, &join_result));
ASSERT_EQ(SIGRTMIN, received_signal);
ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(join_result));
// Restore the original signal mask.
ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &original_set, nullptr));
}
// The limit is 15 characters --- the kernel's buffer is 16, but includes a NUL.
ASSERT_EQ(0, pthread_setname_np(t, "123456789012345"));
ASSERT_EQ(0, pthread_getname_np(t, name, sizeof(name)));
ASSERT_STREQ("123456789012345", name);
// The passed-in buffer should be at least 16 bytes.
ASSERT_EQ(0, pthread_getname_np(t, name, 16));
ASSERT_EQ(ERANGE, pthread_getname_np(t, name, 15));
}
// http://b/28051133: a kernel misfeature means that you can't change the // name of another thread if you've set PR_SET_DUMPABLE to 0.
TEST(pthread, pthread_setname_np__pthread_getname_np__other_PR_SET_DUMPABLE) {
ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 0)) << strerror(errno);
TEST(pthread, pthread_kill__0) { // Signal 0 just tests that the thread exists, so it's safe to call on ourselves.
ASSERT_EQ(0, pthread_kill(pthread_self(), 0));
}
staticvoid pthread_kill__in_signal_handler_helper(int signal_number) { staticint count = 0;
ASSERT_EQ(SIGALRM, signal_number); if (++count == 1) { // Can we call pthread_kill from a signal handler?
ASSERT_EQ(0, pthread_kill(pthread_self(), SIGALRM));
}
}
sleep(1); // (Give t2 a chance to call pthread_join.)
// Multiple joins to the same thread should fail.
ASSERT_EQ(EINVAL, pthread_join(t1, nullptr));
spin_helper.UnSpin();
// ...but t2's join on t1 still goes ahead (which we can tell because our join on t2 finishes). void* join_result;
ASSERT_EQ(0, pthread_join(t2, &join_result));
ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(join_result));
}
TEST(pthread, pthread_join__race) { // http://b/11693195 --- pthread_join could return before the thread had actually exited. // If the joiner unmapped the thread's stack, that could lead to SIGSEGV in the thread. for (size_t i = 0; i < 1024; ++i) {
size_t stack_size = 640*1024; void* stack = mmap(nullptr, stack_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
// No such thing as too small: will be rounded up to one page by pthread_create.
ASSERT_EQ(0, pthread_attr_setguardsize(&attributes, 128));
size_t guard_size;
ASSERT_EQ(0, pthread_attr_getguardsize(&attributes, &guard_size));
ASSERT_EQ(128U, guard_size);
ASSERT_EQ(static_cast<unsignedlong>(getpagesize()), GetActualGuardSize(attributes));
}
// Large enough and a multiple of the page size.
ASSERT_EQ(0, pthread_attr_setguardsize(&attributes, 32*1024));
size_t guard_size;
ASSERT_EQ(0, pthread_attr_getguardsize(&attributes, &guard_size));
ASSERT_EQ(32*1024U, guard_size);
ASSERT_EQ(32*1024U, GetActualGuardSize(attributes));
}
// Larger than the stack itself. (Historically we mistakenly carved // the guard out of the stack itself, rather than adding it after the // end.)
ASSERT_EQ(0, pthread_attr_setguardsize(&attributes, 32*1024*1024));
size_t guard_size;
ASSERT_EQ(0, pthread_attr_getguardsize(&attributes, &guard_size));
ASSERT_EQ(32*1024*1024U, guard_size);
ASSERT_EQ(32*1024*1024U, GetActualGuardSize(attributes));
}
// Large enough and a multiple of the page size; may be rounded up by pthread_create.
ASSERT_EQ(0, pthread_attr_setstacksize(&attributes, 32*1024));
ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size));
ASSERT_EQ(32*1024U, stack_size);
ASSERT_GE(GetActualStackSize(attributes), 32*1024U);
// Large enough but not aligned; will be rounded up by pthread_create.
ASSERT_EQ(0, pthread_attr_setstacksize(&attributes, 32*1024 + 1));
ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size));
ASSERT_EQ(32*1024U + 1, stack_size); #ifdefined(__BIONIC__)
ASSERT_GT(GetActualStackSize(attributes), 32*1024U + 1); #else// __BIONIC__ // glibc rounds down, in violation of POSIX. They document this in their BUGS section.
ASSERT_EQ(GetActualStackSize(attributes), 32*1024U); #endif// __BIONIC__
}
// Child and parent calls are made in the order they were registered. if (pid == 0) {
ASSERT_EQ(12, g_atfork_child_calls);
_exit(0);
}
ASSERT_EQ(12, g_atfork_parent_calls);
// Prepare calls are made in the reverse order.
ASSERT_EQ(21, g_atfork_prepare_calls);
AssertChildExited(pid, 0);
}
#else// __BIONIC__
GTEST_SKIP() << "pthread_cond_clockwait not available"; #endif// __BIONIC__
}
TEST(pthread, pthread_attr_getstack__main_thread) { // This test is only meaningful for the main thread, so make sure we're running on it!
ASSERT_EQ(getpid(), syscall(__NR_gettid));
// Get the main thread's attributes.
pthread_attr_t attributes;
ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attributes));
// Check that we correctly report that the main thread has no guard page.
size_t guard_size;
ASSERT_EQ(0, pthread_attr_getguardsize(&attributes, &guard_size));
ASSERT_EQ(0U, guard_size); // The main thread has no guard page.
// Get the stack base and the stack size (both ways). void* stack_base;
size_t stack_size;
ASSERT_EQ(0, pthread_attr_getstack(&attributes, &stack_base, &stack_size));
size_t stack_size2;
ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size2));
// The two methods of asking for the stack size should agree.
EXPECT_EQ(stack_size, stack_size2);
#ifdefined(__BIONIC__) // Find stack in /proc/self/maps using a pointer to the stack. // // We do not use "[stack]" label because in native-bridge environment it is not // guaranteed to point to the right stack. A native bridge implementation may // keep separate stack for the guest code. void* maps_stack_hi = nullptr;
std::vector<map_record> maps;
ASSERT_TRUE(Maps::parse_maps(&maps));
uintptr_t stack_address = reinterpret_cast<uintptr_t>(untag_address(&maps_stack_hi)); for (constauto& map : maps) { if (map.addr_start <= stack_address && map.addr_end > stack_address){
maps_stack_hi = reinterpret_cast<void*>(map.addr_end); break;
}
}
// The high address of the /proc/self/maps stack region should equal stack_base + stack_size. // Remember that the stack grows down (and is mapped in on demand), so the low address of the // region isn't very interesting.
EXPECT_EQ(maps_stack_hi, reinterpret_cast<uint8_t*>(stack_base) + stack_size);
// The stack size should correspond to RLIMIT_STACK.
rlimit rl;
ASSERT_EQ(0, getrlimit(RLIMIT_STACK, &rl));
uint64_t original_rlim_cur = rl.rlim_cur; if (rl.rlim_cur == RLIM_INFINITY) {
rl.rlim_cur = 8 * 1024 * 1024; // Bionic reports unlimited stacks as 8MiB.
}
EXPECT_EQ(rl.rlim_cur, stack_size);
// // What if RLIMIT_STACK is smaller than the stack's current extent? //
rl.rlim_cur = rl.rlim_max = 1024; // 1KiB. We know the stack must be at least a page already.
rl.rlim_max = RLIM_INFINITY;
ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
// // What if RLIMIT_STACK isn't a whole number of pages? //
rl.rlim_cur = rl.rlim_max = 6666; // Not a whole number of pages.
rl.rlim_max = RLIM_INFINITY;
ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
staticvoid getstack_signal_handler(int sig) {
ASSERT_EQ(SIGUSR1, sig); // Use sleep() to make current thread be switched out by the kernel to provoke the error.
sleep(1);
pthread_attr_t attr;
ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attr)); void* stack_base;
size_t stack_size;
ASSERT_EQ(0, pthread_attr_getstack(&attr, &stack_base, &stack_size));
// Verify if the stack used by the signal handler is the alternate stack just registered.
ASSERT_LE(getstack_signal_handler_arg.signal_stack_base, &attr);
ASSERT_LT(static_cast<void*>(untag_address(&attr)), static_cast<char*>(getstack_signal_handler_arg.signal_stack_base) +
getstack_signal_handler_arg.signal_stack_size);
// Verify if the main thread's stack got in the signal handler is correct.
ASSERT_EQ(getstack_signal_handler_arg.main_stack_base, stack_base);
ASSERT_LE(getstack_signal_handler_arg.main_stack_size, stack_size);
getstack_signal_handler_arg.done = true;
}
// The previous code obtained the main thread's stack by reading the entry in // /proc/self/task/<pid>/maps that was labeled [stack]. Unfortunately, on x86/x86_64, the kernel // relies on sp0 in task state segment(tss) to label the stack map with [stack]. If the kernel // switches a process while the main thread is in an alternate stack, then the kernel will label // the wrong map with [stack]. This test verifies that when the above situation happens, the main // thread's stack is found correctly.
TEST(pthread, pthread_attr_getstack_in_signal_handler) { // This test is only meaningful for the main thread, so make sure we're running on it!
ASSERT_EQ(getpid(), syscall(__NR_gettid));
// Test whether &local_variable is in [stack_base, stack_base + stack_size).
ASSERT_LE(reinterpret_cast<char*>(stack_base), &local_variable);
ASSERT_LT(untag_address(&local_variable), reinterpret_cast<char*>(stack_base) + stack_size);
}
// Check whether something on stack is in the range of // [stack_base, stack_base + stack_size). see b/18908062.
TEST(pthread, pthread_attr_getstack_18908062) {
pthread_t t;
ASSERT_EQ(0, pthread_create(&t, nullptr, reinterpret_cast<void* (*)(void*)>(pthread_attr_getstack_18908062_helper),
nullptr));
ASSERT_EQ(0, pthread_join(t, nullptr));
}
// Wait for our parent to call pthread_gettid_np on us before exiting.
pthread_mutex_lock(&pthread_gettid_np_mutex);
pthread_mutex_unlock(&pthread_gettid_np_mutex); return nullptr;
} #endif
pthread_cleanup_pop(0); // Pop the abort without executing it.
pthread_cleanup_pop(1); // Pop one count while executing it.
ASSERT_EQ(1U, cleanup_counter); // Exit while the other count is still on the cleanup stack.
pthread_exit(nullptr);
// Calls to pthread_cleanup_pop/pthread_cleanup_push must always be balanced.
pthread_cleanup_pop(0);
}
TEST(pthread, pthread_mutex_pi_count_limit) { #ifdefined(__BIONIC__) && !defined(__LP64__) // Bionic only supports 65536 pi mutexes in 32-bit programs.
pthread_mutexattr_t attr;
ASSERT_EQ(0, pthread_mutexattr_init(&attr));
ASSERT_EQ(0, pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT));
std::vector<pthread_mutex_t> mutexes(65536); // Test if we can use 65536 pi mutexes at the same time. // Run 2 times to check if freed pi mutexes can be recycled. for (int repeat = 0; repeat < 2; ++repeat) { for (auto& m : mutexes) {
ASSERT_EQ(0, pthread_mutex_init(&m, &attr));
}
pthread_mutex_t m;
ASSERT_EQ(ENOMEM, pthread_mutex_init(&m, &attr)); for (auto& m : mutexes) {
ASSERT_EQ(0, pthread_mutex_lock(&m));
} for (auto& m : mutexes) {
ASSERT_EQ(0, pthread_mutex_unlock(&m));
} for (auto& m : mutexes) {
ASSERT_EQ(0, pthread_mutex_destroy(&m));
}
}
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr)); #else
GTEST_SKIP() << "pi mutex count not limited to 64Ki"; #endif
}
staticint GetThreadPriority(pid_t tid) { // sched_getparam() returns the static priority of a thread, which can't reflect a thread's // priority after priority inheritance. So read /proc/<pid>/stat to get the dynamic priority.
std::string filename = android::base::StringPrintf("/proc/%d/stat", tid);
std::string content; int result = INT_MAX; if (!android::base::ReadFileToString(filename, &content)) { return result;
}
std::vector<std::string> strs = android::base::Split(content, " "); if (strs.size() < 18) { return result;
} if (!android::base::ParseInt(strs[17], &result)) { return INT_MAX;
} return result;
}
class PIMutexWakeupHelper { private:
PthreadMutex m; int protocol; enum Progress {
LOCK_INITIALIZED,
LOCK_CHILD_READY,
LOCK_WAITING,
LOCK_RELEASED,
};
std::atomic<Progress> progress;
std::atomic<pid_t> main_tid;
std::atomic<pid_t> child_tid;
PthreadMutex start_thread_m;
// Check we wait long enough for the lock before timing out...
// What time is it before we start?
ASSERT_EQ(0, clock_gettime(clock, &ts)); const int64_t start_ns = to_ns(ts); // Add a second to get deadline, and wait until we time out.
ts.tv_sec += 1;
ASSERT_EQ(ETIMEDOUT, lock_function(&m, &ts));
// What time is it now we've timed out?
timespec ts2;
clock_gettime(clock, &ts2); const int64_t end_ns = to_ns(ts2);
// The timedlock must have waited at least 1 second before returning.
ASSERT_GE(end_ns - start_ns, NS_PER_S);
// If the mutex is unlocked, pthread_mutex_timedlock should succeed.
ASSERT_EQ(0, pthread_mutex_unlock(&m));
ASSERT_EQ(0, clock_gettime(clock, &ts));
ts.tv_sec += 1;
ASSERT_EQ(0, lock_function(&m, &ts));
// The timedlock must have waited at least 1 second before returning.
clock_gettime(clock, &ts); const int64_t end_ns = ts.tv_sec * NS_PER_S + ts.tv_nsec;
ASSERT_GT(end_ns - start_ns, NS_PER_S);
TEST_F(pthread_DeathTest, pthread_mutex_using_destroyed_mutex) { #ifdefined(__BIONIC__)
pthread_mutex_t m;
ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
ASSERT_EQ(0, pthread_mutex_destroy(&m));
ASSERT_EXIT(pthread_mutex_lock(&m), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_lock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_unlock(&m), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_unlock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_trylock(&m), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_trylock called on a destroyed mutex");
timespec ts;
ASSERT_EXIT(pthread_mutex_timedlock(&m, &ts), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_timedlock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_timedlock_monotonic_np(&m, &ts), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_timedlock_monotonic_np called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_clocklock(&m, CLOCK_MONOTONIC, &ts), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_clocklock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_clocklock(&m, CLOCK_REALTIME, &ts), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_clocklock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_clocklock(&m, CLOCK_PROCESS_CPUTIME_ID, &ts),
::testing::KilledBySignal(SIGABRT), "pthread_mutex_clocklock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_destroy(&m), ::testing::KilledBySignal(SIGABRT), "pthread_mutex_destroy called on a destroyed mutex"); #else
GTEST_SKIP() << "bionic-only test"; #endif
}
class StrictAlignmentAllocator { public: void* allocate(size_t size, size_t alignment) { char* p = newchar[size + alignment * 2];
allocated_array.push_back(p); while (!is_strict_aligned(p, alignment)) {
++p;
} return p;
}
~StrictAlignmentAllocator() { for (constauto& p : allocated_array) { delete[] p;
}
}
TEST(pthread, pthread_types_allow_four_bytes_alignment) { #ifdefined(__BIONIC__) // For binary compatibility with old version, we need to allow 4-byte aligned data for pthread types.
StrictAlignmentAllocator allocator;
pthread_mutex_t* mutex = reinterpret_cast<pthread_mutex_t*>(
allocator.allocate(sizeof(pthread_mutex_t), 4));
ASSERT_EQ(0, pthread_mutex_init(mutex, nullptr));
ASSERT_EQ(0, pthread_mutex_lock(mutex));
ASSERT_EQ(0, pthread_mutex_unlock(mutex));
ASSERT_EQ(0, pthread_mutex_destroy(mutex));
TEST(pthread, pthread_mutex_lock_null_32) { #ifdefined(__BIONIC__) && !defined(__LP64__) // For LP32, the pthread lock/unlock functions allow a NULL mutex and return // EINVAL in that case: http://b/19995172. // // We decorate the public defintion with _Nonnull so that people recompiling // their code with get a warning and might fix their bug, but need to pass // NULL here to test that we remain compatible.
pthread_mutex_t* null_value = nullptr;
ASSERT_EQ(EINVAL, pthread_mutex_lock(null_value)); #else
GTEST_SKIP() << "32-bit bionic-only test"; #endif
}
TEST(pthread, pthread_mutex_unlock_null_32) { #ifdefined(__BIONIC__) && !defined(__LP64__) // For LP32, the pthread lock/unlock functions allow a NULL mutex and return // EINVAL in that case: http://b/19995172. // // We decorate the public defintion with _Nonnull so that people recompiling // their code with get a warning and might fix their bug, but need to pass // NULL here to test that we remain compatible.
pthread_mutex_t* null_value = nullptr;
ASSERT_EQ(EINVAL, pthread_mutex_unlock(null_value)); #else
GTEST_SKIP() << "32-bit bionic-only test"; #endif
}
__attribute__((__noinline__)) staticvoid signal_handler_backtrace() { // Check if we have enough stack space for unwinding. int count = 0;
_Unwind_Backtrace(FrameCounter, &count);
ASSERT_GT(count, 0);
}
__attribute__((__noinline__)) staticvoid signal_handler_logging() { // Check if we have enough stack space for logging.
std::string s(2048, '*');
GTEST_LOG_(INFO) << s;
signal_handler_on_altstack_done = true;
}
__attribute__((__noinline__)) staticvoid signal_handler_snprintf() { // Check if we have enough stack space for snprintf to a PATH_MAX buffer, plus some extra. char buf[PATH_MAX + 2048];
ASSERT_GT(snprintf(buf, sizeof(buf), "/proc/%d/status", getpid()), 0);
}
TEST(pthread, pthread_create__mmap_failures) { // After thread is successfully created, native_bridge might need more memory to run it.
SKIP_WITH_NATIVE_BRIDGE;
// Use up all the VMAs. By default this is 64Ki (though some will already be in use).
std::vector<void*> pages;
pages.reserve(64 * 1024); int prot = PROT_NONE; while (true) { void* page = mmap(nullptr, kPageSize, prot, MAP_ANON|MAP_PRIVATE, -1, 0); if (page == MAP_FAILED) break;
pages.push_back(page);
prot = (prot == PROT_NONE) ? PROT_READ : PROT_NONE;
}
// Try creating threads, freeing up a page each time we fail.
size_t EAGAIN_count = 0;
size_t i = 0; for (; i < pages.size(); ++i) {
pthread_t t; int status = pthread_create(&t, &attr, IdFn, nullptr); if (status != EAGAIN) break;
++EAGAIN_count;
ASSERT_EQ(0, munmap(pages[i], kPageSize));
}
// Creating a thread uses at least three VMAs: the combined stack and TLS, and a guard on each // side. So we should have seen at least three failures.
ASSERT_GE(EAGAIN_count, 3U);
for (; i < pages.size(); ++i) {
ASSERT_EQ(0, munmap(pages[i], kPageSize));
}
}
#ifdefined(__LP64__) // If we ask to use them, though, we'll see a failure...
ASSERT_EQ(0, pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED));
ASSERT_EQ(EINVAL, pthread_create(&t, &attr, IdFn, nullptr)); #else // For backwards compatibility with broken apps, we just ignore failures // to set scheduler attributes on LP32. #endif
}
TEST(pthread, pthread_attr_setinheritsched_PTHREAD_INHERIT_SCHED_takes_effect) {
sched_param param = { .sched_priority = sched_get_priority_min(SCHED_FIFO) }; int rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); if (rc == EPERM) GTEST_SKIP() << "pthread_setschedparam failed with EPERM";
ASSERT_EQ(0, rc);
TEST(pthread, pthread_setaffinity_np_failure) { // Trivial test of the errno-preserving/returning behavior. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnonnull"
ASSERT_ERRNO_FAILURE(0, EINVAL, pthread_setaffinity_np(pthread_self(), 0, nullptr)); #pragma clang diagnostic pop
}
TEST(pthread, pthread_setaffinity) {
cpu_set_t set;
CPU_ZERO(&set);
ASSERT_EQ(0, pthread_getaffinity_np(pthread_self(), sizeof(set), &set)); // It's hard to make any more general claim than this, // but it ought to be safe to ask for the same affinity you already have.
ASSERT_EQ(0, pthread_setaffinity_np(pthread_self(), sizeof(set), &set));
}
#ifdefined(__aarch64__)
staticvoid* sme_state_checking_thread(void*) { // Expected state in the child thread: // - PSTATE.SM is 0 // - PSTATE.ZA is 0 // - TPIDR2_EL0 is 0
EXPECT_FALSE(sme_is_sm_on());
EXPECT_FALSE(sme_is_za_on());
EXPECT_EQ(0UL, sme_tpidr2_el0());
return nullptr;
}
staticvoid create_thread() {
pthread_t thread; // Even if these asserts fail sme_state_cleanup() will still be run.
ASSERT_EQ(0, pthread_create(&thread, nullptr, &sme_state_checking_thread, nullptr));
ASSERT_EQ(0, pthread_join(thread, nullptr));
}
// It is expected that the new thread is started with SME off.
TEST(pthread, pthread_create_with_sme_off) { if (!sme_is_enabled()) {
GTEST_SKIP() << "FEAT_SME is not enabled on the device.";
}
// It is safe to call __arm_za_disable(). This is required to avoid inter-test dependencies.
__arm_za_disable();
create_thread();
sme_state_cleanup();
}
// It is expected that the new thread is started with SME off.
TEST(pthread, pthread_create_with_sme_dormant_state) { if (!sme_is_enabled()) {
GTEST_SKIP() << "FEAT_SME is not enabled on the device.";
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.