Summary:
If a retired object's destructor retire()s other hazard pointers, currently
these are not cleaned up correctly when the domain destructs.
Retired pointers must be cleaned up before destroying hazptr_recs, and must be done
iteratively until no more garbage is generated.
Reviewed By: magedm
Differential Revision:
D4987333
fbshipit-source-id:
bcdd61abb47caca0892a8c4dbb864d17d4f2fa30
inline hazptr_domain::~hazptr_domain() {
DEBUG_PRINT(this);
+ { /* reclaim all remaining retired objects */
+ hazptr_obj* next;
+ auto retired = retired_.exchange(nullptr);
+ while (retired) {
+ for (auto p = retired; p; p = next) {
+ next = p->next_;
+ (*(p->reclaim_))(p);
+ }
+ retired = retired_.exchange(nullptr);
+ }
+ }
{ /* free all hazptr_rec-s */
hazptr_rec* next;
for (auto p = hazptrs_.load(); p; p = next) {
mr_->deallocate(static_cast<void*>(p), sizeof(hazptr_rec));
}
}
- { /* reclaim all remaining retired objects */
- hazptr_obj* next;
- for (auto p = retired_.load(); p; p = next) {
- next = p->next_;
- (*(p->reclaim_))(p);
- }
- }
}
inline void hazptr_domain::try_reclaim() {
EXPECT_EQ(bar->a, i);
}
}
+
+TEST_F(HazptrTest, DestructionTest) {
+ hazptr_domain myDomain0;
+ struct Thing : public hazptr_obj_base<Thing> {
+ Thing* next;
+ Thing(Thing* n) : next(n) {}
+ ~Thing() {
+ DEBUG_PRINT("this: " << this << " next: " << next);
+ if (next) {
+ next->retire();
+ }
+ }
+ };
+ Thing* last{nullptr};
+ for (int i = 0; i < 2000; i++) {
+ last = new Thing(last);
+ }
+ last->retire();
+}