// Copyright 2015 Google Inc. All Rights Reserved. | |
// | |
// 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. | |
// Broadcast is Sunny Day tested in most of the other SbConditionVariable tests. | |
#include "starboard/nplb/thread_helpers.h" | |
#include "starboard/once.h" | |
#include "starboard/thread.h" | |
#include "starboard/thread_types.h" | |
#include "testing/gtest/include/gtest/gtest.h" | |
namespace starboard { | |
namespace nplb { | |
namespace { | |
int s_global_value; | |
void IncrementGlobalValue() { | |
++s_global_value; | |
} | |
TEST(SbOnceTest, SunnyDaySingleInit) { | |
SbOnceControl once_control = SB_ONCE_INITIALIZER; | |
s_global_value = 0; | |
EXPECT_TRUE(SbOnce(&once_control, &IncrementGlobalValue)); | |
EXPECT_EQ(1, s_global_value); | |
} | |
TEST(SbOnceTest, SunnyDayMultipleInit) { | |
SbOnceControl once_control = SB_ONCE_INITIALIZER; | |
s_global_value = 0; | |
EXPECT_TRUE(SbOnce(&once_control, &IncrementGlobalValue)); | |
EXPECT_EQ(1, s_global_value); | |
s_global_value = 0; | |
EXPECT_TRUE(SbOnce(&once_control, &IncrementGlobalValue)); | |
EXPECT_EQ(0, s_global_value); | |
s_global_value = 0; | |
EXPECT_TRUE(SbOnce(&once_control, &IncrementGlobalValue)); | |
EXPECT_EQ(0, s_global_value); | |
} | |
struct RunSbOnceContext { | |
RunSbOnceContext() : once_control(SB_ONCE_INITIALIZER) { | |
SbMutexCreate(&mutex); | |
SbConditionVariableCreate(&condition, &mutex); | |
} | |
~RunSbOnceContext() { | |
SbConditionVariableDestroy(&condition); | |
SbMutexDestroy(&mutex); | |
} | |
Semaphore semaphore; | |
SbMutex mutex; | |
SbConditionVariable condition; | |
SbOnceControl once_control; | |
}; | |
void* RunSbOnceEntryPoint(void* context) { | |
RunSbOnceContext* run_sbonce_context = | |
reinterpret_cast<RunSbOnceContext*>(context); | |
{ | |
SbMutexAcquire(&run_sbonce_context->mutex); | |
run_sbonce_context->semaphore.Put(); | |
SbConditionVariableWait(&run_sbonce_context->condition, | |
&run_sbonce_context->mutex); | |
SbMutexRelease(&run_sbonce_context->mutex); | |
} | |
SbThreadYield(); | |
static const int kIterationCount = 3; | |
for (int i = 0; i < kIterationCount; ++i) { | |
SbOnce(&run_sbonce_context->once_control, &IncrementGlobalValue); | |
} | |
return NULL; | |
} | |
// Here we spawn many threads each of which will call SbOnce multiple times | |
// using a shared SbOnceControl object. We then test that the initialization | |
// routine got called exactly one time. | |
TEST(SbOnceTest, SunnyDayMultipleThreadsInit) { | |
const int kMany = SB_MAX_THREADS; | |
SbThread threads[kMany]; | |
const int kIterationCount = 10; | |
for (int i = 0; i < kIterationCount; ++i) { | |
SbOnceControl once_control = SB_ONCE_INITIALIZER; | |
RunSbOnceContext context; | |
s_global_value = 0; | |
for (int i = 0; i < kMany; ++i) { | |
threads[i] = | |
SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity, true, | |
kThreadName, RunSbOnceEntryPoint, &context); | |
} | |
// Wait for all threads to finish initializing and become ready, then | |
// broadcast the signal to begin. We do this to increase the chances that | |
// threads will call SbOnce() at the same time as each other. | |
for (int i = 0; i < kMany; ++i) { | |
context.semaphore.Take(); | |
} | |
{ | |
SbMutexAcquire(&context.mutex); | |
SbConditionVariableBroadcast(&context.condition); | |
SbMutexRelease(&context.mutex); | |
} | |
// Signal threads to beginWait for all threads to complete. | |
for (int i = 0; i < kMany; ++i) { | |
void* result; | |
SbThreadJoin(threads[i], &result); | |
} | |
EXPECT_EQ(1, s_global_value); | |
} | |
} | |
TEST(SbOnceTest, RainyDayBadOnceControl) { | |
s_global_value = 0; | |
EXPECT_FALSE(SbOnce(NULL, &IncrementGlobalValue)); | |
EXPECT_EQ(0, s_global_value); | |
} | |
TEST(SbOnceTest, RainyDayBadInitRoutine) { | |
SbOnceControl once_control = SB_ONCE_INITIALIZER; | |
s_global_value = 0; | |
EXPECT_FALSE(SbOnce(&once_control, NULL)); | |
EXPECT_EQ(0, s_global_value); | |
} | |
SB_ONCE_INITIALIZE_FUNCTION(int, GetIntSingleton); | |
TEST(SbOnceTest, InitializeOnceMacroFunction) { | |
int* int_singelton = GetIntSingleton(); | |
ASSERT_TRUE(int_singelton); | |
EXPECT_EQ(0, *int_singelton) | |
<< "Singleton Macro does not default initialize."; | |
} | |
} // namespace. | |
} // namespace nplb. | |
} // namespace starboard. |