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

Port some CoreRT Threading classes to Mono #47333

Merged
merged 36 commits into from
Mar 13, 2021

Conversation

CoffeeFlux
Copy link
Contributor

@CoffeeFlux CoffeeFlux commented Jan 22, 2021

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.

@vargaz
Copy link
Contributor

vargaz commented Jan 22, 2021

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.

@CoffeeFlux
Copy link
Contributor Author

It should be yeah, but this PR is already large enough that I'd prefer to do that in a followup.

@CoffeeFlux
Copy link
Contributor Author

CoffeeFlux commented Feb 8, 2021

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.

private void Initialize()
{
InitInternal(this);

// TODO: This can go away once the mono/mono mirror is disabled
stack_size = _startHelper!._maxStackSize;
Copy link
Member

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.

Copy link
Contributor Author

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.

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 currently used by the runtime.

Copy link
Member

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")

Copy link
Member

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.

Copy link
Contributor Author

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?

@vargaz
Copy link
Contributor

vargaz commented Feb 9, 2021

The runtime changes look ok to me.

@@ -409,6 +409,13 @@ private static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int
}
}

internal static void ThrowInvalidHandleException()
Copy link
Contributor

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)
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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

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;
}
. The API is windows only and on Unix will have never reached error handling.

@CoffeeFlux
Copy link
Contributor Author

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.

@CoffeeFlux
Copy link
Contributor Author

Ignore the Windows stuff for now, I'll just boot a Windows machine and sort out whatever build issues are arising there.

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.
@CoffeeFlux
Copy link
Contributor Author

CoffeeFlux commented Mar 12, 2021

I still have a cleanup-related change to push, but this is green on CI. Issues uncovered as part of the port:

#49518

#49521

#48720

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 InvalidOperationException saying the semaphore is full instead of just a SemaphoreFullException, but that's the legacy behavior.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Nice!

@marek-safar marek-safar merged commit 6791d05 into dotnet:main Mar 13, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Apr 12, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
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.

Move System.Threading.Event/Mutex/Semaphore support to managed code
7 participants