Skip to content

Commit

Permalink
Started to reuse SocketAsyncEventArgs instances.
Browse files Browse the repository at this point in the history
  • Loading branch information
lextm committed Nov 21, 2016
1 parent 97489d3 commit c8cba7e
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 39 deletions.
21 changes: 10 additions & 11 deletions SharpSnmpLib/Messaging/Discoverer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,11 @@ public async Task DiscoverAsync(VersionCode version, IPEndPoint broadcastAddress

using (var udp = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp))
{
using (var info = new SocketAsyncEventArgs())
var info = SocketExtension.EventArgsFactory.Create();
info.RemoteEndPoint = broadcastAddress;
info.SetBuffer(bytes, 0, bytes.Length);
using (var awaitable1 = new SocketAwaitable(info))
{
info.RemoteEndPoint = broadcastAddress;
info.SetBuffer(bytes, 0, bytes.Length);
var awaitable1 = new SocketAwaitable(info);
await udp.SendToAsync(awaitable1);
}

Expand Down Expand Up @@ -370,13 +370,16 @@ private async Task ReceiveAsync(Socket socket)

int count;
var reply = new byte[_bufferSize];
var args = new SocketAsyncEventArgs();
var args = SocketExtension.EventArgsFactory.Create();
try
{
args.RemoteEndPoint = remote;
args.SetBuffer(reply, 0, _bufferSize);
var awaitable = new SocketAwaitable(args);
count = await socket.ReceiveAsync(awaitable);
using (var awaitable = new SocketAwaitable(args))
{
count = await socket.ReceiveAsync(awaitable);
}

await Task.Factory.StartNew(() => HandleMessage(reply, count, (IPEndPoint)remote)).ConfigureAwait(false);
}
catch (SocketException ex)
Expand All @@ -392,10 +395,6 @@ private async Task ReceiveAsync(Socket socket)
}
}
}
finally
{
args.Dispose();
}
}
}
}
Expand Down
21 changes: 11 additions & 10 deletions SharpSnmpLib/Messaging/ListenerBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,14 +426,16 @@ public async Task SendResponseAsync(ISnmpMessage response, EndPoint receiver)
}

var buffer = response.ToBytes();
var info = new SocketAsyncEventArgs();
var info = SocketExtension.EventArgsFactory.Create();

try
{
info.RemoteEndPoint = receiver;
info.SetBuffer(buffer, 0, buffer.Length);
var awaitable1 = new SocketAwaitable(info);
await _socket.SendToAsync(awaitable1);
using (var awaitable1 = new SocketAwaitable(info))
{
await _socket.SendToAsync(awaitable1);
}
}
catch (SocketException ex)
{
Expand All @@ -443,10 +445,6 @@ public async Task SendResponseAsync(ISnmpMessage response, EndPoint receiver)
throw;
}
}
finally
{
info.Dispose();
}
}

/// <summary>
Expand Down Expand Up @@ -512,13 +510,16 @@ private async Task ReceiveAsync()

int count;
var reply = new byte[_bufferSize];
var args = new SocketAsyncEventArgs();
var args = SocketExtension.EventArgsFactory.Create();
try
{
args.RemoteEndPoint = remote;
args.SetBuffer(reply, 0, _bufferSize);
var awaitable = new SocketAwaitable(args);
count = await _socket.ReceiveAsync(awaitable);
using (var awaitable = new SocketAwaitable(args))
{
count = await _socket.ReceiveAsync(awaitable);
}

await Task.Factory.StartNew(() => HandleMessage(reply, count, (IPEndPoint)remote));
}
catch (SocketException ex)
Expand Down
28 changes: 13 additions & 15 deletions SharpSnmpLib/Messaging/SnmpMessageExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -551,11 +551,11 @@ public static async Task SendAsync(this ISnmpMessage message, EndPoint manager,
}

var bytes = message.ToBytes();
using (var info = new SocketAsyncEventArgs())
var info = SocketExtension.EventArgsFactory.Create();
info.RemoteEndPoint = manager;
info.SetBuffer(bytes, 0, bytes.Length);
using (var awaitable1 = new SocketAwaitable(info))
{
info.RemoteEndPoint = manager;
info.SetBuffer(bytes, 0, bytes.Length);
var awaitable1 = new SocketAwaitable(info);
await socket.SendToAsync(awaitable1);
}
}
Expand Down Expand Up @@ -695,26 +695,28 @@ public static async Task<ISnmpMessage> GetResponseAsync(this ISnmpMessage reques
var bufSize = udpSocket.ReceiveBufferSize = Messenger.MaxMessageSize;

// Whatever you change, try to keep the Send and the Receive close to each other.
using (var info = new SocketAsyncEventArgs())
var info = SocketExtension.EventArgsFactory.Create();
info.RemoteEndPoint = receiver;
info.SetBuffer(bytes, 0, bytes.Length);
using (var awaitable1 = new SocketAwaitable(info))
{
info.RemoteEndPoint = receiver;
info.SetBuffer(bytes, 0, bytes.Length);
var awaitable1 = new SocketAwaitable(info);
await udpSocket.SendToAsync(awaitable1);
}

int count;
var reply = new byte[bufSize];

// IMPORTANT: follow http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
var args = new SocketAsyncEventArgs();
var args = SocketExtension.EventArgsFactory.Create();
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
try
{
args.RemoteEndPoint = remote;
args.SetBuffer(reply, 0, bufSize);
var awaitable = new SocketAwaitable(args);
count = await udpSocket.ReceiveAsync(awaitable);
using (var awaitable = new SocketAwaitable(args))
{
count = await udpSocket.ReceiveAsync(awaitable);
}
}
catch (SocketException ex)
{
Expand All @@ -733,10 +735,6 @@ public static async Task<ISnmpMessage> GetResponseAsync(this ISnmpMessage reques

throw;
}
finally
{
args.Dispose();
}

// Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
var response = MessageFactory.ParseMessages(reply, 0, count, registry)[0];
Expand Down
68 changes: 68 additions & 0 deletions SharpSnmpLib/Messaging/SocketAsyncEventArgsFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SNMP application factory class.
// Copyright (C) 2009-2010 Lex Li
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.Collections.Generic;
using System.Net.Sockets;

namespace Lextm.SharpSnmpLib.Messaging
{
/// <summary>
/// SNMP application factory, who holds all pipeline instances.
/// </summary>
public sealed class SocketAsyncEventArgsFactory
{
private readonly object _root = new object();
private readonly Queue<SocketAsyncEventArgs> _queue = new Queue<SocketAsyncEventArgs>();

/// <summary>
/// Finds an available event args.
/// </summary>
/// <returns></returns>
public SocketAsyncEventArgs Create()
{
SocketAsyncEventArgs result = null;
lock (_root)
{
if (_queue.Count > 0)
{
result = _queue.Dequeue();
}
}

if (result == null)
{
result = new SocketAsyncEventArgs();
}

return result;
}

/// <summary>
/// Reuses the specified event args.
/// </summary>
/// <param name="args">The resource.</param>
internal void Reuse(SocketAsyncEventArgs args)
{
lock (_root)
{
_queue.Enqueue(args);
}
}
}
}
34 changes: 31 additions & 3 deletions SharpSnmpLib/Messaging/SocketAwaitable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
using System.Threading;
using System.Threading.Tasks;

internal sealed class SocketAwaitable : INotifyCompletion
internal sealed class SocketAwaitable : INotifyCompletion, IDisposable
{
private readonly static Action SENTINEL = () => { };

internal bool m_wasCompleted;
internal Action m_continuation;
internal SocketAsyncEventArgs m_eventArgs;
private bool _disposed;

public SocketAwaitable(SocketAsyncEventArgs eventArgs)
{
Expand All @@ -21,8 +22,35 @@ public SocketAwaitable(SocketAsyncEventArgs eventArgs)
throw new ArgumentNullException(nameof(eventArgs));
}

this.m_eventArgs = eventArgs;
eventArgs.Completed += Completed;
m_eventArgs = eventArgs;
m_eventArgs.Completed += Completed;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

~SocketAwaitable()
{
Dispose(false);
}

private void Dispose(bool disposing)
{
if (_disposed)
{
return;
}

_disposed = true;
if (disposing)
{
m_eventArgs.Completed -= Completed;
SocketExtension.EventArgsFactory.Reuse(m_eventArgs);
m_eventArgs = null;
}
}

private void Completed(object sender, SocketAsyncEventArgs e)
Expand Down
2 changes: 2 additions & 0 deletions SharpSnmpLib/Messaging/SocketExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ public static SocketAwaitable SendToAsync(this Socket socket,
awaitable.m_wasCompleted = true;
return awaitable;
}

internal static readonly SocketAsyncEventArgsFactory EventArgsFactory = new SocketAsyncEventArgsFactory();
}
}
1 change: 1 addition & 0 deletions SharpSnmpLib/SharpSnmpLib.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<Compile Include="Messaging\ResponseMessage.cs" />
<Compile Include="Messaging\SetRequestMessage.cs" />
<Compile Include="Messaging\SnmpMessageExtension.cs" />
<Compile Include="Messaging\SocketAsyncEventArgsFactory.cs" />
<Compile Include="Messaging\SocketAwaitable.cs" />
<Compile Include="Messaging\SocketExtension.cs" />
<Compile Include="Messaging\TimeoutException.cs" />
Expand Down
1 change: 1 addition & 0 deletions SharpSnmpLib/SharpSnmpLib.Full.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
<Compile Include="Messaging\ResponseMessage.cs" />
<Compile Include="Messaging\SetRequestMessage.cs" />
<Compile Include="Messaging\SnmpMessageExtension.cs" />
<Compile Include="Messaging\SocketAsyncEventArgsFactory.cs" />
<Compile Include="Messaging\SocketAwaitable.cs" />
<Compile Include="Messaging\SocketExtension.cs" />
<Compile Include="Messaging\TimeoutException.cs" />
Expand Down
1 change: 1 addition & 0 deletions SharpSnmpLib/SharpSnmpLib.iOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<Compile Include="Messaging\ResponseMessage.cs" />
<Compile Include="Messaging\SetRequestMessage.cs" />
<Compile Include="Messaging\SnmpMessageExtension.cs" />
<Compile Include="Messaging\SocketAsyncEventArgsFactory.cs" />
<Compile Include="Messaging\SocketAwaitable.cs" />
<Compile Include="Messaging\SocketExtension.cs" />
<Compile Include="Messaging\TimeoutException.cs" />
Expand Down

0 comments on commit c8cba7e

Please sign in to comment.