-
Notifications
You must be signed in to change notification settings - Fork 388
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
iox-#751: remove old semaphore posix wrapper #1402
iox-#751: remove old semaphore posix wrapper #1402
Conversation
a6f134a
to
664f61d
Compare
Codecov Report
@@ Coverage Diff @@
## master #1402 +/- ##
==========================================
+ Coverage 78.71% 78.99% +0.28%
==========================================
Files 379 377 -2
Lines 14707 14511 -196
Branches 2050 2023 -27
==========================================
- Hits 11576 11463 -113
+ Misses 2466 2398 -68
+ Partials 665 650 -15
Flags with carried forward coverage won't be shown. Click here to find out more.
|
iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/functional_interface.inl
Outdated
Show resolved
Hide resolved
iceoryx_posh/include/iceoryx_posh/internal/popo/building_blocks/condition_variable_data.hpp
Outdated
Show resolved
Hide resolved
sendRequest(); | ||
wasRequestSent = true; | ||
}); | ||
|
||
// wait some time to check if the client is blocked | ||
constexpr std::chrono::milliseconds SLEEP_TIME{100U}; | ||
ASSERT_FALSE(threadSyncSemaphore->wait().has_error()); | ||
iox::cxx::internal::adaptive_wait().wait_loop([&] { return !isThreadStarted.load(); }); |
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.
Hmm, in theory this will slow down our tests. At first it might slow down the start of the thread because the CPU is busy and then it might sleep longer than necessary.
I agree that this is a pattern that we use quite often but why not just wrap the semaphore into something like a Trigger
class in the testing library with just a fire
and wait
method?
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.
You mean in the end a condition variable without predicate - notify
and wait
. I already implemented this and wanted to create a PR in the near future which would contain:
- posix condition wrapper (condition variable without predicate)
- unit tests for this wrapper
see this here: https://github.com/ApexAI/iceoryx/blob/iox-%231037-implement-posix-condition-variable/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/condition.hpp
Would it be alright for you that I add this to the condition issue that adaptive_wait
is replaced with the posix condition when it is merged?
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.
Yes, that's fine but Condition
alone is not sufficient. It needs either a Semaphore
or a Condition
with a predicate else there is a race between the main thread wait()
and worker thread notifyOne
/notifyAll
. If notify is called before the main thread enters wait
, the thread blocks.
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.
I found Barrier
in hoofs testing which does exactly what we want here and replaced all adaptive waits with the barrier
UnnamedSemaphoreBuilder() | ||
.isInterProcessCapable(false) | ||
.create(m_semaphore) | ||
.expect("Unable to create semaphore for signal watcher"); |
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 should be safe. Although getInstance
will be called in the signal handler and getInstance
creates the instance, it must be called before the signal handler is registered.
Out of curiosity. It seems the signal handler can only be registered with a call to getInstance
, which happens when one calls e.g. waitForTerminationRequest()
, which in turn is called quite late. What happens when a signal was raised before this function was called? I guess the same as when no signal handler is registered? Do we want to give the user the opportunity to explicitly register the signal handler quite early in the main method?
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.
What happens when a signal was raised before this function was called?
You are right, it behaves like no signal handler was registered.
Do we want to give the user the opportunity to explicitly register the signal handler quite early in the main method?
I would refrain from that. For instance we register our own signal handler in the shared memory object when we zero the whole memory. After the zeroing we restore the previous signal handler but still the user may wonder why the custom call was not used.
I would prefer that the user is not allowed to register any signal handler globally and always has to use our abstractions when they want to handle something like wait for CTRL+c
.
I would propose the following best practices.
- Do not register a universal signal handler for all iceoryx applications.
- To wait for
CTRL+c
always use theSignalWatcher
- When registering a signal handler always use
registerSignalHandler
in the smallest scope possible with as less signals as possible (only the required ones).
// do stuff
{
auto mySigbusGuard = registerSignalHandler(Signal::BUS, signalHandlerCallback);
functionCallWhichMayLeadToSigbus();
}
// do other stuff
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.
@elfenpiff I think I didn't communicate my intention clearly. It is not about the user to register a signal handler but about the abstraction registering the signal handler quite late. Let's assume Ctrl+C
is pressed before the first call to iox::posix::hasTerminationRequested
. In this scenario there is no graceful termination with stack unwinding and all sockets, etc. are not cleaned up. If one wants to use the convenient iox::posix::hasTerminationRequested
function but also terminate gracefully, there is no obvious way to do it, except calling iox::posix::hasTerminationRequested
right at the start of main
. The question is, do we want to give the user a more obvious way to register our signal handler at the start of main?
There is of course also a downside of this since there might be blocking calls the user added which are stuck but then a custom signal handler needs to be registered.
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 is a bigger question and I created an issue to discuss it in more detail and come up with a clean solution: #1414
iceoryx_posh/include/iceoryx_posh/internal/popo/building_blocks/condition_variable_data.hpp
Outdated
Show resolved
Hide resolved
sendRequest(); | ||
wasRequestSent = true; | ||
}); | ||
|
||
// wait some time to check if the client is blocked | ||
constexpr std::chrono::milliseconds SLEEP_TIME{100U}; | ||
ASSERT_FALSE(threadSyncSemaphore->wait().has_error()); | ||
iox::cxx::internal::adaptive_wait().wait_loop([&] { return !isThreadStarted.load(); }); |
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.
Yes, that's fine but Condition
alone is not sufficient. It needs either a Semaphore
or a Condition
with a predicate else there is a race between the main thread wait()
and worker thread notifyOne
/notifyAll
. If notify is called before the main thread enters wait
, the thread blocks.
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.
Only small nitpicks. Can be merged once the integration test issue is fixed
d1eccb9
to
1c4ea5b
Compare
… that it can be used from within a signal handler Signed-off-by: Christian Eltzschig <me@elchris.org>
…semaphore in the signal watcher and the named pipe Signed-off-by: Christian Eltzschig <me@elchris.org>
…and use signal_watcher instead, use UnnamedSemaphore instead of Semaphore in NamedPipe, PeriodicTask, WatchDog, ConditionVariableData Signed-off-by: Christian Eltzschig <me@elchris.org>
…the tests for a more efficient busy loop Signed-off-by: Christian Eltzschig <me@elchris.org>
… dds gateway, replace semaphores in test with adaptive wait Signed-off-by: Christian Eltzschig <me@elchris.org>
… notes Signed-off-by: Christian Eltzschig <me@elchris.org>
Signed-off-by: Christian Eltzschig <me@elchris.org>
… to ensure type safety, fix gcc warning unused value Signed-off-by: Christian Eltzschig <me@elchris.org>
…ency reasons, fix issue in SignalWatcher test Signed-off-by: Christian Eltzschig <me@elchris.org>
…ignalWatcher made signal safe and added comments to explain signal safe nature Signed-off-by: Christian Eltzschig <christian.eltzschig@apex.ai>
…struction Signed-off-by: Christian Eltzschig <christian.eltzschig@apex.ai>
1c4ea5b
to
4866c4b
Compare
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.
Didn't review completely.
iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/named_pipe.hpp
Outdated
Show resolved
Hide resolved
iceoryx_hoofs/include/iceoryx_hoofs/cxx/functional_interface.hpp
Outdated
Show resolved
Hide resolved
iceoryx_posh/include/iceoryx_posh/internal/popo/building_blocks/condition_variable_data.hpp
Show resolved
Hide resolved
iceoryx_posh/source/popo/building_blocks/condition_listener.cpp
Outdated
Show resolved
Hide resolved
iceoryx_posh/source/popo/building_blocks/condition_variable_data.cpp
Outdated
Show resolved
Hide resolved
56633b8
to
68b1ace
Compare
…TERM Signed-off-by: Christian Eltzschig <me@elchris.org>
68b1ace
to
7a32fdd
Compare
… readability Signed-off-by: Christian Eltzschig <me@elchris.org>
Signed-off-by: Christian Eltzschig <me@elchris.org>
Signed-off-by: Christian Eltzschig <me@elchris.org>
iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/named_pipe.hpp
Outdated
Show resolved
Hide resolved
iceoryx_posh/test/integrationtests/test_publisher_subscriber_communication.cpp
Outdated
Show resolved
Hide resolved
…able in windows Signed-off-by: Christian Eltzschig <me@elchris.org>
Signed-off-by: Christian Eltzschig <me@elchris.org>
@@ -85,21 +85,21 @@ void unblocksWhenSignalWasRaisedForWaiters(SignalWatcher_test& test, | |||
const uint64_t numberOfWaiters, | |||
const std::function<void()>& wait) | |||
{ | |||
std::atomic<uint64_t> isThreadStarted{0}; | |||
Barrier isThreadStarted(numberOfWaiters); |
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.
Hahaha, I didn't know this exists.
Not required but it feels a bit weird to read isThreadStarted.wait()
. Can you come up with a more lyrical name like threadStartSync.wait()
of so?
We can keep it if you like it as it is or don't find something that satisfies you.
@@ -37,7 +37,7 @@ UnnamedSemaphoreBuilder::create(cxx::optional<UnnamedSemaphore>& uninitializedSe | |||
uninitializedSemaphore.emplace(); | |||
|
|||
auto result = posixCall(iox_sem_init)(&uninitializedSemaphore.value().m_handle, | |||
(m_isInterProcessCapable) ? 0 : 1, |
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.
Oh boy ... I think I even reviewed this 😕
Pre-Review Checklist for the PR Author
iox-#123-this-is-a-branch
)iox-#123 commit text
)git commit -s
)task-list-completed
)Notes for Reviewer
The
posix::Semaphore
was completely removed. Custom implementations of ouriox::posix::waitForTerminationRequest();
were also removed fromRoudiApp
and the dds gateway.With that the public API for
RoudiApp
changed and thewaitForSignal
protected method was deprecated (not removed) sinceiox::posix::waitForTerminationRequest()
already implements that behavior.Checklist for the PR Reviewer
Post-review Checklist for the PR Author
References