-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Port some CoreRT Threading classes to Mono #47333
Port some CoreRT Threading classes to Mono #47333
Conversation
In addition to the icalls, it should be possible to remove all the w32semaphore/event/mutex files from the netcore build. It might be possible to remove the whole w32handle code on platforms which have no processes like wasm, i.e. w32process-unix.c is the last user of that code. |
It should be yeah, but this PR is already large enough that I'd prefer to do that in a followup. |
b204fa1
to
ea04f42
Compare
Rebased and took out of draft since the other PRs are in. Not sure if this will build, but maybe I'll get lucky? Still should be largely reasonable to review, and I still recommend commit-by-commit. |
src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs
Outdated
Show resolved
Hide resolved
private void Initialize() | ||
{ | ||
InitInternal(this); | ||
|
||
// TODO: This can go away once the mono/mono mirror is disabled | ||
stack_size = _startHelper!._maxStackSize; |
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 think you also need to delete the stack_size
field and pass the stack_size
as argument instead.
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 pinged Aleksey about this TODO since I don't have context for the recent Thread changes and don't want to spent half an hour looking through it all if possible. I'll update tomorrow after I talk with him.
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 currently used by the runtime.
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 pinged Aleksey about this TODO since I don't have context for the recent Thread changes and don't want to spent half an hour looking through it all if possible. I'll update tomorrow after I talk with him.
I don't remember what that comment means anymore except the superficial "once we stop the mirror, the layout of MonoInternalThread
can change".
But yea we so still need to pass a stack_size down into the runtime so that it's threaded down to the native thread creation functions. (otherwise it ends up initialized to 0 which I think mean "default 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.
I have added this comment one month ago as I was moving more Thread.cs to be shared. It is exactly as @lambdageek says - you need to pass a stack_size down into the native thread creating function.
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.
Hopefully I understood correctly how the stack size stuff is supposed to work?
The runtime changes look ok to me. |
@@ -409,6 +409,13 @@ private static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int | |||
} | |||
} | |||
|
|||
internal static void ThrowInvalidHandleException() |
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.
internal static void ThrowInvalidHandleException() => throw new InvalidOperationException(SR.InvalidOperation_InvalidHandle) { HResult = HResults.E_HANDLE; }
@@ -19,7 +19,7 @@ private void CreateEventCore(bool initialState, EventResetMode mode, string name | |||
createdNew = true; | |||
} | |||
|
|||
private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle result) | |||
private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle? result) |
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 might be better to move to the caller. It seems to do always do some error checking which is Windows specific
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 think we have to match the Windows equivalent here, since otherwise you end up with a bunch of weird platform-specific code at a higher level? Maybe I'm misunderstanding.
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 was referring to code patterns like
runtime/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs
Lines 32 to 45 in 1d9e50c
public static EventWaitHandle OpenExisting(string name) | |
{ | |
switch (OpenExistingWorker(name, out EventWaitHandle? result)) | |
{ | |
case OpenExistingResult.NameNotFound: | |
throw new WaitHandleCannotBeOpenedException(); | |
case OpenExistingResult.NameInvalid: | |
throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); | |
case OpenExistingResult.PathNotFound: | |
throw new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, name)); | |
default: | |
Debug.Assert(result != null, "result should be non-null on success"); | |
return result; | |
} |
src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs
Outdated
Show resolved
Hide resolved
src/mono/System.Private.CoreLib/src/System/Threading/LowLevelLock.cs
Outdated
Show resolved
Hide resolved
Oh yeah, cc: @fanyang-mono @naricc, as per usual I'm changing threading things and this might have perf implications, either for TE or microbenchmarks. No need to run in advance of merging this PR, but you might see movement. |
Ignore the Windows stuff for now, I'll just boot a Windows machine and sort out whatever build issues are arising there. |
src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs
Outdated
Show resolved
Hide resolved
Some of these are uncovering real issues, so I think it's better to silently ignore the argument for now
This might be a bad idea and we should just call into managed to check?
This is probably not optimal from a linker perspective, but that can be dealt with later
The remaining failures are just related to the named mutexes
I originally implemented Zoltan's suggestion, but this seems to work and is significantly cleaner. Pre-jitting is also an option here, so if this doesn't work try that next.
I think it would make much more sense to always throw SemaphoreFullException instead of sometimes throwing InvalidOperationException saying the semaphore is full, but this preserves the old behavior.
59504ff
to
891987b
Compare
I still have a cleanup-related change to push, but this is green on CI. Issues uncovered as part of the port: I don't consider any of these a big enough deal to block a merge here. All of them would probably block CoreCLR from adopting the managed implementation, but from a Mono perspective the only regression is the interrupts on Windows, and thankfully that appears to be the easiest of the three to address. For the mutex abandonment, I opted to do it from the Thread object's destructor. As far as I can tell this works fine and is fairly clean, but if the approach is discovered to be faulty I can switch to pre-jitting the method instead. For the different exception types, I just catch and rethrow. I'm not particularly fond of throwing an |
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.
Nice!
Fixes #44795
Best reviewed commit by commit. In some cases, I've left comments in the commit description. I expect the most interesting commits to be the last few, in particular the annotations.