summaryrefslogtreecommitdiff
path: root/src/cleanup_queue.h
blob: 64e04e1856a197e70a3d2f29dda2dd45927a24ba (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
#ifndef SRC_CLEANUP_QUEUE_H_
#define SRC_CLEANUP_QUEUE_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <cstddef>
#include <cstdint>
#include <unordered_set>

#include "memory_tracker.h"

namespace node {

class BaseObject;

class CleanupQueue : public MemoryRetainer {
 public:
  typedef void (*Callback)(void*);

  CleanupQueue() {}

  // Not copyable.
  CleanupQueue(const CleanupQueue&) = delete;

  SET_MEMORY_INFO_NAME(CleanupQueue)
  inline void MemoryInfo(node::MemoryTracker* tracker) const override;
  inline size_t SelfSize() const override;

  inline bool empty() const;

  inline void Add(Callback cb, void* arg);
  inline void Remove(Callback cb, void* arg);
  void Drain();

  template <typename T>
  inline void ForEachBaseObject(T&& iterator) const;

 private:
  class CleanupHookCallback {
   public:
    CleanupHookCallback(Callback fn,
                        void* arg,
                        uint64_t insertion_order_counter)
        : fn_(fn),
          arg_(arg),
          insertion_order_counter_(insertion_order_counter) {}

    // Only hashes `arg_`, since that is usually enough to identify the hook.
    struct Hash {
      size_t operator()(const CleanupHookCallback& cb) const;
    };

    // Compares by `fn_` and `arg_` being equal.
    struct Equal {
      bool operator()(const CleanupHookCallback& a,
                      const CleanupHookCallback& b) const;
    };

   private:
    friend class CleanupQueue;
    Callback fn_;
    void* arg_;

    // We keep track of the insertion order for these objects, so that we can
    // call the callbacks in reverse order when we are cleaning up.
    uint64_t insertion_order_counter_;
  };

  inline BaseObject* GetBaseObject(const CleanupHookCallback& callback) const;

  // Use an unordered_set, so that we have efficient insertion and removal.
  std::unordered_set<CleanupHookCallback,
                     CleanupHookCallback::Hash,
                     CleanupHookCallback::Equal>
      cleanup_hooks_;
  uint64_t cleanup_hook_counter_ = 0;
};

}  // namespace node

#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif  // SRC_CLEANUP_QUEUE_H_