• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h"
6 
7 #include <glib-object.h>
8 
9 #include "base/logging.h"
10 #include "base/memory/singleton.h"
11 
12 namespace libgtk2ui {
13 
GObjectDestructorFILO()14 GObjectDestructorFILO::GObjectDestructorFILO() {
15 }
16 
~GObjectDestructorFILO()17 GObjectDestructorFILO::~GObjectDestructorFILO() {
18   // Probably CHECK(handler_map_.empty()) would look natural here. But
19   // some tests (some views_unittests) violate this assertion.
20 }
21 
22 // static
GetInstance()23 GObjectDestructorFILO* GObjectDestructorFILO::GetInstance() {
24   return Singleton<GObjectDestructorFILO>::get();
25 }
26 
Connect(GObject * object,DestructorHook callback,void * context)27 void GObjectDestructorFILO::Connect(
28     GObject* object, DestructorHook callback, void* context) {
29   const Hook hook(object, callback, context);
30   HandlerMap::iterator iter = handler_map_.find(object);
31   if (iter == handler_map_.end()) {
32     g_object_weak_ref(object, WeakNotifyThunk, this);
33     handler_map_[object].push_front(hook);
34   } else {
35     iter->second.push_front(hook);
36   }
37 }
38 
Disconnect(GObject * object,DestructorHook callback,void * context)39 void GObjectDestructorFILO::Disconnect(
40     GObject* object, DestructorHook callback, void* context) {
41   HandlerMap::iterator iter = handler_map_.find(object);
42   if (iter == handler_map_.end()) {
43     LOG(DFATAL) << "Unable to disconnect destructor hook for object " << object
44                 << ": hook not found (" << callback << ", " << context << ").";
45     return;
46   }
47   HandlerList& dtors = iter->second;
48   if (dtors.empty()) {
49     LOG(DFATAL) << "Destructor list is empty for specified object " << object
50                 << " Maybe it is being executed?";
51     return;
52   }
53   if (!dtors.front().equal(object, callback, context)) {
54     // Reenable this warning once this bug is fixed:
55     // http://code.google.com/p/chromium/issues/detail?id=85603
56     DVLOG(1) << "Destructors should be unregistered the reverse order they "
57              << "were registered. But for object " << object << " "
58              << "deleted hook is "<< context << ", the last queued hook is "
59              << dtors.front().context;
60   }
61   for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i) {
62     if (i->equal(object, callback, context)) {
63       dtors.erase(i);
64       break;
65     }
66   }
67   if (dtors.empty()) {
68     g_object_weak_unref(object, WeakNotifyThunk, this);
69     handler_map_.erase(iter);
70   }
71 }
72 
WeakNotify(GObject * where_the_object_was)73 void GObjectDestructorFILO::WeakNotify(GObject* where_the_object_was) {
74   HandlerMap::iterator iter = handler_map_.find(where_the_object_was);
75   DCHECK(iter != handler_map_.end());
76   DCHECK(!iter->second.empty());
77 
78   // Save destructor list for given object into local copy to avoid reentrancy
79   // problem: if callee wants to modify the caller list.
80   HandlerList dtors;
81   iter->second.swap(dtors);
82   handler_map_.erase(iter);
83 
84   // Execute hooks in local list in FILO order.
85   for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i)
86     i->callback(i->context, where_the_object_was);
87 }
88 
89 }  // namespace libgtk2ui
90