| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <iosfwd> | 5 #include <iosfwd> |
| 6 #include <sstream> | 6 #include <sstream> |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/port.h" | 13 #include "base/port.h" |
| 14 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 15 #include "chrome/browser/sync/util/event_sys-inl.h" | 15 #include "chrome/browser/sync/util/event_sys-inl.h" |
| 16 #include "chrome/browser/sync/util/pthread_helpers.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
| 18 | 17 |
| 19 using std::endl; | 18 using std::endl; |
| 20 using std::ostream; | 19 using std::ostream; |
| 21 using std::string; | 20 using std::string; |
| 22 using std::stringstream; | 21 using std::stringstream; |
| 23 using std::vector; | 22 using std::vector; |
| 24 | 23 |
| 25 namespace { | 24 namespace { |
| 26 | 25 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 // Test that disconnect within callback doesn't deadlock. | 138 // Test that disconnect within callback doesn't deadlock. |
| 140 TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 }; | 139 TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 }; |
| 141 sally.event_channel()->NotifyListeners(event); | 140 sally.event_channel()->NotifyListeners(event); |
| 142 sally.set_a(7); | 141 sally.set_a(7); |
| 143 ASSERT_EQ(log.str(), golden_result); | 142 ASSERT_EQ(log.str(), golden_result); |
| 144 } | 143 } |
| 145 | 144 |
| 146 | 145 |
| 147 // This goes pretty far beyond the normal use pattern, so don't use | 146 // This goes pretty far beyond the normal use pattern, so don't use |
| 148 // ThreadTester as an example of what to do. | 147 // ThreadTester as an example of what to do. |
| 149 class ThreadTester : public EventListener<TestEvent> { | 148 class ThreadTester : public EventListener<TestEvent>, |
| 149 public PlatformThread::Delegate { |
| 150 public: | 150 public: |
| 151 explicit ThreadTester(Pair* pair) | 151 explicit ThreadTester(Pair* pair) |
| 152 : pair_(pair), remove_event_bool_(false) { | 152 : pair_(pair), remove_event_(&remove_event_mutex_), |
| 153 remove_event_bool_(false) { |
| 153 pair_->event_channel()->AddListener(this); | 154 pair_->event_channel()->AddListener(this); |
| 154 } | 155 } |
| 155 ~ThreadTester() { | 156 ~ThreadTester() { |
| 156 pair_->event_channel()->RemoveListener(this); | 157 pair_->event_channel()->RemoveListener(this); |
| 157 for (size_t i = 0; i < threads_.size(); i++) { | 158 for (size_t i = 0; i < threads_.size(); i++) { |
| 158 CHECK(pthread_join(threads_[i].thread, NULL) == 0); | 159 PlatformThread::Join(threads_[i].thread); |
| 159 delete threads_[i].completed; | |
| 160 } | 160 } |
| 161 } | 161 } |
| 162 | 162 |
| 163 struct ThreadInfo { | 163 struct ThreadInfo { |
| 164 pthread_t thread; | 164 PlatformThreadHandle thread; |
| 165 bool* completed; | 165 bool* completed; |
| 166 }; | 166 }; |
| 167 | 167 |
| 168 struct ThreadArgs { | 168 struct ThreadArgs { |
| 169 ThreadTester* self; | 169 ConditionVariable* thread_running_cond; |
| 170 pthread_cond_t* thread_running_cond; | 170 Lock* thread_running_mutex; |
| 171 pthread_mutex_t* thread_running_mutex; | 171 bool thread_running; |
| 172 bool* thread_running; | 172 bool completed; |
| 173 bool* completed; | |
| 174 }; | 173 }; |
| 175 | 174 |
| 176 pthread_t Go() { | 175 void Go() { |
| 177 PThreadCondVar thread_running_cond; | 176 Lock thread_running_mutex; |
| 178 PThreadMutex thread_running_mutex; | 177 ConditionVariable thread_running_cond(&thread_running_mutex); |
| 179 ThreadArgs args; | 178 ThreadArgs args; |
| 180 ThreadInfo info; | 179 ThreadInfo info; |
| 181 info.completed = new bool(false); | 180 info.completed = false; |
| 182 args.self = this; | |
| 183 args.completed = info.completed; | 181 args.completed = info.completed; |
| 184 args.thread_running_cond = &(thread_running_cond.condvar_); | 182 args.thread_running_cond = &(thread_running_cond); |
| 185 args.thread_running_mutex = &(thread_running_mutex.mutex_); | 183 args.thread_running_mutex = &(thread_running_mutex); |
| 186 args.thread_running = new bool(false); | 184 args.thread_running = false; |
| 187 CHECK(0 == | 185 args_ = args; |
| 188 pthread_create(&info.thread, NULL, ThreadTester::ThreadMain, &args)); | 186 ASSERT_TRUE(PlatformThread::Create(0, this, &info.thread)); |
| 189 thread_running_mutex.Lock(); | 187 thread_running_mutex.Acquire(); |
| 190 while ((*args.thread_running) == false) { | 188 while ((args_.thread_running) == false) { |
| 191 pthread_cond_wait(&(thread_running_cond.condvar_), | 189 thread_running_cond.Wait(); |
| 192 &(thread_running_mutex.mutex_)); | |
| 193 } | 190 } |
| 194 thread_running_mutex.Unlock(); | 191 thread_running_mutex.Release(); |
| 195 delete args.thread_running; | |
| 196 threads_.push_back(info); | 192 threads_.push_back(info); |
| 197 return info.thread; | |
| 198 } | 193 } |
| 199 | 194 |
| 200 static void* ThreadMain(void* arg) { | 195 // PlatformThread::Delegate methods. |
| 196 virtual void ThreadMain() { |
| 201 // Make sure each thread gets a current MessageLoop in TLS. | 197 // Make sure each thread gets a current MessageLoop in TLS. |
| 202 // This test should use chrome threads for testing, but I'll leave it like | 198 // This test should use chrome threads for testing, but I'll leave it like |
| 203 // this for the moment since it requires a big chunk of rewriting and I | 199 // this for the moment since it requires a big chunk of rewriting and I |
| 204 // want the test passing while I checkpoint my CL. Technically speaking, | 200 // want the test passing while I checkpoint my CL. Technically speaking, |
| 205 // there should be no functional difference. | 201 // there should be no functional difference. |
| 206 MessageLoop message_loop; | 202 MessageLoop message_loop; |
| 207 ThreadArgs args = *reinterpret_cast<ThreadArgs*>(arg); | 203 args_.thread_running_mutex->Acquire(); |
| 208 pthread_mutex_lock(args.thread_running_mutex); | 204 args_.thread_running = true; |
| 209 *args.thread_running = true; | 205 args_.thread_running_mutex->Release(); |
| 210 pthread_cond_signal(args.thread_running_cond); | 206 args_.thread_running_cond->Signal(); |
| 211 pthread_mutex_unlock(args.thread_running_mutex); | |
| 212 | 207 |
| 213 args.self->remove_event_mutex_.Lock(); | 208 remove_event_mutex_.Acquire(); |
| 214 while (args.self->remove_event_bool_ == false) { | 209 while (remove_event_bool_ == false) { |
| 215 pthread_cond_wait(&args.self->remove_event_.condvar_, | 210 remove_event_.Wait(); |
| 216 &args.self->remove_event_mutex_.mutex_); | |
| 217 } | 211 } |
| 218 args.self->remove_event_mutex_.Unlock(); | 212 remove_event_mutex_.Release(); |
| 219 | 213 |
| 220 // Normally, you'd just delete the hookup. This is very bad style, but | 214 // Normally, you'd just delete the hookup. This is very bad style, but |
| 221 // necessary for the test. | 215 // necessary for the test. |
| 222 args.self->pair_->event_channel()->RemoveListener(args.self); | 216 pair_->event_channel()->RemoveListener(this); |
| 223 *args.completed = true; | 217 args_.completed = true; |
| 224 return 0; | |
| 225 } | 218 } |
| 226 | 219 |
| 227 void HandleEvent(const TestEvent& event) { | 220 void HandleEvent(const TestEvent& event) { |
| 228 remove_event_mutex_.Lock(); | 221 remove_event_mutex_.Acquire(); |
| 229 remove_event_bool_ = true; | 222 remove_event_bool_ = true; |
| 230 pthread_cond_broadcast(&remove_event_.condvar_); | 223 remove_event_mutex_.Release(); |
| 231 remove_event_mutex_.Unlock(); | 224 remove_event_.Broadcast(); |
| 232 | 225 |
| 233 // Windows and posix use different functions to sleep. | 226 // Windows and posix use different functions to sleep. |
| 234 #ifdef OS_WIN | 227 #ifdef OS_WIN |
| 235 Sleep(1); | 228 Sleep(1); |
| 236 #else | 229 #else |
| 237 sleep(1); | 230 sleep(1); |
| 238 #endif | 231 #endif |
| 239 | 232 |
| 240 for (size_t i = 0; i < threads_.size(); i++) { | 233 for (size_t i = 0; i < threads_.size(); i++) { |
| 241 if (*(threads_[i].completed)) | 234 if (threads_[i].completed) |
| 242 LOG(FATAL) << "A test thread exited too early."; | 235 LOG(FATAL) << "A test thread exited too early."; |
| 243 } | 236 } |
| 244 } | 237 } |
| 245 | 238 |
| 246 Pair* pair_; | 239 Pair* pair_; |
| 247 PThreadCondVar remove_event_; | 240 ConditionVariable remove_event_; |
| 248 PThreadMutex remove_event_mutex_; | 241 Lock remove_event_mutex_; |
| 249 bool remove_event_bool_; | 242 bool remove_event_bool_; |
| 250 vector<ThreadInfo> threads_; | 243 vector<ThreadInfo> threads_; |
| 244 ThreadArgs args_; |
| 251 }; | 245 }; |
| 252 | 246 |
| 253 TEST(EventSys, Multithreaded) { | 247 TEST(EventSys, Multithreaded) { |
| 254 Pair sally("Sally"); | 248 Pair sally("Sally"); |
| 255 ThreadTester a(&sally); | 249 ThreadTester a(&sally); |
| 256 for (int i = 0; i < 3; ++i) | 250 for (int i = 0; i < 3; ++i) |
| 257 a.Go(); | 251 a.Go(); |
| 258 sally.set_b(99); | 252 sally.set_b(99); |
| 259 } | 253 } |
| 260 | 254 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 271 Pair sally("Sally"); | 265 Pair sally("Sally"); |
| 272 HookupDeleter deleter; | 266 HookupDeleter deleter; |
| 273 deleter.hookup_ = NewEventListenerHookup(sally.event_channel(), | 267 deleter.hookup_ = NewEventListenerHookup(sally.event_channel(), |
| 274 &deleter, | 268 &deleter, |
| 275 &HookupDeleter::HandleEvent); | 269 &HookupDeleter::HandleEvent); |
| 276 sally.set_a(1); | 270 sally.set_a(1); |
| 277 ASSERT_TRUE(NULL == deleter.hookup_); | 271 ASSERT_TRUE(NULL == deleter.hookup_); |
| 278 } | 272 } |
| 279 | 273 |
| 280 } // namespace | 274 } // namespace |
| OLD | NEW |