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

IOThreadScheduler using IO Threads on Windows #4282

Merged
merged 1 commit into from
May 27, 2020

Conversation

mconnew
Copy link
Member

@mconnew mconnew commented May 26, 2020

Scheduling a delegate via overlapped to the IO thread pool wasn't available when this project started. It is now available on Windows so bringing back this functionality to prevent extra thread creation.

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

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

Thanks for reverting this.

@@ -295,6 +296,16 @@ public static Action<T1> ThunkCallback<T1>(Action<T1> callback)
return (new ActionThunk<T1>(callback)).ThunkFrame;
}

#pragma warning disable CS3002 // Return type is not CLS-compliant
#pragma warning disable CS3001 // Argument type is not CLS-compliant
public static IOCompletionCallback ThunkCallback(IOCompletionCallback callback)
Copy link
Member

Choose a reason for hiding this comment

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

public?

}
catch (Exception exception)
{
if (!Fx.HandleAtThreadBase(exception))
Copy link
Member

Choose a reason for hiding this comment

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

Could use exception filters of you wanted

}

bool queued = false;
while (!queued)
{
try { }
try
{ }
finally
Copy link
Member

Choose a reason for hiding this comment

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

Is this code run on platforms other than .NET Core? This try/finally pattern isn't applicable to core, which lacks thread aborts.

// by the GC anyway.
private unsafe class ScheduledOverlapped
{
private static bool s_isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
Copy link
Member

Choose a reason for hiding this comment

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

readonly. It'll be optimized like a const at tier 1.

if (callback != null)
{
callback(state);
}
Copy link
Member

Choose a reason for hiding this comment

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

FWIW, you can now do things like:
callback?.Invoke(state);

Fx.Assert(iots != null, "Post called with a null scheduler.");

_scheduler = iots;
_postDelegate();
Copy link
Member

Choose a reason for hiding this comment

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

Why go through a delegate here?

}
else
{
_postDelegate = PostNewThread;
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 we should experiment with this being a QieueUserWorkItem, but that can be a discussion for another day :-)

Copy link
Member

Choose a reason for hiding this comment

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

I feel like it can’t really hurt but we can leave it

private void PostNewThread()
{
var thread = new Thread(new ThreadStart(Callback));
thread.Start();
Copy link
Member

Choose a reason for hiding this comment

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

This should set IsBackground to true before starting the thread.

@@ -12,7 +12,7 @@ public class ServiceModelSynchronizationContext : SynchronizationContext

public override void Post(SendOrPostCallback d, object state)
{
IOThreadScheduler.ScheduleCallbackNoFlow(d, state);
IOThreadScheduler.ScheduleCallbackNoFlow((s) => d(s), state);
Copy link
Member

Choose a reason for hiding this comment

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

This is going to allocate a closure and a delegate on every invocation. Is it called low-frequency enough that the overhead doesn't matter?

}
else
{
await Task.Factory.FromAsync(other.BeginClose(timeout, callback: null, state: null), other.EndClose);
return Task.Factory.FromAsync(other.BeginClose, other.EndClose, timeout, null);
Copy link
Member

Choose a reason for hiding this comment

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

I thought I remember you saying that everything was implemented via tasks and then APM was wrapped around those. This is the inverse. Is this just a rarity?

@HongGit HongGit merged commit fd00ad9 into dotnet:release/3.1.0 May 27, 2020
HongGit added a commit that referenced this pull request Jun 22, 2020
@mconnew mconnew deleted the IOThreadScheduler branch October 11, 2023 17:10
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.

5 participants