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

Make Platform functions to return az_result #1256

Merged
merged 10 commits into from
Sep 17, 2020
Merged

Make Platform functions to return az_result #1256

merged 10 commits into from
Sep 17, 2020

Conversation

antkmsft
Copy link
Member

@antkmsft antkmsft commented Sep 11, 2020

This is variant A of the proposed behavior. Variant B: #1257

Closes #1226

Copy link
Contributor

@ahsonkhan ahsonkhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other variant is better.

*/
void az_platform_sleep_msec(int32_t milliseconds);
AZ_NODISCARD az_result az_platform_sleep_msec(int32_t milliseconds);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unnecessary burden to the implementor of the PAL.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahsonkhan are you referring to the AZ_NODISCARD or the az_result. I agree that we shouldn't force AZ_NODISCARD onto the implementations. I however do prefer the az_result return codes on the PAL. The minimal burden is greatly outweighed by the fact we can consistently validate the API performed as expected

Copy link
Contributor

@ahsonkhan ahsonkhan Sep 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you referring to the AZ_NODISCARD or the az_result

Both.

The minimal burden is greatly outweighed by the fact we can consistently validate the API performed as expected

I don't understand what you mean by this. What are we getting here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha, what I was thinking of, is that you Ahson was talking about the contrast of this variant to the proposal in #1257, saying that out parameters and az_result are generally more cumbersome to implement. I didn't read it as if you are commenting on the AZ_NODISCARD.
Regarding AZ_NODISCARD, I do not think it is a burden on the implementor. It is an intentional burden on the user, i.e. us. So, if we ignore the return result, we get a warning treated as compilation error. For the implementor, I am not sure if they even have to put AZ_NODISCARD in the signature of their imlpementation - having it in this header alone is probably enough (I am not sure, because AZ_NODISCARD is really compiler-specific).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMHO, platform should not depend on az_core. Only az_core should depend on some specific implementation.
Right now, in order to implement a platform, people need to get az_core, and people getting az_core need an az_platform. I don't like how that look XD. It works using cmake targets, but not sure if it would work without it (including pah directly)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting point on layering the dependency @vhvb1989

}

void az_platform_sleep_msec(int32_t milliseconds)
AZ_NODISCARD az_result az_platform_sleep_msec(int32_t milliseconds)
{
(void)usleep((useconds_t)milliseconds * _az_TIME_MICROSECONDS_PER_MILLISECOND);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated: precondition that milliseconds is positive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far we say in the docs, @remarks The behavior is undefined when \p milliseconds is a non-positive value (0 or less than 0). That's because on some platform, it would yield to other thread, but will return control back if no other thread needs it. We don't use this feature though.

Copy link
Contributor

@ahsonkhan ahsonkhan Sep 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because on some platform, it would yield to other thread, but will return control back if no other thread needs it. We don't use this feature though.

We can add a precondition now to help folks write correct code, and loosen that in the future, if that value becomes meaningful.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because on some platform, it would yield to other thread, but will return control back if no other thread needs it. We don't use this feature though.

We can add a precondition now to help folks write correct code, and loosen that in the future, if that value becomes meaningful.

We could precondition, but we would be limiting to a particular implementation of POSIX. Its not clear if every implementation places the same constraints. e.g. some platforms say the usec is not smaller than 1000000 others allow 0 to mean yield.

Copy link
Contributor

@ahsonkhan ahsonkhan Sep 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one particular implementation though. Adding a precondition here doesn't impact users who want to provide their own PAL implementation. Passing in a negative millisecond will overflow when cast to unsigned int, and that could be an unintended bug in the user's code (given usleep takes an unsigned number).
https://man7.org/linux/man-pages/man3/usleep.3.html#NOTES

@antkmsft antkmsft marked this pull request as ready for review September 11, 2020 09:30
*/
void az_platform_sleep_msec(int32_t milliseconds);
AZ_NODISCARD az_result az_platform_sleep_msec(int32_t milliseconds);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahsonkhan are you referring to the AZ_NODISCARD or the az_result. I agree that we shouldn't force AZ_NODISCARD onto the implementations. I however do prefer the az_result return codes on the PAL. The minimal burden is greatly outweighed by the fact we can consistently validate the API performed as expected

antkmsft and others added 2 commits September 11, 2020 10:54
Co-authored-by: Rick Winter <rick.winter@microsoft.com>
Co-authored-by: Rick Winter <rick.winter@microsoft.com>
@antkmsft
Copy link
Member Author

@ahsonkhan , I pinged Jeffrey, I'll wait to hear his opinion. If you are ok with this implementation, please approve :)

@antkmsft
Copy link
Member Author

@ahsonkhan and the team: Jeffrey is ok with returning az_result instead of precondition failure.

@ahsonkhan
Copy link
Contributor

instead of precondition failure.

Can we have both?

@antkmsft
Copy link
Member Author

instead of precondition failure.

Can we have both?

We could, and I thought about it at some point, but I don't think we should do it, given that precondition failure is not obvious to the users who are not familiar with it, so now that it is failed, users have to go learn about it first, and only then realize they need to implement PAL layer, so it removes one of the benefits of az_result.
Plus, if we are ok with the interface - function signature, returns az_result, precondition failure can be added in the future.

@ahsonkhan
Copy link
Contributor

precondition failure can be added in the future.

I would flip that. Precondition failures can be removed in the future. Strengthening a condition is more user hostile than weakening it.

Copy link
Contributor

@ahsonkhan ahsonkhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't discuss @vhvb1989 point on dependency/layering. I think that is a good argument for not returning az_result. Let's close on that one.

void az_platform_sleep_msec(int32_t milliseconds) { Sleep(milliseconds); }
AZ_NODISCARD az_result az_platform_sleep_msec(int32_t milliseconds)
{
Sleep(milliseconds);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think we should add a _az_PRECONDITION(milliseconds > 0) to all the implementations of the PAL.

Copy link
Member Author

@antkmsft antkmsft Sep 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have a variety of opinions, let's cover it outside of the scope of this PR, it can be added later without affecting this change.


void az_platform_sleep_msec(int32_t milliseconds) { (void)milliseconds; }
AZ_NODISCARD az_result az_platform_sleep_msec(int32_t milliseconds)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this again, I agree with Rick on the sleep API, we should consider removing AZ_NODISCARD.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should. It is us who calls these APIs. Rick's assumption is that 3 things are happening: 1. Customer calls PAL function. 2. Doesn't handle a result, and doesn't need/want to. 3. It is painful to ignore the result, which I think is not:

az_result ignore = az_platform_sleep_msec(1000);
(void)ignore;

Copy link
Contributor

@ahsonkhan ahsonkhan Sep 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, we should consider updating the documentation of az_http_pipeline_policy_logging and az_http_pipeline_policy_retry since they can now return any PAL-defined az_result. Alternatively, those APIs should take any PAL-error and convert it to a single error value, and return/document that.

@antkmsft
Copy link
Member Author

precondition failure can be added in the future.

I would flip that. Precondition failures can be removed in the future. Strengthening a condition is more user hostile than weakening it.

Jeff said to me "I can appreciate not wanting the customer getting started experience to force understanding on preconditions and figuring out how to deal with an infinite loop. To me, this is the ONLY compelling reason to avoid the precondition. Understanding preconditions is fundamental to our library just like spans and so you're only delaying the customer being forced to understand this; not preventing it entirely."

So I replied "What you've just said about delaying the learning, to me sounds like more of an argument for having the az_result, and a relatively significant one."

Adding a precondition would eliminate one of the benefits we get now.

@ahsonkhan
Copy link
Contributor

Adding a precondition would eliminate one of the benefits we get now.

Great point. Progressive disclosure is definitely something we should try to achieve, where possible.

@antkmsft
Copy link
Member Author

We didn't discuss @vhvb1989 point on dependency/layering. I think that is a good argument for not returning az_result. Let's close on that one.

We had that discussion about last November with Jeffrey, and decided in favor of header-only what-appears-to-look-like circular dependency, because it is simpler, and it works. I was actually a proponent of breaking the core into two modules back then: small core <- pal <- big core.
Victor's argument can and should be applied to the http adapter implementation, and we're not doing it there. Going with that change implies a lot more than the scope of this PR.

@ahsonkhan
Copy link
Contributor

ahsonkhan commented Sep 17, 2020

Victor's argument can and should be applied to the http adapter implementation, and we're not doing it there. Going with that change implies a lot more than the scope of this PR.

I think the PAL and HTTP adapter sit at different layers, so I don't think they both need to be held at the same bar.

I was actually a proponent of breaking the core into two modules back then: small core <- pal <- big core.

We shouldn't need a small core below at all for PAL (since conceptually it sits below the SDK, closer to the OS/device hardware):
OS <- pal <- core

@antkmsft
Copy link
Member Author

antkmsft commented Sep 17, 2020

We shouldn't need a small core below at all for PAL (since conceptually it sits below the SDK, closer to the OS/device hardware):
OS <- pal <- core

It was the point that IoT didn't need PAL, and didn't want to depend on it at all so they would depend only on small core. There's even no need to rely on the linker throwing out the unused parts, as today. Small core has spans, results, etc. There was no az_noplatform/az_nohttp in that picture, at all. So, if you are a blob client library, you need big core that has HTTP and PAL dependencies. You on't have a suitable implementation of pal/http - you don't get az_storage, we don't/can't compile it until the dependency is satisfied.

@antkmsft
Copy link
Member Author

antkmsft commented Sep 17, 2020

I think the PAL and HTTP adapter sit at different layers, so I don't think they both need to be held at the same bar.

Why az_curl can have a dependency on az_result, if the PAL can't?
Policies from Core do have http policy, which invokes HTTP adapter, but HTTP adapter relies on Core. It is the same argument.
Current solution: we do it carefully for both cases. If done carefully, it is simpler. Other option: circular2 => linear/diamond3 dependency, as we're discussing with small and big core, but that didn't happen. It is right from every angle, but more massive in terms of understanding/complexity,

@ahsonkhan
Copy link
Contributor

Policies from Core do have http policy, which invokes HTTP adapter, but HTTP adapter relies on Core.

True.

@antkmsft antkmsft closed this Sep 17, 2020
@antkmsft antkmsft reopened this Sep 17, 2020
@antkmsft antkmsft merged commit bb4f941 into Azure:master Sep 17, 2020
ghost pushed a commit that referenced this pull request Sep 17, 2020
@antkmsft - this change slipped through between the clang format validation check PR and the recent PAL update.
#1256

It is blocking CI for other PRs atm.
@antkmsft antkmsft deleted the pal-azresult branch October 3, 2020 01:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

sleep() and clock() should return az_result
4 participants