Skip to content
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

Merged

Conversation

bhalevy
Copy link
Member

@bhalevy bhalevy commented Feb 3, 2023

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

@bhalevy
Copy link
Member Author

bhalevy commented Feb 3, 2023

In v2 (ca8bd17)

  • fixed unit tests failing with g++ 12 so not to reassigned destroyed semaphore_units
  • explicitly call return_all() in operator=(semaphore_units&&) rather than using std::swap so not keep the state of the moved-from object the same as it was before this change.

@bhalevy bhalevy marked this pull request as draft February 4, 2023 11:06
@bhalevy bhalevy marked this pull request as ready for review February 4, 2023 11:06
@bhalevy bhalevy marked this pull request as draft February 8, 2023 10:58
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>
@bhalevy bhalevy force-pushed the semaphore_units-return-when-reassigned branch from ca8bd17 to 79b8e01 Compare July 18, 2023 17:04
@bhalevy
Copy link
Member Author

bhalevy commented Jul 18, 2023

v3:

  • rebased
  • refactor test cases instead of using unique_ptr to reduce code churn

@bhalevy bhalevy marked this pull request as ready for review July 18, 2023 17:06
@bhalevy
Copy link
Member Author

bhalevy commented Jul 25, 2023

@xemul can you please review?

@@ -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;
Copy link
Member

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.

Copy link
Member Author

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>
@bhalevy bhalevy force-pushed the semaphore_units-return-when-reassigned branch from 79b8e01 to c4733e5 Compare July 25, 2023 13:54
@bhalevy
Copy link
Member Author

bhalevy commented Jul 25, 2023

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);
Copy link
Member

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);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

semaphore_units are leaked when reassigned
2 participants