15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stddef.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ostream>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keep a stack of registered AtExitManagers.  We always operate on the most
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// recent, and we should never have more than one outside of testing (for a
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// statically linked version of this library).  Testing may use the shadow
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// version of the constructor, and if we are building a dynamic library we may
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// end up with multiple AtExitManagers on the same process.  We don't protect
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this for thread-safe access, since it will only be modified in testing.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static AtExitManager* g_top_manager = NULL;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If multiple modules instantiate AtExitManagers they'll end up living in this
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// module... they have to coexist.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(COMPONENT_BUILD)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!g_top_manager);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_top_manager = this;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AtExitManager::~AtExitManager() {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_top_manager) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(this, g_top_manager);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProcessCallbacksNow();
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_top_manager = next_manager_;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(func);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterTask(base::Bind(func, param));
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AtExitManager::RegisterTask(base::Closure task) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_top_manager) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(g_top_manager->lock_);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_top_manager->stack_.push(task);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AtExitManager::ProcessCallbacksNow() {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_top_manager) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(g_top_manager->lock_);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!g_top_manager->stack_.empty()) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Closure task = g_top_manager->stack_.top();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    task.Run();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_top_manager->stack_.pop();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(shadow || !g_top_manager);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_top_manager = this;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
83