Skip to content

Commit acc0c4f

Browse files
committed
test/stock/TestMultiStock: add test that calls FinishWaiting() recursively
This test succeeds, but is potentially dangerous. The test aims to test the next commit which will protect against such a call.
1 parent 02fc195 commit acc0c4f

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

test/stock/TestMultiStock.cxx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,3 +1654,65 @@ TEST(MultiStock, ContinueOnCancelIdleReuse)
16541654

16551655
ASSERT_EQ(foo.destroyed, 1);
16561656
}
1657+
1658+
TEST(MultiStock, ReentrantGetFromReadyHandler)
1659+
{
1660+
Instance instance{2};
1661+
1662+
Partition foo{instance, "foo"};
1663+
1664+
struct ReentrantLease final : StockGetHandler {
1665+
Partition &partition;
1666+
bool did_reenter = false;
1667+
1668+
CancellablePointer get_cancel_ptr;
1669+
MyInnerStockItem *item = nullptr;
1670+
1671+
explicit ReentrantLease(Partition &_partition) noexcept
1672+
:partition(_partition) {}
1673+
1674+
~ReentrantLease() noexcept {
1675+
if (get_cancel_ptr)
1676+
get_cancel_ptr.Cancel();
1677+
else if (item != nullptr)
1678+
item->Put(PutAction::REUSE);
1679+
}
1680+
1681+
void OnStockItemReady(StockItem &_item) noexcept override {
1682+
get_cancel_ptr = nullptr;
1683+
item = (MyInnerStockItem *)&_item;
1684+
1685+
if (!did_reenter) {
1686+
did_reenter = true;
1687+
partition.Get();
1688+
}
1689+
}
1690+
1691+
void OnStockItemError(std::exception_ptr) noexcept override {
1692+
get_cancel_ptr = nullptr;
1693+
}
1694+
};
1695+
1696+
/* Queue one normal create, then put the reentrant waiter behind
1697+
it. This makes the reentrant waiter a real waiter even though
1698+
the MultiStock still has room for one more outer item. */
1699+
foo.defer_create = true;
1700+
foo.Get(1);
1701+
1702+
ReentrantLease lease{foo};
1703+
instance.multi_stock.Get(StockKey{foo.key}, ToNopPointer(&foo), 2,
1704+
lease, lease.get_cancel_ptr);
1705+
1706+
ASSERT_TRUE(lease.get_cancel_ptr);
1707+
1708+
/* Complete the pending create, then let the reentrant handler's
1709+
nested Get() create another outer item synchronously. */
1710+
foo.defer_create = false;
1711+
instance.RunSome();
1712+
1713+
ASSERT_TRUE(lease.did_reenter);
1714+
ASSERT_NE(lease.item, nullptr);
1715+
ASSERT_EQ(foo.factory_created, 2);
1716+
ASSERT_EQ(foo.waiting, 0);
1717+
ASSERT_EQ(foo.ready, 2);
1718+
}

0 commit comments

Comments
 (0)