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

Mono: Monitor.Enter() is not interrupted by Thread.Interrupt() #87718

Open
kouvel opened this issue Jun 17, 2023 · 4 comments
Open

Mono: Monitor.Enter() is not interrupted by Thread.Interrupt() #87718

kouvel opened this issue Jun 17, 2023 · 4 comments
Assignees
Milestone

Comments

@kouvel
Copy link
Member

kouvel commented Jun 17, 2023

See MonitorTests.InterruptWaitTest under src/libraries/System.Threading/tests (the test is being added by PR #87672):

public static void InterruptWaitTest()
{
object obj = new();
lock (obj)
{
var threadReady = new AutoResetEvent(false);
var t =
ThreadTestHelpers.CreateGuardedThread(out Action waitForThread, () =>
{
threadReady.Set();
Assert.Throws<ThreadInterruptedException>(() => Monitor.Enter(obj));
});
t.IsBackground = true;
t.Start();
threadReady.CheckedWait();
t.Interrupt();
waitForThread();
}
}

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jun 17, 2023
@lambdageek lambdageek self-assigned this Jun 19, 2023
@lambdageek lambdageek removed the untriaged New issue has not been triaged by the area owner label Jun 19, 2023
@lambdageek lambdageek added this to the 8.0.0 milestone Jun 19, 2023
@lambdageek
Copy link
Member

Not a regression. Same behavior with mono on net6.0 and net7.0.

Works on legacy Mono 6.12.0.188.

It looks like we still have the code for async thread interruptions and the WaitSleepJoin thread state. But we don't have this block anymore in dotnet/runtime mono

https://github.com/mono/mono/blob/59a40d68879b69416f15a1d78198483cddda8cc0/mono/metadata/threads.c#L5161-L5170

@lambdageek
Copy link
Member

That code was removed as part of #47333

I'm not sure if there was some corert-based interruption logic that was wired up that didn't work, or if it worked initially and then we added something before the net6 release that broke it

@lambdageek
Copy link
Member

@kouvel This is probably going to be hard to fix. The right thing is to finish out #48058 and remove mono's native Monitor implementation in favor of a managed one like NativeAOT.

But touching anything related to the sync block causes significant performance perturbations. I think we can probably switch to using a Lock object in Mono instead of the native Monitor, but I'm less sure about switching from an inline sync block to a conditional weak table.

The runtime code for interruptable syscalls is still there, so that part of the native monitor implementation is still functional. It's just that we don't do anything with that information and simply retry the syscall as if we got a spurious interruption. I suppose one thing we can do is call out to managed to WaitSubsystem.ThreadWaitInfo.CheckAndResetPendingInterrupt_NotLocked (same as a Sleep0) and check whether there is a pending interrupt. I'm not sure if that kind of hack is worth it. (Also I'm not 100% confident that it won't mess up the WaitSubsystem invariants)

@lambdageek
Copy link
Member

Made a draft PR that piggybacks on the interruption logic in Mono and calls out to thread.WaitInfo.CheckAndResetPendingInterrupt_TakeLock (which takes s_Lock and then checks the wait subsystem interruption flag)

it's not too bad - it won't get called unless the condvar wait syscall is actually interrupted for some reason (most commonly, I think, due to a GC) and calling out to managed is not unreasonable at that point.

I will play around with actually replacing native Monitor logic with a managed Lock, too, but I think that's probably too big of a change for net8 at this point

@lambdageek lambdageek modified the milestones: 8.0.0, 9.0.0 Aug 4, 2023
@mangod9 mangod9 modified the milestones: 9.0.0, Future Jul 24, 2024
@lambdageek lambdageek assigned steveisok and unassigned lambdageek Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants