13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Use of this source code is governed by a BSD-style license that can be
306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// found in the LICENSE file.
406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <iosfwd>
606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <sstream>
706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <string>
806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <vector>
906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/basictypes.h"
1106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/message_loop.h"
1206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/port.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
1406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "build/build_config.h"
1506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/deprecated/event_sys-inl.h"
1606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "testing/gtest/include/gtest/gtest.h"
1706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochnamespace {
1906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass Pair;
2106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstruct TestEvent {
2306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Pair* source;
2406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  enum {
2506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    A_CHANGED, B_CHANGED, PAIR_BEING_DELETED,
2606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } what_happened;
2706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int old_value;
2806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
2906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstruct TestEventTraits {
3106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef TestEvent EventType;
3206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  static bool IsChannelShutdownEvent(const TestEvent& event) {
3306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return TestEvent::PAIR_BEING_DELETED == event.what_happened;
3406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
3506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
3606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass Pair {
3806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
3906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef EventChannel<TestEventTraits> Channel;
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  explicit Pair(const std::string& name) : name_(name), a_(0), b_(0) {
4106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    TestEvent shutdown = { this, TestEvent::PAIR_BEING_DELETED, 0 };
4206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    event_channel_ = new Channel(shutdown);
4306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
4406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ~Pair() {
4506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    delete event_channel_;
4606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
4706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void set_a(int n) {
4806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    TestEvent event = { this, TestEvent::A_CHANGED, a_ };
4906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    a_ = n;
5006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    event_channel_->NotifyListeners(event);
5106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
5206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void set_b(int n) {
5306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    TestEvent event = { this, TestEvent::B_CHANGED, b_ };
5406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    b_ = n;
5506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    event_channel_->NotifyListeners(event);
5606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
5706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int a() const { return a_; }
5806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int b() const { return b_; }
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const std::string& name() { return name_; }
6006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Channel* event_channel() const { return event_channel_; }
6106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
6206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch protected:
63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const std::string name_;
6406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int a_;
6506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int b_;
6606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Channel* event_channel_;
6706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
6806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
6906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass EventLogger {
7006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  explicit EventLogger(std::ostream* out) : out_(out) { }
7206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ~EventLogger() {
7306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    for (Hookups::iterator i = hookups_.begin(); i != hookups_.end(); ++i)
7406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      delete *i;
7506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
7606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  void Hookup(const std::string name, Pair::Channel* channel) {
7806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    hookups_.push_back(NewEventListenerHookup(channel, this,
7906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                              &EventLogger::HandlePairEvent,
8006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                              name));
8106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
8206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  void HandlePairEvent(const std::string& name, const TestEvent& event) {
8406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const char* what_changed = NULL;
8506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    int new_value = 0;
8606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    Hookups::iterator dead;
8706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    switch (event.what_happened) {
8806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    case TestEvent::A_CHANGED:
8906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      what_changed = "A";
9006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      new_value = event.source->a();
9106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      break;
9206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    case TestEvent::B_CHANGED:
9306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      what_changed = "B";
9406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      new_value = event.source->b();
9506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      break;
9606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    case TestEvent::PAIR_BEING_DELETED:
97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      *out_ << name << " heard " << event.source->name() << " being deleted."
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            << std::endl;
9906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      return;
10006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    default:
10106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      FAIL() << "Bad event.what_happened: " << event.what_happened;
10206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      break;
10306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    *out_ << name << " heard " << event.source->name() << "'s " << what_changed
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          << " change from " << event.old_value
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          << " to " << new_value << std::endl;
10706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
10806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  typedef std::vector<EventListenerHookup*> Hookups;
11006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Hookups hookups_;
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::ostream* out_;
11206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
11306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
11406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochconst char golden_result[] = "Larry heard Sally's B change from 0 to 2\n"
11506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch"Larry heard Sally's A change from 1 to 3\n"
11606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch"Lewis heard Sam's B change from 0 to 5\n"
11706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch"Larry heard Sally's A change from 3 to 6\n"
11806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch"Larry heard Sally being deleted.\n";
11906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
12006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochTEST(EventSys, Basic) {
12106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Pair sally("Sally"), sam("Sam");
12206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.set_a(1);
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::stringstream log;
124731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  EventLogger logger(&log);
12506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  logger.Hookup("Larry", sally.event_channel());
12606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.set_b(2);
12706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.set_a(3);
12806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sam.set_a(4);
12906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  logger.Hookup("Lewis", sam.event_channel());
13006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sam.set_b(5);
13106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.set_a(6);
13206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Test that disconnect within callback doesn't deadlock.
13306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 };
13406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.event_channel()->NotifyListeners(event);
13506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.set_a(7);
13606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ASSERT_EQ(log.str(), golden_result);
13706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
13806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
13906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
14006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// This goes pretty far beyond the normal use pattern, so don't use
14106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// ThreadTester as an example of what to do.
14206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass ThreadTester : public EventListener<TestEvent>,
1433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                     public base::PlatformThread::Delegate {
14406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
14506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  explicit ThreadTester(Pair* pair)
14606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : pair_(pair), remove_event_(&remove_event_mutex_),
14706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      remove_event_bool_(false), completed_(false) {
14806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    pair_->event_channel()->AddListener(this);
14906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
15006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ~ThreadTester() {
15106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    pair_->event_channel()->RemoveListener(this);
15206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    for (size_t i = 0; i < threads_.size(); i++) {
1533f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      base::PlatformThread::Join(threads_[i].thread);
15406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
15506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
15606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
15706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  struct ThreadInfo {
1583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::PlatformThreadHandle thread;
15906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  };
16006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
16106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  struct ThreadArgs {
1623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::ConditionVariable* thread_running_cond;
1633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::Lock* thread_running_mutex;
16406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    bool thread_running;
16506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  };
16606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
16706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void Go() {
1683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::Lock thread_running_mutex;
1693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::ConditionVariable thread_running_cond(&thread_running_mutex);
17006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ThreadArgs args;
17106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ThreadInfo info;
17206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args.thread_running_cond = &(thread_running_cond);
17306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args.thread_running_mutex = &(thread_running_mutex);
17406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args.thread_running = false;
17506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args_ = args;
1763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    ASSERT_TRUE(base::PlatformThread::Create(0, this, &info.thread));
17706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    thread_running_mutex.Acquire();
17806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    while ((args_.thread_running) == false) {
17906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      thread_running_cond.Wait();
18006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
18106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    thread_running_mutex.Release();
18206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    threads_.push_back(info);
18306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
18406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
18506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // PlatformThread::Delegate methods.
18606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  virtual void ThreadMain() {
18706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Make sure each thread gets a current MessageLoop in TLS.
18806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // This test should use chrome threads for testing, but I'll leave it like
18906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // this for the moment since it requires a big chunk of rewriting and I
19006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // want the test passing while I checkpoint my CL.  Technically speaking,
19106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // there should be no functional difference.
19206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    MessageLoop message_loop;
19306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args_.thread_running_mutex->Acquire();
19406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args_.thread_running = true;
19506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args_.thread_running_cond->Signal();
19606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    args_.thread_running_mutex->Release();
19706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
19806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    remove_event_mutex_.Acquire();
19906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    while (remove_event_bool_ == false) {
20006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      remove_event_.Wait();
20106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
20206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    remove_event_mutex_.Release();
20306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
20406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Normally, you'd just delete the hookup. This is very bad style, but
20506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // necessary for the test.
20606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    pair_->event_channel()->RemoveListener(this);
20706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
20806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    completed_mutex_.Acquire();
20906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    completed_ = true;
21006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    completed_mutex_.Release();
21106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
21206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
21306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void HandleEvent(const TestEvent& event) {
21406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    remove_event_mutex_.Acquire();
21506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    remove_event_bool_ = true;
21606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    remove_event_.Broadcast();
21706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    remove_event_mutex_.Release();
21806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2193f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::PlatformThread::YieldCurrentThread();
22006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
22106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    completed_mutex_.Acquire();
22206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (completed_)
22306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      FAIL() << "A test thread exited too early.";
22406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    completed_mutex_.Release();
22506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
22606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
22706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Pair* pair_;
2283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::ConditionVariable remove_event_;
2293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::Lock remove_event_mutex_;
23006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  bool remove_event_bool_;
2313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::Lock completed_mutex_;
23206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  bool completed_;
233731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::vector<ThreadInfo> threads_;
23406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ThreadArgs args_;
23506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
23606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
23706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochTEST(EventSys, Multithreaded) {
23806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Pair sally("Sally");
23906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ThreadTester a(&sally);
24006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  for (int i = 0; i < 3; ++i)
24106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    a.Go();
24206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.set_b(99);
24306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
24406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
24506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass HookupDeleter {
24606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
24706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void HandleEvent(const TestEvent& event) {
24806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    delete hookup_;
24906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    hookup_ = NULL;
25006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
25106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  EventListenerHookup* hookup_;
25206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
25306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
25406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochTEST(EventSys, InHandlerDeletion) {
25506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Pair sally("Sally");
25606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  HookupDeleter deleter;
25706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  deleter.hookup_ = NewEventListenerHookup(sally.event_channel(),
25806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                           &deleter,
25906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                           &HookupDeleter::HandleEvent);
26006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  sally.set_a(1);
26106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ASSERT_TRUE(NULL == deleter.hookup_);
26206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
26306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
26406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}  // namespace
265