-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
semaphore: semaphore_units: return units when reassigned #1466
semaphore: semaphore_units: return units when reassigned #1466
Conversation
da90eaf
to
ca8bd17
Compare
In v2 (ca8bd17)
|
The test case fails with g++ (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4) ``` tests/unit/semaphore_test.cc(0): Entering test case "test_semaphore_units_splitting" src/testing/seastar_test.cc(43): info: check true has passed tests/unit/semaphore_test.cc(269): info: check units.count() == 3 has passed tests/unit/semaphore_test.cc(270): info: check sm.available_units() == 0 has passed tests/unit/semaphore_test.cc(272): info: check sm.available_units() == 0 has passed tests/unit/semaphore_test.cc(273): info: check units.count() == 2 has passed tests/unit/semaphore_test.cc(274): info: check split.count() == 1 has passed tests/unit/semaphore_test.cc(276): info: check sm.available_units() == 1 has passed tests/unit/semaphore_test.cc(279): fatal error: in "test_semaphore_units_splitting": critical check sm.available_units() == 0 has failed [2 != 0] ``` Avoid reassigning `units` after it is destroyed. Split the existing test sub-cases into test cases of their own. Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
ca8bd17
to
79b8e01
Compare
v3:
|
@xemul can you please review? |
include/seastar/core/semaphore.hh
Outdated
@@ -482,6 +482,7 @@ public: | |||
semaphore_units(semaphore_units&& o) noexcept : _sem(o._sem), _n(std::exchange(o._n, 0)) { | |||
} | |||
semaphore_units& operator=(semaphore_units&& o) noexcept { | |||
return_all(); | |||
_sem = o._sem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't work when this == &o.
It technically doesn't need to work (passing a temporary contains a promise not to use it other than to invoke the destructor), but the damage is so great it's better to protect against it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in v4
When semaphore_units are (move-) reassigned with other units, the held units aren't currently returned to the semaphore. Call return_all before reassigning the semaphore_units object. Add a unit test reproducer. Fixes scylladb#1465 Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
79b8e01
to
c4733e5
Compare
In v4 (c4733e5): protect against self-assignment in move assignment operator. |
if (this != &o) { | ||
return_all(); | ||
_sem = o._sem; | ||
_n = std::exchange(o._n, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: the following change might also have fixed it:
std::swap(_sem, o,_sem);
std::swap(_n, o._n);
When semaphore_units are (move-) reassigned with
other units, the held units aren't currently
returned to the semaphore.
This change implements the move-reassignment operator by swapping the semaphore and the units counter
so that when the moved-from semaphore_units object is destroyed, the units will be returned to the semaphore via
~semaphore_units
->return_all
.Add a unit test reproducer.
Fixes #1465
Signed-off-by: Benny Halevy bhalevy@scylladb.com