Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2278)

Unified Diff: chrome/browser/profiles/profile_destroyer.cc

Issue 10645005: Modify ProfileDestroyer to prevent leaks. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/profiles/profile_destroyer.h ('k') | chrome/browser/profiles/profile_impl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/profiles/profile_destroyer.cc
===================================================================
--- chrome/browser/profiles/profile_destroyer.cc (revision 143384)
+++ chrome/browser/profiles/profile_destroyer.cc (working copy)
@@ -12,8 +12,18 @@
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
+
+namespace {
+
+const int64 kTimerDelaySeconds = 1;
+
+} // namespace
+
+std::vector<ProfileDestroyer*>* ProfileDestroyer::pending_destroyers_ = NULL;
+
// static
void ProfileDestroyer::DestroyProfileWhenAppropriate(Profile* const profile) {
+ DCHECK(profile);
std::vector<content::RenderProcessHost*> hosts;
// Testing profiles can simply be deleted directly. Some tests don't setup
// RenderProcessHost correctly and don't necessary run on the UI thread
@@ -23,47 +33,127 @@
if (!profile->IsOffTheRecord() && profile->HasOffTheRecordProfile())
GetHostsForProfile(profile->GetOffTheRecordProfile(), &hosts);
}
- if (hosts.empty()) {
+ // This should never happen for non Off the record profile, this means that
+ // there is a leak in a render process host that MUST BE FIXED!!!
+ DCHECK(hosts.empty() || profile->IsOffTheRecord());
+ // Note that we still test for !profile->IsOffTheRecord here even though we
+ // DCHECK'd above because we want to protect Release builds against this even
+ // we need to identify if there are leaks when we run Debug builds.
+ if (hosts.empty() || !profile->IsOffTheRecord()) {
if (profile->IsOffTheRecord())
profile->GetOriginalProfile()->DestroyOffTheRecordProfile();
else
delete profile;
} else {
// The instance will destroy itself once all render process hosts referring
- // to it and/or it's off the record profile are properly terminated.
+ // to it are properly terminated.
scoped_refptr<ProfileDestroyer> profile_destroyer(
new ProfileDestroyer(profile, hosts));
}
}
+// This can be called to cancel any pending destruction and destroy the profile
+// now, e.g., if the parent profile is being destroyed while the incognito one
+// still pending...
+void ProfileDestroyer::DestroyOffTheRecordProfileNow(Profile* const profile) {
+ DCHECK(profile);
+ DCHECK(profile->IsOffTheRecord());
+ if (pending_destroyers_) {
+ for (size_t i = 0; i < pending_destroyers_->size(); ++i) {
+ if ((*pending_destroyers_)[i]->profile_ == profile) {
+ // We want to signal this in debug builds so that we don't lose sight of
+ // these potential leaks, but we handle it in release so that we don't
+ // crash or corrupt profile data on disk.
+ NOTREACHED() << "A render process host wasn't destroyed early enough.";
+ (*pending_destroyers_)[i]->profile_ = NULL;
+ break;
+ }
+ }
+ }
+ DCHECK(profile->GetOriginalProfile());
+ profile->GetOriginalProfile()->DestroyOffTheRecordProfile();
+}
+
ProfileDestroyer::ProfileDestroyer(
Profile* const profile,
- const std::vector<content::RenderProcessHost*>& hosts) : profile_(profile) {
+ const std::vector<content::RenderProcessHost*>& hosts)
+ : timer_(false, false),
+ num_hosts_(0),
+ profile_(profile) {
+ if (pending_destroyers_ == NULL)
+ pending_destroyers_ = new std::vector<ProfileDestroyer*>;
+ pending_destroyers_->push_back(this);
for (size_t i = 0; i < hosts.size(); ++i) {
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
content::Source<content::RenderProcessHost>(hosts[i]));
// For each of the notifications, we bump up our reference count.
// It will go back to 0 and free us when all hosts are terminated.
- AddRef();
+ ++num_hosts_;
}
+ // If we are going to wait for render process hosts, we don't want to do it
+ // for longer than kTimerDelaySeconds.
+ if (num_hosts_) {
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(kTimerDelaySeconds),
+ base::Bind(&ProfileDestroyer::DestroyProfile, this));
+ }
}
ProfileDestroyer::~ProfileDestroyer() {
// Check again, in case other render hosts were added while we were
// waiting for the previous ones to go away...
- DestroyProfileWhenAppropriate(profile_);
+ if (profile_)
+ DestroyProfileWhenAppropriate(profile_);
+
+ // We shouldn't be deleted with pending notifications.
+ DCHECK(registrar_.IsEmpty());
+
+ DCHECK(pending_destroyers_ != NULL);
+ std::vector<ProfileDestroyer*>::iterator iter = std::find(
+ pending_destroyers_->begin(), pending_destroyers_->end(), this);
+ DCHECK(iter != pending_destroyers_->end());
+ pending_destroyers_->erase(iter);
+ DCHECK(pending_destroyers_->end() == std::find(pending_destroyers_->begin(),
+ pending_destroyers_->end(),
+ this));
+ if (pending_destroyers_->empty()) {
+ delete pending_destroyers_;
+ pending_destroyers_ = NULL;
+ }
}
void ProfileDestroyer::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED);
- // Delay the destruction one step further in case other observers of this
- // notification need to look at the profile attached to the host.
- MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&ProfileDestroyer::Release, this));
+ DCHECK(num_hosts_ > 0);
+ --num_hosts_;
+ if (num_hosts_ == 0) {
+ // Delay the destruction one step further in case other observers of this
+ // notification need to look at the profile attached to the host.
+ MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&ProfileDestroyer::DestroyProfile, this));
+ }
}
+void ProfileDestroyer::DestroyProfile() {
+ // We might have been cancelled externally before the timer expired.
+ if (profile_ == NULL)
+ return;
+ DCHECK(profile_->IsOffTheRecord());
+ DCHECK(profile_->GetOriginalProfile());
+ profile_->GetOriginalProfile()->DestroyOffTheRecordProfile();
+ profile_ = NULL;
+
+ // Don't wait for pending registrations, if any, these hosts are buggy.
+ DCHECK(registrar_.IsEmpty()) << "Some render process hosts where not "
+ << "destroyed early enough!";
+ registrar_.RemoveAll();
+
+ // And stop the timer so we can be released early too.
+ timer_.Stop();
+}
+
// static
bool ProfileDestroyer::GetHostsForProfile(
Profile* const profile, std::vector<content::RenderProcessHost*>* hosts) {
« no previous file with comments | « chrome/browser/profiles/profile_destroyer.h ('k') | chrome/browser/profiles/profile_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698