summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.xcodeproj/project.pbxproj6
-rw-r--r--base/condition_variable_test.cc167
-rw-r--r--base/spin_wait.h3
3 files changed, 87 insertions, 89 deletions
diff --git a/base/base.xcodeproj/project.pbxproj b/base/base.xcodeproj/project.pbxproj
index 3ae34ed..6a5372c 100644
--- a/base/base.xcodeproj/project.pbxproj
+++ b/base/base.xcodeproj/project.pbxproj
@@ -133,6 +133,7 @@
ABFBD3E60DC793C600E164CB /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 825403290D92D2090006B936 /* md5.cc */; };
BA739A020E5E3242009842A7 /* tracked_objects_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA739A000E5E3242009842A7 /* tracked_objects_test.cc */; };
BA739A030E5E3242009842A7 /* timer_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA739A010E5E3242009842A7 /* timer_unittest.cc */; };
+ BA73AA330E5F614B00A20026 /* condition_variable_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA73AA320E5F614B00A20026 /* condition_variable_test.cc */; };
E45062A60E40A9BE0025A81A /* base_switches.cc in Sources */ = {isa = PBXBuildFile; fileRef = 825402CB0D92D1390006B936 /* base_switches.cc */; };
E48A05F70E3F61B300172919 /* command_line.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4A133490E37A41D00110AA2 /* command_line.cc */; };
E48A06710E3F70E200172919 /* convolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = E48A06680E3F70B500172919 /* convolver.cc */; };
@@ -513,6 +514,8 @@
ABF4B9B40DC2BC9F00A6E319 /* path_service.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = path_service.cc; sourceTree = "<group>"; };
BA739A000E5E3242009842A7 /* tracked_objects_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tracked_objects_test.cc; sourceTree = "<group>"; };
BA739A010E5E3242009842A7 /* timer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timer_unittest.cc; sourceTree = "<group>"; };
+ BA73AA320E5F614B00A20026 /* condition_variable_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = condition_variable_test.cc; sourceTree = "<group>"; };
+ BA73AA420E5F62F400A20026 /* spin_wait.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spin_wait.h; sourceTree = "<group>"; };
E45629E40E27C058005E4685 /* rect_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rect_unittest.cc; sourceTree = "<group>"; };
E4562A200E27C8C1005E4685 /* png_codec_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = png_codec_unittest.cc; sourceTree = "<group>"; };
E4562A2A0E27CA2F005E4685 /* libpng.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libpng.xcodeproj; path = third_party/libpng/libpng.xcodeproj; sourceTree = "<group>"; };
@@ -703,6 +706,7 @@
7BAFFC8A0E5E0CC000797CC4 /* compiler_specific.h */,
825402EB0D92D1940006B936 /* condition_variable.h */,
824653670DC12CEC007C2BAA /* condition_variable_posix.cc */,
+ BA73AA320E5F614B00A20026 /* condition_variable_test.cc */,
825402F40D92D1AC0006B936 /* debug_on_start.cc */,
825402F30D92D1AC0006B936 /* debug_on_start.h */,
825402F20D92D1AC0006B936 /* debug_util.cc */,
@@ -806,6 +810,7 @@
824653730DC12D0E007C2BAA /* shared_memory_posix.cc */,
7BD9E84E0DA447F800FC7A01 /* singleton.h */,
E4AFA4BE0E50DE7400201347 /* singleton_unittest.cc */,
+ BA73AA420E5F62F400A20026 /* spin_wait.h */,
825403770D92D2CF0006B936 /* stack_container.h */,
E491165C0E48A51E001EE8C3 /* stack_container_unittest.cc */,
825403780D92D2CF0006B936 /* stats_counters.h */,
@@ -1211,6 +1216,7 @@
files = (
7B78D38E0E54FE0100609465 /* at_exit_unittest.cc in Sources */,
7B78D38F0E54FE0100609465 /* command_line_unittest.cc in Sources */,
+ BA73AA330E5F614B00A20026 /* condition_variable_test.cc in Sources */,
7B8505D40E5B43FE00730B43 /* convolver_unittest.cc in Sources */,
A5CE1D2B0E55F4D800AD0606 /* file_util_unittest.cc in Sources */,
7B78D3910E54FE0100609465 /* file_version_info_unittest.cc in Sources */,
diff --git a/base/condition_variable_test.cc b/base/condition_variable_test.cc
index ff4d71e..6952567 100644
--- a/base/condition_variable_test.cc
+++ b/base/condition_variable_test.cc
@@ -35,6 +35,7 @@
#include "base/condition_variable.h"
#include "base/logging.h"
+#include "base/platform_thread.h"
#include "base/scoped_ptr.h"
#include "base/spin_wait.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -73,17 +74,18 @@ class ConditionVariableTest : public testing::Test {
// cases will validate that the WorkQueue has records showing that the desired
// activities were performed.
//------------------------------------------------------------------------------
-// Forward declare the WorkerProcess task
-static DWORD WINAPI WorkerProcess(void* p);
// Callers are responsible for synchronizing access to the following class.
// The WorkQueue::lock_, as accessed via WorkQueue::lock(), should be used for
// all synchronized access.
-class WorkQueue {
+class WorkQueue : public PlatformThread::Delegate {
public:
explicit WorkQueue(int thread_count);
~WorkQueue();
+ // PlatformThread::Delegate interface.
+ void ThreadMain();
+
//----------------------------------------------------------------------------
// Worker threads only call the following methods.
// They should use the lock to get exclusive access.
@@ -130,7 +132,7 @@ class WorkQueue {
ConditionVariable no_more_tasks_; // Task count is zero.
const int thread_count_;
- scoped_array<HANDLE> handles_;
+ scoped_array<PlatformThreadHandle> thread_handles_;
std::vector<int> assignment_history_; // Number of assignment per worker.
std::vector<int> completion_history_; // Number of completions per worker.
int thread_started_counter_; // Used to issue unique id to workers.
@@ -142,72 +144,6 @@ class WorkQueue {
};
//------------------------------------------------------------------------------
-// Define the standard worker task. Several tests will spin out many of these
-// threads.
-//------------------------------------------------------------------------------
-
-// The multithread tests involve several threads with a task to perform as
-// directed by an instance of the class WorkQueue.
-// The task is to:
-// a) Check to see if there are more tasks (there is a task counter).
-// a1) Wait on condition variable if there are no tasks currently.
-// b) Call a function to see what should be done.
-// c) Do some computation based on the number of milliseconds returned in (b).
-// d) go back to (a).
-
-// WorkerProcess() implements the above task for all threads.
-// It calls the controlling object to tell the creator about progress, and to
-// ask about tasks.
-static DWORD WINAPI WorkerProcess(void* p) {
- int thread_id;
- class WorkQueue* queue = reinterpret_cast<WorkQueue*>(p);
- {
- AutoLock auto_lock(*queue->lock());
- thread_id = queue->GetThreadId();
- if (queue->EveryIdWasAllocated())
- queue->all_threads_have_ids()->Signal(); // Tell creator we're ready.
- }
-
- Lock private_lock; // Used to waste time on "our work".
- while (1) { // This is the main consumer loop.
- TimeDelta work_time;
- bool could_use_help;
- {
- AutoLock auto_lock(*queue->lock());
- while (0 == queue->task_count() && !queue->shutdown()) {
- queue->work_is_available()->Wait();
- }
- if (queue->shutdown()) {
- // Ack the notification of a shutdown message back to the controller.
- queue->thread_shutting_down();
- return 0; // Terminate.
- }
- // Get our task duration from the queue.
- work_time = queue->GetAnAssignment(thread_id);
- could_use_help = (queue->task_count() > 0) &&
- queue->allow_help_requests();
- } // Release lock
-
- // Do work (outside of locked region.
- if (could_use_help)
- queue->work_is_available()->Signal(); // Get help from other threads.
-
- if (work_time > TimeDelta::FromMilliseconds(0)) {
- // We could just sleep(), but we'll instead further exercise the
- // condition variable class, and do a timed wait.
- AutoLock auto_lock(private_lock);
- ConditionVariable private_cv(&private_lock);
- private_cv.TimedWait(work_time); // Unsynchronized waiting.
- }
-
- {
- AutoLock auto_lock(*queue->lock());
- // Send notification that we completed our "work."
- queue->WorkIsCompleted(thread_id);
- }
- }
-}
-//------------------------------------------------------------------------------
// The next section contains the actual tests.
//------------------------------------------------------------------------------
@@ -414,7 +350,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
queue.shutdown_task_count() == kThreadCount);
- Sleep(10); // Be sure they're all shutdown.
+ PlatformThread::Sleep(10); // Be sure they're all shutdown.
}
TEST_F(ConditionVariableTest, LargeFastTaskTest) {
@@ -514,7 +450,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
// Wait for shutdowns to complete.
SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
queue.shutdown_task_count() == kThreadCount);
- Sleep(10); // Be sure they're all shutdown.
+ PlatformThread::Sleep(10); // Be sure they're all shutdown.
}
//------------------------------------------------------------------------------
@@ -527,7 +463,7 @@ WorkQueue::WorkQueue(int thread_count)
all_threads_have_ids_(&lock_),
no_more_tasks_(&lock_),
thread_count_(thread_count),
- handles_(new HANDLE[thread_count]),
+ thread_handles_(new PlatformThreadHandle[thread_count]),
assignment_history_(thread_count),
completion_history_(thread_count),
thread_started_counter_(0),
@@ -541,13 +477,9 @@ WorkQueue::WorkQueue(int thread_count)
SetWorkTime(TimeDelta::FromMilliseconds(30));
for (int i = 0; i < thread_count_; ++i) {
- handles_[i] = CreateThread(NULL, // security.
- 0, // <64K stack size.
- WorkerProcess, // Static function.
- reinterpret_cast<void*>(this),
- 0, // Create running process.
- NULL); // OS version of thread id.
- EXPECT_NE(reinterpret_cast<void*>(NULL), handles_[i]);
+ PlatformThreadHandle pth;
+ EXPECT_TRUE(PlatformThread::Create(0, this, &pth));
+ thread_handles_[i] = pth;
}
}
@@ -557,16 +489,9 @@ WorkQueue::~WorkQueue() {
SetShutdown();
}
work_is_available_.Broadcast(); // Tell them all to terminate.
- DWORD result = WaitForMultipleObjects(
- thread_count_,
- &handles_[0],
- true, // Wait for all
- 10000); // Ten seconds max.
for (int i = 0; i < thread_count_; ++i) {
- int ret_value = CloseHandle(handles_[i]);
- CHECK(ret_value);
- handles_[i] = NULL;
+ PlatformThread::Join(thread_handles_[i]);
}
}
@@ -688,4 +613,70 @@ void WorkQueue::SetShutdown() {
shutdown_ = true;
}
+//------------------------------------------------------------------------------
+// Define the standard worker task. Several tests will spin out many of these
+// threads.
+//------------------------------------------------------------------------------
+
+// The multithread tests involve several threads with a task to perform as
+// directed by an instance of the class WorkQueue.
+// The task is to:
+// a) Check to see if there are more tasks (there is a task counter).
+// a1) Wait on condition variable if there are no tasks currently.
+// b) Call a function to see what should be done.
+// c) Do some computation based on the number of milliseconds returned in (b).
+// d) go back to (a).
+
+// WorkQueue::ThreadMain() implements the above task for all threads.
+// It calls the controlling object to tell the creator about progress, and to
+// ask about tasks.
+
+void WorkQueue::ThreadMain() {
+ int thread_id;
+ {
+ AutoLock auto_lock(lock_);
+ thread_id = GetThreadId();
+ if (EveryIdWasAllocated())
+ all_threads_have_ids()->Signal(); // Tell creator we're ready.
+ }
+
+ Lock private_lock; // Used to waste time on "our work".
+ while (1) { // This is the main consumer loop.
+ TimeDelta work_time;
+ bool could_use_help;
+ {
+ AutoLock auto_lock(lock_);
+ while (0 == task_count() && !shutdown()) {
+ work_is_available()->Wait();
+ }
+ if (shutdown()) {
+ // Ack the notification of a shutdown message back to the controller.
+ thread_shutting_down();
+ return; // Terminate.
+ }
+ // Get our task duration from the queue.
+ work_time = GetAnAssignment(thread_id);
+ could_use_help = (task_count() > 0) && allow_help_requests();
+ } // Release lock
+
+ // Do work (outside of locked region.
+ if (could_use_help)
+ work_is_available()->Signal(); // Get help from other threads.
+
+ if (work_time > TimeDelta::FromMilliseconds(0)) {
+ // We could just sleep(), but we'll instead further exercise the
+ // condition variable class, and do a timed wait.
+ AutoLock auto_lock(private_lock);
+ ConditionVariable private_cv(&private_lock);
+ private_cv.TimedWait(work_time); // Unsynchronized waiting.
+ }
+
+ {
+ AutoLock auto_lock(lock_);
+ // Send notification that we completed our "work."
+ WorkIsCompleted(thread_id);
+ }
+ }
+}
+
} // namespace
diff --git a/base/spin_wait.h b/base/spin_wait.h
index 7226387..31628bb 100644
--- a/base/spin_wait.h
+++ b/base/spin_wait.h
@@ -40,6 +40,7 @@
#ifndef BASE_SPIN_WAIT_H__
#define BASE_SPIN_WAIT_H__
+#include "base/platform_thread.h"
#include "base/time.h"
// Provide a macro that will wait no longer than 1 second for an asynchronous
@@ -66,7 +67,7 @@
kTimeout.InMilliseconds()) << "Timed out"; \
break; \
} \
- Sleep(50); \
+ PlatformThread::Sleep(50); \
} \
} \
while(0)