/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#pragma once
-#include <boost/noncopyable.hpp>
-#include <inttypes.h>
-#include <assert.h>
+#include <folly/io/async/DelayedDestructionBase.h>
+
+#include <glog/logging.h>
namespace folly {
* DelayedDestruction does not perform any locking. It is intended to be used
* only from a single thread.
*/
-class DelayedDestruction : private boost::noncopyable {
+class DelayedDestruction : public DelayedDestructionBase {
public:
- /**
- * Helper class to allow DelayedDestruction classes to be used with
- * std::shared_ptr.
- *
- * This class can be specified as the destructor argument when creating the
- * shared_ptr, and it will destroy the guarded class properly when all
- * shared_ptr references are released.
- */
- class Destructor {
- public:
- void operator()(DelayedDestruction* dd) const {
- dd->destroy();
- }
- };
-
/**
* destroy() requests destruction of the object.
*
virtual void destroy() {
// If guardCount_ is not 0, just set destroyPending_ to delay
// actual destruction.
- if (guardCount_ != 0) {
+ if (getDestructorGuardCount() != 0) {
destroyPending_ = true;
} else {
- destroyNow(false);
+ onDelayedDestroy(false);
}
}
/**
- * Classes should create a DestructorGuard object on the stack in any
- * function that may invoke callback functions.
+ * Helper class to allow DelayedDestruction classes to be used with
+ * std::shared_ptr.
*
- * The DestructorGuard prevents the guarded class from being destroyed while
- * it exists. Without this, the callback function could delete the guarded
- * object, causing problems when the callback function returns and the
- * guarded object's method resumes execution.
+ * This class can be specified as the destructor argument when creating the
+ * shared_ptr, and it will destroy the guarded class properly when all
+ * shared_ptr references are released.
*/
- class DestructorGuard {
+ class Destructor {
public:
-
- explicit DestructorGuard(DelayedDestruction* dd) : dd_(dd) {
- ++dd_->guardCount_;
- assert(dd_->guardCount_ > 0); // check for wrapping
- }
-
- DestructorGuard(const DestructorGuard& dg) : dd_(dg.dd_) {
- ++dd_->guardCount_;
- assert(dd_->guardCount_ > 0); // check for wrapping
- }
-
- ~DestructorGuard() {
- assert(dd_->guardCount_ > 0);
- --dd_->guardCount_;
- if (dd_->guardCount_ == 0 && dd_->destroyPending_) {
- dd_->destroyPending_ = false;
- dd_->destroyNow(true);
- }
+ void operator()(DelayedDestruction* dd) const {
+ dd->destroy();
}
-
- private:
- DelayedDestruction* dd_;
};
- protected:
- /**
- * destroyNow() is invoked to actually destroy the object, after destroy()
- * has been called and no more DestructorGuard objects exist. By default it
- * calls "delete this", but subclasses may override this behavior.
- *
- * @param delayed This parameter is true if destruction was delayed because
- * of a DestructorGuard object, or false if destroyNow() is
- * being called directly from destroy().
- */
- virtual void destroyNow(bool delayed) {
- delete this;
- (void)delayed; // prevent unused variable warnings
+ bool getDestroyPending() const {
+ return destroyPending_;
}
- DelayedDestruction()
- : guardCount_(0)
- , destroyPending_(false) {}
-
+ protected:
/**
* Protected destructor.
*
* shared_ptr using a DelayedDestruction::Destructor as the second argument
* to the shared_ptr constructor.
*/
- virtual ~DelayedDestruction() = default;
+ ~DelayedDestruction() override = default;
- /**
- * Get the number of DestructorGuards currently protecting this object.
- *
- * This is primarily intended for debugging purposes, such as asserting
- * that an object has at least 1 guard.
- */
- uint32_t getDestructorGuardCount() const {
- return guardCount_;
+ DelayedDestruction()
+ : destroyPending_(false) {
}
private:
- /**
- * guardCount_ is incremented by DestructorGuard, to indicate that one of
- * the DelayedDestruction object's methods is currently running.
- *
- * If destroy() is called while guardCount_ is non-zero, destruction will
- * be delayed until guardCount_ drops to 0. This allows DelayedDestruction
- * objects to invoke callbacks without having to worry about being deleted
- * before the callback returns.
- */
- uint32_t guardCount_;
-
/**
* destroyPending_ is set to true if destoy() is called while guardCount_ is
- * non-zero.
+ * non-zero. It is set to false before the object is deleted.
*
* If destroyPending_ is true, the object will be destroyed the next time
* guardCount_ drops to 0.
*/
bool destroyPending_;
+
+ void onDelayedDestroy(bool delayed) override {
+ // check if it is ok to destroy now
+ if (delayed && !destroyPending_) {
+ return;
+ }
+ destroyPending_ = false;
+ delete this;
+ }
};
} // folly