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

Change win32 compat atomic_compare_exchange_strong to match C11 spec #57

Closed
wants to merge 2 commits into from

Conversation

frankplow
Copy link
Collaborator

@frankplow frankplow commented Apr 3, 2023

As a preface, vvc_thread.c is the only place in the entire FFmpeg codebase which uses atomic_compare_* so hopefully this isn't too risky a change – it feels like a daunting place to make one. The change to compat/atomics/win32/stdatomic.h probably belongs upstream but I thought I'd get it checked here first considering this is the only place where it will matter at the moment.

Previously, OS-dependent code was needed to use atomic_compare_exchange_strong. This was causing issues with cross-compilation. This was necessary because the definition of the function in the win32 atomic compatibility header did not match the C11 specification. The C11 spec describes the function as

_Bool atomic_compare_exchange_strong(volatile A *object, C *expected, C desired)

where

  • A is an atomic type
  • C is its non-atomic counterpart

In FFmpeg's win32 atomic compatibility header, all atomic types are intptr_ts. atomic_compare_exchange_strong was defined as an inline function with the prototype

static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, intptr_t desired)

which only matches the C11 specification for atomic_intptr_t - both object and expected are essentially A.

The new prototype is much more relaxed, it uses a macro to take any pointer object and expected and any desired. This is more relaxed than the C11 specification - it makes no assertions that A is atomic nor that A and C are counterparts. I figure this is better than the previous prototype though as it doesn't require OS-specific code to use the function every time and any mistakes will still be flagged when compiling with gcc for Linux (which is much more common than Windows/MSVC during development I imagine).

Its implementation uses InterlockedCompareExchangePointer), which works with 64-bit operands on a 64-bit system and 32-bit operands on a 32-bit system. This is not the same as the C11 atomic_compare_exchange_strong – this takes arbitrarily-sized arguments. For this reason, the function currently produces a build warning:

warning C4312: 'type cast': conversion from 'int' to 'PVOID' of greater size

Should this instead be implemented with a switch statement on the size of the type to the Window's API's sized arguments e.g. InterlockedCompareExchange64?

I believe this PR will supersede #56 and close #37.

* Change `atomic_compare_exchange_strong` to macro, so it may take an atomic first argument and non-atomic second argument, as in the C11 specification
* Remove OS-dependent code in `libavcodec/vcc_thread.c`
return *expected == old;
}
#define atomic_compare_exchange_strong(object, expected, desired) \
(InterlockedCompareExchangePointer((PVOID *) object, (PVOID) desired, *((PVOID *) expected)) == *((PVOID *) expected))
Copy link
Member

Choose a reason for hiding this comment

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

This will overwrite the *object.
int is 32 bits on most platforms. PVOID is 64 bits on 64 bits platform.
this function will write 64 bits data(PVOID) to a 32 bits (int) location.

only vlc can do the right thing:
https://code.videolan.org/videolan/vlc/-/blob/8ef254bbae16f3df8b760c4d89fc518610a2f40a/include/vlc_atomic.h#L331

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

👍 This is what I was worried about without using the fixed-size types. I tried implementing using a switch statement but this was a bit funny with the macros. I will try the way VLC is doing it with the telescoping macros.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

dabc841 has gotten rid of the error but I'm still not sure is what we want.

atomic_int is not necessarily (will be on 32 bit) the same size as int when using the win32 atomic compatibility header. At the moment, on a 64-bit system object will be a 64-bit intptr_t so expected and desired will be overread. The spec says each integer type and its corresponding atomic type should have the same size, but I assume there's some reason intptr_t is being used here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looks like the definitions of all atomic types as intptr_t (initially in c91e72e) is simply taken from an old version of VLC: https://code.videolan.org/videolan/vlc/-/commit/fd82bdcba3903bfe377d25c0cbadd960958d37ea

@nuomi2021
Shall I change them all to the corresponding non-atomic types? This is what VLC has now, seems more in line with the C11 specification and will fix the issue we have here.

Copy link
Member

@nuomi2021 nuomi2021 Apr 3, 2023

Choose a reason for hiding this comment

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

Please send your current patch to the mailing list and ask other maintainers for review.
the project will continue to rebase against upstream. Once upstream accepted your patch. we will get it too.

@nuomi2021
Copy link
Member

let's close this. since you will send patch to upstream.
Thank you @frankplow for your patch.

@nuomi2021 nuomi2021 closed this Apr 4, 2023
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.

Fix #ifdef WIN32 for atomic_compare_exchange_strong
2 participants