summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/weak_handle.cc
blob: 1c78307f9fab45f584cbe1264932c4cca8a99d2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/weak_handle.h"

#include <sstream>

#include "base/message_loop_proxy.h"
#include "base/tracked.h"

namespace browser_sync {

namespace internal {

WeakHandleCoreBase::WeakHandleCoreBase()
    : owner_loop_(MessageLoop::current()),
      owner_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()),
      destroyed_on_owner_thread_(false) {
  owner_loop_->AddDestructionObserver(this);
}

bool WeakHandleCoreBase::IsOnOwnerThread() const {
  // We can't use |owner_loop_proxy_->BelongsToCurrentThread()| as
  // it may not work from within a MessageLoop::DestructionObserver
  // callback.
  return MessageLoop::current() == owner_loop_;
}

void WeakHandleCoreBase::WillDestroyCurrentMessageLoop() {
  CHECK(IsOnOwnerThread());
  CHECK(!destroyed_on_owner_thread_);
  // NOTE: This function dispatches to
  // WeakHandle<T>::CleanupOnOwnerThread() (i.e., not just
  // WeakHandleCoreBase::CleanupOnOwnerThread() is run).
  CleanupOnOwnerThread();
  CHECK(destroyed_on_owner_thread_);
}

WeakHandleCoreBase::~WeakHandleCoreBase() {
  // It is safe to read |destroyed_on_owner_thread_| here even if
  // we're not on the owner thread (see comments on
  // base::AtomicRefCountDecN()).
  CHECK(destroyed_on_owner_thread_);
}

void WeakHandleCoreBase::CleanupOnOwnerThread() {
  CHECK(IsOnOwnerThread());
  CHECK(!destroyed_on_owner_thread_);
  owner_loop_->RemoveDestructionObserver(this);
  destroyed_on_owner_thread_ = true;
}

namespace {

// TODO(akalin): Merge with similar function in
// js_transaction_observer.cc.
std::string GetLocationString(const tracked_objects::Location& location) {
  std::ostringstream oss;
  oss << location.function_name() << "@"
      << location.file_name() << ":" << location.line_number();
  return oss.str();
}

}  // namespace

void WeakHandleCoreBase::PostToOwnerThread(
    const tracked_objects::Location& from_here,
    const base::Closure& fn) const {
  if (!owner_loop_proxy_->PostTask(from_here, fn)) {
    VLOG(1) << "Could not post task from " << GetLocationString(from_here);
  }
}

void WeakHandleCoreBase::Destroy() {
  if (IsOnOwnerThread()) {
    CHECK(!destroyed_on_owner_thread_);
    CleanupAndDestroyOnOwnerThread();
  } else if (!owner_loop_proxy_->PostTask(
      FROM_HERE,
      base::Bind(&WeakHandleCoreBase::CleanupAndDestroyOnOwnerThread,
                 base::Unretained(this)))) {
    // If the post fails, that means that the owner loop is gone and
    // therefore CleanupOnOwnerThread() should have already been
    // called via WillDestroyCurrentMessageLoop().  Therefore, the
    // only thing left is to self-destruct.
    delete this;
  }
}

void WeakHandleCoreBase::CleanupAndDestroyOnOwnerThread() {
  CHECK(IsOnOwnerThread());
  CHECK(!destroyed_on_owner_thread_);
  CleanupOnOwnerThread();
  CHECK(destroyed_on_owner_thread_);
  delete this;
}

void WeakHandleCoreBaseTraits::Destruct(const WeakHandleCoreBase* core_base) {
  const_cast<WeakHandleCoreBase*>(core_base)->Destroy();
}

}  // namespace internal

}  // namespace base