Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Improve inlinability of libuv success checking #1059

Merged
merged 3 commits into from
Aug 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ private void ThreadStart(object parameter)

try
{
var ran1 = _loop.Run();
_loop.Run();
if (_stopImmediate)
{
// thread-abort form of exit, resources will be leaked
Expand All @@ -291,7 +291,7 @@ private void ThreadStart(object parameter)
_post.Dispose();

// Ensure the Dispose operations complete in the event loop.
var ran2 = _loop.Run();
_loop.Run();

_loop.Dispose();
}
Expand Down
108 changes: 59 additions & 49 deletions src/Microsoft.AspNetCore.Server.Kestrel/Internal/Networking/Libuv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Networking
Expand Down Expand Up @@ -61,50 +62,57 @@ internal Libuv(bool onlyForTesting)

public readonly bool IsWindows;

public int Check(int statusCode)
public void ThrowIfErrored(int statusCode)
{
Exception error;
var result = Check(statusCode, out error);
if (error != null)
// Note: method is explicitly small so the success case is easily inlined
if (statusCode < 0)
{
throw error;
ThrowError(statusCode);
}
return statusCode;
}

public int Check(int statusCode, out Exception error)
private void ThrowError(int statusCode)
{
if (statusCode < 0)
{
var errorName = err_name(statusCode);
var errorDescription = strerror(statusCode);
error = new UvException("Error " + statusCode + " " + errorName + " " + errorDescription, statusCode);
}
else
{
error = null;
}
return statusCode;
// Note: only has one throw block so it will marked as "Does not return" by the jit
// and not inlined into previous function, while also marking as a function
// that does not need cpu register prep to call (see: https://github.com/dotnet/coreclr/pull/6103)
throw GetError(statusCode);
}

public void Check(int statusCode, out Exception error)
{
// Note: method is explicitly small so the success case is easily inlined
error = statusCode < 0 ? GetError(statusCode) : null;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private UvException GetError(int statusCode)
{
// Note: method marked as NoInlining so it doesn't bloat either of the two preceeding functions
// Check and ThrowError and alter their jit heuristics.
var errorName = err_name(statusCode);
var errorDescription = strerror(statusCode);
return new UvException("Error " + statusCode + " " + errorName + " " + errorDescription, statusCode);
}

protected Func<UvLoopHandle, int> _uv_loop_init;
public void loop_init(UvLoopHandle handle)
{
Check(_uv_loop_init(handle));
ThrowIfErrored(_uv_loop_init(handle));
}

protected Func<IntPtr, int> _uv_loop_close;
public void loop_close(UvLoopHandle handle)
{
handle.Validate(closed: true);
Check(_uv_loop_close(handle.InternalGetHandle()));
ThrowIfErrored(_uv_loop_close(handle.InternalGetHandle()));
}

protected Func<UvLoopHandle, int, int> _uv_run;
public int run(UvLoopHandle handle, int mode)
public void run(UvLoopHandle handle, int mode)
{
handle.Validate();
return Check(_uv_run(handle, mode));
ThrowIfErrored(_uv_run(handle, mode));
}

protected Action<UvLoopHandle> _uv_stop;
Expand All @@ -131,10 +139,10 @@ public void unref(UvHandle handle)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
protected delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket);
protected uv_fileno_func _uv_fileno;
public int uv_fileno(UvHandle handle, ref IntPtr socket)
public void uv_fileno(UvHandle handle, ref IntPtr socket)
{
handle.Validate();
return Check(_uv_fileno(handle, ref socket));
ThrowIfErrored(_uv_fileno(handle, ref socket));
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand All @@ -158,35 +166,35 @@ public void async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb)
{
loop.Validate();
handle.Validate();
Check(_uv_async_init(loop, handle, cb));
ThrowIfErrored(_uv_async_init(loop, handle, cb));
}

protected Func<UvAsyncHandle, int> _uv_async_send;
public void async_send(UvAsyncHandle handle)
{
Check(_uv_async_send(handle));
ThrowIfErrored(_uv_async_send(handle));
}

protected Func<IntPtr, int> _uv_unsafe_async_send;
public void unsafe_async_send(IntPtr handle)
{
Check(_uv_unsafe_async_send(handle));
ThrowIfErrored(_uv_unsafe_async_send(handle));
}

protected Func<UvLoopHandle, UvTcpHandle, int> _uv_tcp_init;
public void tcp_init(UvLoopHandle loop, UvTcpHandle handle)
{
loop.Validate();
handle.Validate();
Check(_uv_tcp_init(loop, handle));
ThrowIfErrored(_uv_tcp_init(loop, handle));
}

protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags);
protected uv_tcp_bind_func _uv_tcp_bind;
public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags)
{
handle.Validate();
Check(_uv_tcp_bind(handle, ref addr, flags));
ThrowIfErrored(_uv_tcp_bind(handle, ref addr, flags));
if (PlatformApis.IsWindows)
{
tcp_bind_windows_extras(handle);
Expand All @@ -200,7 +208,7 @@ private unsafe void tcp_bind_windows_extras(UvTcpHandle handle)
const int SOCKET_ERROR = -1;

var socket = IntPtr.Zero;
Check(_uv_fileno(handle, ref socket));
ThrowIfErrored(_uv_fileno(handle, ref socket));

// Enable loopback fast-path for lower latency for localhost comms, like HttpPlatformHandler fronting
// http://blogs.technet.com/b/wincat/archive/2012/12/05/fast-tcp-loopback-performance-and-low-latency-with-windows-server-2012-tcp-loopback-fast-path.aspx
Expand All @@ -218,7 +226,7 @@ private unsafe void tcp_bind_windows_extras(UvTcpHandle handle)
}
else
{
Check(errorId);
ThrowIfErrored(errorId);
}
}
}
Expand All @@ -227,29 +235,29 @@ private unsafe void tcp_bind_windows_extras(UvTcpHandle handle)
public void tcp_open(UvTcpHandle handle, IntPtr hSocket)
{
handle.Validate();
Check(_uv_tcp_open(handle, hSocket));
ThrowIfErrored(_uv_tcp_open(handle, hSocket));
}

protected Func<UvTcpHandle, int, int> _uv_tcp_nodelay;
public void tcp_nodelay(UvTcpHandle handle, bool enable)
{
handle.Validate();
Check(_uv_tcp_nodelay(handle, enable ? 1 : 0));
ThrowIfErrored(_uv_tcp_nodelay(handle, enable ? 1 : 0));
}

protected Func<UvLoopHandle, UvPipeHandle, int, int> _uv_pipe_init;
public void pipe_init(UvLoopHandle loop, UvPipeHandle handle, bool ipc)
{
loop.Validate();
handle.Validate();
Check(_uv_pipe_init(loop, handle, ipc ? -1 : 0));
ThrowIfErrored(_uv_pipe_init(loop, handle, ipc ? -1 : 0));
}

protected Func<UvPipeHandle, string, int> _uv_pipe_bind;
public void pipe_bind(UvPipeHandle handle, string name)
{
handle.Validate();
Check(_uv_pipe_bind(handle, name));
ThrowIfErrored(_uv_pipe_bind(handle, name));
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand All @@ -258,15 +266,15 @@ public void pipe_bind(UvPipeHandle handle, string name)
public void listen(UvStreamHandle handle, int backlog, uv_connection_cb cb)
{
handle.Validate();
Check(_uv_listen(handle, backlog, cb));
ThrowIfErrored(_uv_listen(handle, backlog, cb));
}

protected Func<UvStreamHandle, UvStreamHandle, int> _uv_accept;
public void accept(UvStreamHandle server, UvStreamHandle client)
{
server.Validate();
client.Validate();
Check(_uv_accept(server, client));
ThrowIfErrored(_uv_accept(server, client));
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand Down Expand Up @@ -294,21 +302,23 @@ unsafe public int pipe_pending_count(UvPipeHandle handle)
public void read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
{
handle.Validate();
Check(_uv_read_start(handle, alloc_cb, read_cb));
ThrowIfErrored(_uv_read_start(handle, alloc_cb, read_cb));
}

protected Func<UvStreamHandle, int> _uv_read_stop;
public void read_stop(UvStreamHandle handle)
{
handle.Validate();
Check(_uv_read_stop(handle));
ThrowIfErrored(_uv_read_stop(handle));
}

protected Func<UvStreamHandle, uv_buf_t[], int, int> _uv_try_write;
public int try_write(UvStreamHandle handle, uv_buf_t[] bufs, int nbufs)
{
handle.Validate();
return Check(_uv_try_write(handle, bufs, nbufs));
var count = _uv_try_write(handle, bufs, nbufs);
ThrowIfErrored(count);
return count;
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand All @@ -320,7 +330,7 @@ unsafe public void write(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, i
{
req.Validate();
handle.Validate();
Check(_uv_write(req, handle, bufs, nbufs, cb));
ThrowIfErrored(_uv_write(req, handle, bufs, nbufs, cb));
}

unsafe protected delegate int uv_write2_func(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb);
Expand All @@ -329,7 +339,7 @@ unsafe public void write2(UvRequest req, UvStreamHandle handle, Libuv.uv_buf_t*
{
req.Validate();
handle.Validate();
Check(_uv_write2(req, handle, bufs, nbufs, sendHandle, cb));
ThrowIfErrored(_uv_write2(req, handle, bufs, nbufs, sendHandle, cb));
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand All @@ -339,7 +349,7 @@ public void shutdown(UvShutdownReq req, UvStreamHandle handle, uv_shutdown_cb cb
{
req.Validate();
handle.Validate();
Check(_uv_shutdown(req, handle, cb));
ThrowIfErrored(_uv_shutdown(req, handle, cb));
}

protected Func<int, IntPtr> _uv_err_name;
Expand Down Expand Up @@ -376,16 +386,16 @@ public int req_size(RequestType reqType)

protected delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr);
protected uv_ip4_addr_func _uv_ip4_addr;
public int ip4_addr(string ip, int port, out SockAddr addr, out Exception error)
public void ip4_addr(string ip, int port, out SockAddr addr, out Exception error)
{
return Check(_uv_ip4_addr(ip, port, out addr), out error);
Check(_uv_ip4_addr(ip, port, out addr), out error);
}

protected delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr);
protected uv_ip6_addr_func _uv_ip6_addr;
public int ip6_addr(string ip, int port, out SockAddr addr, out Exception error)
public void ip6_addr(string ip, int port, out SockAddr addr, out Exception error)
{
return Check(_uv_ip6_addr(ip, port, out addr), out error);
Check(_uv_ip6_addr(ip, port, out addr), out error);
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Expand All @@ -402,15 +412,15 @@ unsafe public void walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg)
public void tcp_getsockname(UvTcpHandle handle, out SockAddr addr, ref int namelen)
{
handle.Validate();
Check(_uv_tcp_getsockname(handle, out addr, ref namelen));
ThrowIfErrored(_uv_tcp_getsockname(handle, out addr, ref namelen));
}

public delegate int uv_tcp_getpeername_func(UvTcpHandle handle, out SockAddr addr, ref int namelen);
protected uv_tcp_getpeername_func _uv_tcp_getpeername;
public void tcp_getpeername(UvTcpHandle handle, out SockAddr addr, ref int namelen)
{
handle.Validate();
Check(_uv_tcp_getpeername(handle, out addr, ref namelen));
ThrowIfErrored(_uv_tcp_getpeername(handle, out addr, ref namelen));
}

public uv_buf_t buf_init(IntPtr memory, int len)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public void Init(Libuv uv)
_uv.loop_init(this);
}

public int Run(int mode = 0)
public void Run(int mode = 0)
{
return _uv.run(this, mode);
_uv.run(this, mode);
}

public void Stop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private static void UvConnectionCb(IntPtr handle, int status)
var stream = FromIntPtr<UvStreamHandle>(handle);

Exception error;
status = stream.Libuv.Check(status, out error);
stream.Libuv.Check(status, out error);

try
{
Expand Down