Skip to content

Add the CurrentUserOnly and CurrentSessionOnly options for named Mutex, Semaphore, and EventWaitHandle #112213

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

Merged
merged 8 commits into from
Mar 12, 2025

Conversation

kouvel
Copy link
Contributor

@kouvel kouvel commented Feb 5, 2025

  • In Mutex, Semaphore, and EventWaitHandle, added overloads for methods with a name argument to also include a NamedWaitHandleOptions options argument. The CurrentUserOnly option indicates whether the object should be limited in access to the current user. The CurrentSessionOnly option indicates whether the object object is intended to be used only within the current session (an alternative to the name prefixes, such as Global\). The default value for NamedWaitHandleOptions has CurrentUserOnly=true and CurrentSessionOnly=true.
  • On Unixes, named semaphores and events are not supported. Named mutexes are have a functional implementation on Unixes in CoreCLR. NativeAOT and Mono on Unixes use an incomplete/temporary implementation where named mutexes are just process-local mutexes stored in a dictionary keyed by the name and can't be used to synchronize between processes. This change only briefly extends the NativeAOT/Mono implementation to add another prefix to the name when CurrentUserOnly=true. Sharing the CoreCLR Unix named mutex implementation with NativeAOT/Mono is left to a separate change. Most of what is described below when CurrentUserOnly=true on Unixes refers to the CoreCLR implementation.
  • The plan is to also deprecate the APIs with a name argument but without an options argument in a separate change
  • API review: [API Proposal]: New overloads for named wait handles that enable creating/opening user-specific synchronization primitives #102682 (comment)

Windows with CurrentUserOnly=true

When creating a named mutex, a security descriptor is created and assigned to the object.

  • The owner and group are set to the current user
  • The DACL has two ACEs:
    • One ACE allows the current user the relevant access rights
    • Another ACE allows the BUILTIN\Administrators group the READ_CONTROL access right to enable reading the security info for diagnostic purposes
  • The SACL has a mandatory label ACE
    • The access policy prevents principals with an integrity level lower than the object from opening the object
    • The integrity level assigned to the object is the same as what would be assigned by the system by default
  • When opening a named mutex, the owner and DACL are verified to see if they are as expected, and if not, a WaitHandleCannotBeOpenedException is thrown
  • Access controls are set when creating an object and checked when opening an object. Once a handle to the object is obtained, typical synchronization operations may not do further access checks. It's up to the caller to be careful about how the handle to the object is passed around.

Unixes with CurrentUserOnly=true

  • Files relevant to named mutexes (shared memory and lock files) go under /tmp/.dotnet-uidN/ where N is the effective user ID
    • /tmp/ (or equivalent) was chosen mainly for the automatic cleanup, as the number of files can add up in cases where mutexes are not disposed, particularly when randomly generated names are used upon each invocation of a process. Due to the use of a global location /tmp/ or equivalent, it would be possible for a user to deny access to the .dotnet-uidN directory of a different user if the directory hadn't been created yet. An alternative considered was to use the home directory and introduce some kind of periodic cleanup strategy, but there are also other tradeoffs.
  • /tmp/ or equivalent must either have the sticky bit, or it must be owned by the current user and without write access for any other user. Otherwise, an exception is thrown.
  • Permissions of the /tmp/.dotnet-uidN/ directory and files/directories under it are limited in access to the current user
  • When opening a named mutex, the owner and permissions of relevant files/directories are verified to see if they are as expected, and if not, an exception is thrown
  • Access controls are set when creating an object and checked when opening an object. Once a handle to the object is obtained, typical synchronization operations may not do further access checks. It's up to the caller to be careful about how the handle to the object is passed around.

Namespaces

  • On Windows, there is no namespace for kernel objects for each user. CurrentSessionOnly=true is close, but it is possible for multiple users to be running code simultaneously in the same session. There is a global namespace, and a namespace per session. When CurrentUserOnly=true, callers may need to ensure that the name used is distinguished for different users.
  • On Unixes, a different directory tree is used when CurrentUserOnly=true, so each user has a separate namespace for objects, including for session-scoped and session-unscoped objects.

@kouvel kouvel added this to the 10.0.0 milestone Feb 5, 2025
@kouvel kouvel self-assigned this Feb 5, 2025
@ghost
Copy link

ghost commented Feb 5, 2025

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

1 similar comment
@ghost
Copy link

ghost commented Feb 5, 2025

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

Copy link
Contributor

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE ".coreclr.XXXXXX"

#define SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT (10)
#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE ".dotnet.XXXXXX"
Copy link
Member

Choose a reason for hiding this comment

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

This means that .NET 10+ apps will no longer be able to sync with apps running using older .NET version. It seems we will need to document this.

Copy link
Contributor Author

@kouvel kouvel Feb 7, 2025

Choose a reason for hiding this comment

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

This is only used as the pattern for mkdtemp() when creating the .dotnet, .dotnet-uidN, and shm directories, where a directory with a unique name is created first and renamed to one of those. It shouldn't affect compatibility, the user-unscoped shared memory files and lock files are still stored under /tmp/.dotnet/.

/// </summary>
public struct NamedWaitHandleOptions
{
private bool _notCurrentUserOnly;
Copy link
Member

Choose a reason for hiding this comment

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

I wonder what is the benefit of storing these as negative (_notXXX).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We wanted a zero-initialized struct as in default(NamedWaitHandleOptions) to have CurrentUserOnly == true and CurrentSessionOnly == true, so the fields store the NOT of the property values.

@danmoseley danmoseley requested a review from Copilot February 7, 2025 02:01
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 23 out of 38 changed files in this pull request and generated no comments.

Files not reviewed (15)
  • src/coreclr/pal/inc/pal.h: Language not supported
  • src/coreclr/pal/src/include/pal/mutex.hpp: Language not supported
  • src/coreclr/pal/src/include/pal/sharedmemory.h: Language not supported
  • src/coreclr/pal/src/include/pal/sharedmemory.inl: Language not supported
  • src/coreclr/pal/src/init/pal.cpp: Language not supported
  • src/coreclr/pal/src/synchobj/mutex.cpp: Language not supported
  • src/coreclr/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp: Language not supported
  • src/coreclr/pal/tests/palsuite/threading/NamedMutex/test1/nopal.cpp: Language not supported
  • src/libraries/System.Private.CoreLib/src/Resources/Strings.resx: Language not supported
  • src/libraries/Common/src/Interop/Windows/Advapi32/Interop.OpenThreadToken_SafeAccessTokenHandle.cs: Evaluated as low risk
  • src/libraries/Common/src/Interop/Windows/Interop.Errors.cs: Evaluated as low risk
  • src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Constants.cs: Evaluated as low risk
  • src/libraries/Common/src/System/Threading/OpenExistingResult.cs: Evaluated as low risk
  • src/libraries/Common/src/Interop/Windows/Advapi32/Interop.GetSecurityInfoByHandle.cs: Evaluated as low risk
  • src/libraries/Common/src/Interop/Windows/Advapi32/Interop.OpenThreadToken.cs: Evaluated as low risk

@jkotas
Copy link
Member

jkotas commented Feb 7, 2025

Do we have people lined up to use these new APIs so that we can verify that they work well in practice?

@kouvel
Copy link
Contributor Author

kouvel commented Feb 7, 2025

Do we have people lined up to use these new APIs so that we can verify that they work well in practice?

PowerShell was a use case for user-scoped mutexes. I'll reach out to them to see if they'd be able to test some previews.

The plan was also to deprecate the old APIs with a name argument but no options argument, to push toward the better defaults and explicit choices. It would be nice to do that in .NET 10 as well, but there may be some benefits to wait a release before deprecating.

@kouvel
Copy link
Contributor Author

kouvel commented Feb 19, 2025

Rebased to update with main

Copy link
Member

@janvorli janvorli left a comment

Choose a reason for hiding this comment

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

LGTM, thank you!

@kouvel
Copy link
Contributor Author

kouvel commented Mar 11, 2025

Thank you!

@kouvel kouvel merged commit 3eb245d into dotnet:main Mar 12, 2025
140 of 142 checks passed
@kouvel kouvel deleted the NamedWhApis branch March 12, 2025 16:11
@MichalStrehovsky
Copy link
Member

@kouvel the added tests are failing native AOT outerloop runs on Windows. Is that expected?

Example run: https://dev.azure.com/dnceng-public/public/_build/results?buildId=978053&view=logs&jobId=e2a090ef-1ffe-5b5a-8213-260fbf226a4b&j=e2a090ef-1ffe-5b5a-8213-260fbf226a4b&t=f60bbc11-44b7-557d-f3f2-48d48cb3fb2d

[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: False, open_currentUserOnly: False, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2ae
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: False, open_currentUserOnly: True, open_currentSessionOnly: True)
System.Threading.WaitHandleCannotBeOpenedException : An object with the specified name 'Local\d9519bd264e446619f48be5630240df9' exists and can't be opened because it's not compatible with the specified option 'CurrentUserOnly = true'.
   at System.Threading.EventWaitHandle.CreateEventCore(Boolean, EventResetMode, String, NamedWaitHandleOptionsInternal, Boolean&) + 0x288
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x25d
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: True, open_currentUserOnly: False, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2ae
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: True, open_currentUserOnly: True, open_currentSessionOnly: False)
System.Threading.WaitHandleCannotBeOpenedException : An object with the specified name 'Global\da9c8f1782e74610aea1e09fd34cc6d0' exists and can't be opened because it's not compatible with the specified option 'CurrentUserOnly = true'.
   at System.Threading.EventWaitHandle.CreateEventCore(Boolean, EventResetMode, String, NamedWaitHandleOptionsInternal, Boolean&) + 0x288
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x25d
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: False, open_currentUserOnly: False, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2ae
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: False, open_currentUserOnly: True, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2ae
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: True, open_currentUserOnly: False, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2ae
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: True, open_currentUserOnly: True, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.EventWaitHandleTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2ae
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[SKIP] System.Threading.Tests.EventWaitHandleTests.PingPong
[SKIP] System.Threading.Tests.MutexTests.CrossProcess_NamedMutex_ProtectedFileAccessAtomic
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: False, open_currentUserOnly: False, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2a0
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: False, open_currentUserOnly: True, open_currentSessionOnly: True)
System.Threading.WaitHandleCannotBeOpenedException : An object with the specified name 'Local\2659cf14dd9045af975e149dd2a0eb28' exists and can't be opened because it's not compatible with the specified option 'CurrentUserOnly = true'.
   at System.Threading.Mutex.CreateMutexCore(Boolean, String, NamedWaitHandleOptionsInternal, Boolean&) + 0x253
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x24f
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: True, open_currentUserOnly: False, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2a0
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: True, open_currentUserOnly: True, open_currentSessionOnly: False)
System.Threading.WaitHandleCannotBeOpenedException : An object with the specified name 'Global\0381efae81664e11968396a3384c8ebf' exists and can't be opened because it's not compatible with the specified option 'CurrentUserOnly = true'.
   at System.Threading.Mutex.CreateMutexCore(Boolean, String, NamedWaitHandleOptionsInternal, Boolean&) + 0x253
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x24f
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: False, open_currentUserOnly: False, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2a0
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: False, open_currentUserOnly: True, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2a0
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: True, open_currentUserOnly: False, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2a0
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.MutexTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: True, open_currentUserOnly: True, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.MutexTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2a0
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[SKIP] System.Threading.Tests.MutexTests.Ctor_TryCreateGlobalMutexTest_Uwp
[SKIP] System.Threading.Tests.SemaphoreSlimTests.WaitAsync_Timeout_NoUnhandledException
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: False, open_currentUserOnly: False, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2bd
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: False, open_currentUserOnly: True, open_currentSessionOnly: True)
System.Threading.WaitHandleCannotBeOpenedException : An object with the specified name 'Local\ed8e10edb9f84443b0541a0dcd7a5a8b' exists and can't be opened because it's not compatible with the specified option 'CurrentUserOnly = true'.
   at System.Threading.Semaphore.CreateSemaphoreCore(Int32, Int32, String, NamedWaitHandleOptionsInternal, Boolean&) + 0x27c
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x26c
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: True, open_currentUserOnly: False, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2bd
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: False, create_currentSessionOnly: True, open_currentUserOnly: True, open_currentSessionOnly: False)
System.Threading.WaitHandleCannotBeOpenedException : An object with the specified name 'Global\806843a66d004ecfa814d9f947966a2f' exists and can't be opened because it's not compatible with the specified option 'CurrentUserOnly = true'.
   at System.Threading.Semaphore.CreateSemaphoreCore(Int32, Int32, String, NamedWaitHandleOptionsInternal, Boolean&) + 0x27c
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x26c
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: False, open_currentUserOnly: False, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2bd
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: False, open_currentUserOnly: True, open_currentSessionOnly: True)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2bd
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: True, open_currentUserOnly: False, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2bd
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e
[FAIL] System.Threading.Tests.SemaphoreTests.NameNamespaceTest(create_currentUserOnly: True, create_currentSessionOnly: True, open_currentUserOnly: True, open_currentSessionOnly: False)
Assert.Equal() Failure: Values differ
Expected: True
Actual:   False
   at System.Threading.Tests.SemaphoreTests.NameNamespaceTest(Boolean create_currentUserOnly, Boolean create_currentSessionOnly, Boolean open_currentUserOnly, Boolean open_currentSessionOnly) + 0x2bd
   at System.Threading.Tests!<BaseAddress>+0x7e3c6d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x9e

@kouvel
Copy link
Contributor Author

kouvel commented Mar 13, 2025

the added tests are failing native AOT outerloop runs on Windows. Is that expected?

It looks like some of the tests run on Windows Server Core, which apparently similarly to Windows Nano Server, does not use different namespaces for local and global named synchronization objects. I put up a PR to disable the namespace tests there, which I believe would fix the issue.

@ericstj
Copy link
Member

ericstj commented Apr 4, 2025

@kouvel @janvorli - should we add a note about this to dotnet/core#9824 or dotnet/core#9823?

@kouvel
Copy link
Contributor Author

kouvel commented Apr 4, 2025

@kouvel @janvorli - should we add a note about this to dotnet/core#9824 or dotnet/core#9823?

I wanted to get some documentation added and updated before that, so that folks interested in trying it can have some base info about the new APIs vs the old APIs (esp. since it was also desired to deprecate the relevant old APIs separately). I've been working on that in the background.

@github-actions github-actions bot locked and limited conversation to collaborators May 4, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants