-
Notifications
You must be signed in to change notification settings - Fork 124
semaphore_test.cc: add TimedWaitSpuriousWakeupLinux #1037
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
b9da066
50d9f7d
b58cec2
f3fd1f5
54c9b26
798ee35
69bcc57
ae0036d
9204a3a
1ea2d0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,18 @@ | |
#include "gmock/gmock.h" | ||
#include "gtest/gtest.h" | ||
|
||
// Set SEMAPHORE_LINUX to reflect whether the platform is "Linux", using the | ||
// same logic that semaphore.h uses. | ||
#if FIREBASE_PLATFORM_OSX || FIREBASE_PLATFORM_IOS || \ | ||
FIREBASE_PLATFORM_TVOS || FIREBASE_PLATFORM_WINDOWS | ||
#define SEMAPHORE_LINUX 0 | ||
#else | ||
#define SEMAPHORE_LINUX 1 | ||
#include <pthread.h> | ||
|
||
#include <csignal> | ||
#endif | ||
|
||
namespace { | ||
|
||
// Basic test of TryWait, to make sure that its successes and failures | ||
|
@@ -76,6 +88,43 @@ TEST(SemaphoreTest, TimedWait) { | |
0.20 * firebase::internal::kMillisecondsPerSecond); | ||
} | ||
|
||
#if SEMAPHORE_LINUX | ||
// Tests that Timed Wait handles spurious wakeup (Linux/Android specific). | ||
TEST(SemaphoreTest, TimedWaitSpuriousWakeupLinux) { | ||
// Register a dummy signal handler for SIGUSR1; otherwise, sending SIGUSR1 | ||
// later on will crash the application. | ||
signal(SIGUSR1, [](int signum) -> void {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this actually need the trailing return type syntax? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No it does not. I've removed the trailing return. |
||
|
||
// Start a thread that will send SIGUSR1 to this thread in a few moments. | ||
pthread_t main_thread = pthread_self(); | ||
firebase::Thread signal_sending_thread = firebase::Thread( | ||
[](void* arg) { | ||
firebase::internal::Sleep(500); | ||
pthread_kill(*static_cast<pthread_t*>(arg), SIGUSR1); | ||
}, | ||
&main_thread); | ||
|
||
// Call Semaphore::TimedWait() and keep track of how long it blocks for. | ||
firebase::Semaphore sem(0); | ||
int64_t start_ms = firebase::internal::GetTimestamp(); | ||
EXPECT_FALSE(sem.TimedWait(2 * firebase::internal::kMillisecondsPerSecond)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 * firebase::internal::kMillisecondsPerSecond should be in a constant in this function, for clarity There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
int64_t finish_ms = firebase::internal::GetTimestamp(); | ||
|
||
// Wait for the "signal sending" thread to terminate, since it references | ||
// memory on the stack and we can't have it running after this method returns. | ||
signal_sending_thread.Join(); | ||
|
||
// Unregister the signal handler for SIGUSR1, since it's no longer needed. | ||
signal(SIGUSR1, NULL); | ||
|
||
// Make sure that Semaphore::TimedWait() blocked for the entire timeout, and, | ||
// specifically, did NOT return early as a result of the SIGUSR1 interruption. | ||
ASSERT_LT(labs((finish_ms - start_ms) - | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just use EXPECT_NEAR here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, EXPECT_NEAR works perfectly. Done. |
||
(2 * firebase::internal::kMillisecondsPerSecond)), | ||
0.20 * firebase::internal::kMillisecondsPerSecond); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The allowed delta should probably also be in a constant There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
} | ||
#endif // #if SEMAPHORE_LINUX | ||
|
||
TEST(SemaphoreTest, DISABLED_MultithreadedStressTest) { | ||
for (int i = 0; i < 10000; ++i) { | ||
firebase::Semaphore sem(0); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT about just using #ifdef FIREBASE_ANDROID || FIREBASE_LINUX here and above? To me that's clearer, even though it's not the same as the check in semaphore.h.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.