-
Notifications
You must be signed in to change notification settings - Fork 503
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
Msg & Svc UDP RX pipelines are implemented. #368
Conversation
…verification #docs #sonar
…. #verification #docs #sonar
… #verification #docs #sonar
…Cyphal-Garage/libcyphal into sshirokov/344_fallible_run2
…#verification #docs #sonar
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.
-
The UDP transport appears to be missing a detailed documentation of the socket construciton policy and the associted error handling approach. It has to be made very explicit that sockets are created ad-hoc.
-
The new error result types look overly convoluted, I recommend keeping the less verbose form -- see my comment in one of the affected places. I understand the desire to have a clearly named pair of types for the success and failure case but it doesn't seem to justify the existence of the extra entities.
|
||
private: | ||
// No Sonar `cpp:S5356` b/c we check here low level PMR alignment expectation. | ||
static bool isAligned(cetl::byte* const raw_bytes_ptr, const std::size_t size) |
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.
Why aren't we getting an unused method error here in non-debug builds?
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.
honestly IDK... what do you propose?
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 am just surprised that it is accepted. Would it build if you removed the assertion check where this method is referenced?
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'll try
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 tried - it compiles fine.
Agree, I will add such documentation. |
udpard_node_id_ = node_id; | ||
|
||
UdpardUDPIPEndpoint endpoint{}; | ||
const std::int8_t result = ::udpardRxRPCDispatcherStart(&rpc_dispatcher_, node_id, &endpoint); |
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.
Looks like udpardRxRPCDispatcherStart
is going to get called even if the application only cares about broadcast messages. Is there a lot of overhead to udpardRxRPCDispatcherStart
? Should we optimize the code to only call this function if the application registers interest in a service?
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.
It's called only when node id is set.
From udpard.h
header file documentation:
/// The time complexity is constant. This function does not invoke the dynamic memory manager.
I had discussed this with Pavel at initial stage of the PR - we (correct me please @pavel-kirienko if I'm wrong) agreed that calling this is fine even if there will be no later "interest in a service" as you said. Up to 3 TX sockets (per each redundant media) will be made only once for the whole transport instance, and these TX sockets are in use for both messages and services.
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.
Sounds good, thanks!
auto media_failure = withMediaRxSocketsFor( // | ||
new_msg_node, | ||
[](const Media&, const IRxSocket&, const UdpardRxSubscription&, const IRxSessionDelegate&) | ||
-> cetl::optional<AnyFailure> { return cetl::nullopt; }); |
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.
Noticing that we're using a lot of lambda functions in this code base. Not saying this is necessarily bad, but I think lambdas will be hard to certify at DAL-C and above. Probably fine to leave for now.
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.
AFAIK, compilers should be pretty good to optimize them to a simple plain function (or even completely eliminate/inline it). In this case there is no even capturing of anything (see []
empty list), so...
Also, in autosar c++ 14, again afaik, there nothing really against usage of lambda-s in general, yes there are rules, but not really against its usage in general.
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.
but I think lambdas will be hard to certify at DAL-C and above
Are they prohibited by high-integrity coding standards?
@@ -717,13 +768,268 @@ class TransportImpl final : private TransportDelegate, public IUdpTransport // | |||
return cetl::nullopt; | |||
} | |||
|
|||
/// @brief Tries to call an action with a media and its RX socket. | |||
/// | |||
/// The RX socket is made on demand if necessary (but `endpoint` parameter should have a value). |
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.
Shouldn't we only need to make the RX socket once during initialization? Is this essentially creating a new RX socket every time we call receive?
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.
These are made only when there is no one previously created. Such empty condition (namely UniquePtr is equal tonullptr
) may happen in two scenarios:
- the very first call when RX subscription/service is made (see
makeMsgRxSession
&makeSvcRxSession
) - on transport
run
call - when for any reason the first (above) scenario had failed (but the transient error handler said "it's fine, continue!"), user have got a valid RX session, and now this session is part of transport'srun
life - hence transport tries to "recover" from this empty socket condition by attempting again. Implementation ofIMedia
may do different strategies in such case.
For example:
a. do nothing, let it be, and very quickly return error again - has relatively small impact
b. really try create a socket again and again on each run cycle until it succeeded eventually.
c. have some kind of "max attempts counter" and do the "b" several times, and then switch to "a"
d. or, make it time based - like occasionally, once in a while, do retry recreate such faulty media socket, but not on every attempt.
Note, that currently we don't have means to "mark" a media as permanently "broken", so yes, at transport level we do retry recreate socket on each run, but once it succeeded we of course stop doing it (b/c we finally got one).
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.
Perfect, thank you for the description!
looks good so far |
|
||
// No Sonar `cpp:S909` b/c it make sense to use `continue` statement here - the corner case of | ||
// "early" (by deadline) transfer drop. Using `if` would make the code less readable and more nested. | ||
continue; // NOSONAR cpp:S909 |
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.
BTW, with this helper peekFirstValidUdpardTxItem
method there is no need of NOSONAR anymore (for the continue
).
include/libcyphal/types.hpp
Outdated
@@ -189,7 +189,7 @@ struct PmrRawBytesDeleter final | |||
|
|||
if ((nullptr != memory_resource_) && (nullptr != raw_bytes_ptr)) | |||
{ | |||
CETL_DEBUG_ASSERT(isAligned(raw_bytes_ptr, size_bytes_), "Unexpected alignment of the memory buffer."); | |||
// CETL_DEBUG_ASSERT(isAligned(raw_bytes_ptr, size_bytes_), "Unexpected alignment of the memory buffer."); |
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.
Commenting usage of isAligned
doesn't make it fail on CI... so, it seems that clang-tidy misses it for some reason
Quality Gate failedFailed conditions |
Also: