-> IPScanner added
-> PortScanner added
This commit is contained in:
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31911.196
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Networking", "Networking\Networking.csproj", "{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApp1", "WpfApp1\WpfApp1.csproj", "{89252909-F8E2-4BDB-8EA9-4DA1A329545C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -15,6 +17,10 @@ Global
|
||||
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
104
Networking/IPScannerLib/HiResTimer.cs
Normal file
104
Networking/IPScannerLib/HiResTimer.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace IPScanner
|
||||
{
|
||||
public class HiResTimer
|
||||
{
|
||||
private bool isPerfCounterSupported = false;
|
||||
private Int64 frequency = 0;
|
||||
|
||||
// Windows CE native library with QueryPerformanceCounter().
|
||||
private const string lib = "Kernel32.dll";
|
||||
[DllImport(lib)]
|
||||
private static extern int QueryPerformanceCounter(ref Int64 count);
|
||||
[DllImport(lib)]
|
||||
private static extern int QueryPerformanceFrequency(ref Int64 frequency);
|
||||
|
||||
public HiResTimer()
|
||||
{
|
||||
// Query the high-resolution timer only if it is supported.
|
||||
// A returned frequency of 1000 typically indicates that it is not
|
||||
// supported and is emulated by the OS using the same value that is
|
||||
// returned by Environment.TickCount.
|
||||
// A return value of 0 indicates that the performance counter is
|
||||
// not supported.
|
||||
int returnVal = QueryPerformanceFrequency(ref frequency);
|
||||
|
||||
if (returnVal != 0 && frequency != 1000)
|
||||
{
|
||||
// The performance counter is supported.
|
||||
isPerfCounterSupported = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The performance counter is not supported. Use
|
||||
// Environment.TickCount instead.
|
||||
frequency = 1000;
|
||||
}
|
||||
}
|
||||
|
||||
private Int64 Frequency
|
||||
{
|
||||
get
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
}
|
||||
|
||||
private Int64 Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (isPerfCounterSupported)
|
||||
{
|
||||
// Get the value here if the counter is supported.
|
||||
Int64 tickCount = 0;
|
||||
QueryPerformanceCounter(ref tickCount);
|
||||
return tickCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, use Environment.TickCount.
|
||||
return (Int64)Environment.TickCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Int64 start;
|
||||
private bool isRunning = false;
|
||||
private double elapsedMillisecondsAtTimeOfStop = 0;
|
||||
public double ElapsedMilliseconds
|
||||
{
|
||||
get
|
||||
{
|
||||
if (isRunning)
|
||||
{
|
||||
Int64 timeElapsedInTicks = Value - start;
|
||||
return (timeElapsedInTicks * 1000) / Frequency;
|
||||
}
|
||||
else
|
||||
return elapsedMillisecondsAtTimeOfStop;
|
||||
}
|
||||
}
|
||||
public void Start()
|
||||
{
|
||||
start = Value;
|
||||
isRunning = true;
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
if (!isRunning)
|
||||
return;
|
||||
elapsedMillisecondsAtTimeOfStop = ElapsedMilliseconds;
|
||||
isRunning = false;
|
||||
}
|
||||
public void Reset()
|
||||
{
|
||||
isRunning = false;
|
||||
elapsedMillisecondsAtTimeOfStop = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
185
Networking/IPScannerLib/HttpHelper.cs
Normal file
185
Networking/IPScannerLib/HttpHelper.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using System.Net.Configuration;
|
||||
|
||||
namespace IPScanner
|
||||
{
|
||||
public class HttpResponseData
|
||||
{
|
||||
public string data;
|
||||
public SortedList<string, string> headers;
|
||||
public string host;
|
||||
public HttpResponseData(string data, SortedList<string, string> headers, string host)
|
||||
{
|
||||
this.data = data;
|
||||
this.headers = headers;
|
||||
this.host = host;
|
||||
}
|
||||
public string GetHeaderValue(string key)
|
||||
{
|
||||
string val;
|
||||
if (headers.TryGetValue(key.ToLower(), out val))
|
||||
return val;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
internal static class HttpHelper
|
||||
{
|
||||
static HttpHelper()
|
||||
{
|
||||
ToggleAllowUnsafeHeaderParsing(true);
|
||||
}
|
||||
public static HttpResponseData GetHttpResponseData(string url)
|
||||
{
|
||||
SortedList<string, string> headers = new SortedList<string, string>();
|
||||
//return new HttpResponseData("", headers, url);
|
||||
byte[] data = GetData(url, headers);
|
||||
return new HttpResponseData(UTF8Encoding.UTF8.GetString(data), headers, url);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets data from a URL and returns it as a byte array.
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] GetData(string url, SortedList<string, string> headers = null, string user = "", string password = "", bool keepAlive = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (url.Contains(".80"))
|
||||
{
|
||||
Console.WriteLine(url);
|
||||
}
|
||||
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
|
||||
webRequest.Proxy = null;
|
||||
webRequest.KeepAlive = keepAlive;
|
||||
webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||
|
||||
if (!string.IsNullOrEmpty(user) || !string.IsNullOrEmpty(password))
|
||||
{
|
||||
string authInfo = user + ":" + password;
|
||||
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
|
||||
webRequest.Headers["Authorization"] = "Basic " + authInfo;
|
||||
}
|
||||
webRequest.Method = "GET";
|
||||
webRequest.Timeout = 5000;
|
||||
webRequest.AllowAutoRedirect = true;
|
||||
return GetResponse(webRequest, headers);
|
||||
}
|
||||
catch (ThreadAbortException ex) { throw ex; }
|
||||
catch (WebException ex)
|
||||
{
|
||||
if (ex.Message.StartsWith("The server committed a protocol violation"))
|
||||
return UTF8Encoding.UTF8.GetBytes(ex.Message);
|
||||
if (ex.Message == "The remote server returned an error: (404) Not Found." || ex.Message == "The remote server returned an error: (401) Unauthorized.")
|
||||
{
|
||||
|
||||
//if(ex.Response.ResponseUri.AbsolutePath == "/nocookies.html")
|
||||
try
|
||||
{
|
||||
return GetResponseData(ex.Response, headers);
|
||||
}
|
||||
catch (ThreadAbortException e) { throw e; }
|
||||
catch (Exception e)
|
||||
{
|
||||
if (url.Contains(".80"))
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
//else if (ex.Message == "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel." && url.StartsWith("http:"))
|
||||
//{
|
||||
// url = "https" + url.Substring(4);
|
||||
// return GetData(url, headers, user, password, keepAlive);
|
||||
//}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (url.Contains(".80"))
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
private static byte[] GetResponse(HttpWebRequest webRequest, SortedList<string, string> headers = null)
|
||||
{
|
||||
return GetResponseData((HttpWebResponse)webRequest.GetResponse(), headers);
|
||||
}
|
||||
|
||||
private static byte[] GetResponseData(WebResponse webResponseObj, SortedList<string, string> headers = null)
|
||||
{
|
||||
byte[] data;
|
||||
using (HttpWebResponse webResponse = (HttpWebResponse)webResponseObj)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
using (Stream responseStream = webResponse.GetResponseStream())
|
||||
{
|
||||
// Dump the response stream into the MemoryStream ms
|
||||
int bytesRead = 1;
|
||||
while (bytesRead > 0)
|
||||
{
|
||||
byte[] buffer = new byte[8000];
|
||||
bytesRead = responseStream.Read(buffer, 0, buffer.Length);
|
||||
if (bytesRead > 0)
|
||||
ms.Write(buffer, 0, bytesRead);
|
||||
}
|
||||
data = new byte[ms.Length];
|
||||
|
||||
// Dump the data into the byte array
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
ms.Read(data, 0, data.Length);
|
||||
responseStream.Close();
|
||||
|
||||
if (headers != null)
|
||||
foreach (string key in webResponse.Headers.AllKeys)
|
||||
headers[key.ToLower()] = webResponse.Headers[key];
|
||||
}
|
||||
}
|
||||
webResponse.Close();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable useUnsafeHeaderParsing.
|
||||
/// See http://o2platform.wordpress.com/2010/10/20/dealing-with-the-server-committed-a-protocol-violation-sectionresponsestatusline/
|
||||
/// </summary>
|
||||
/// <param name="enable"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ToggleAllowUnsafeHeaderParsing(bool enable)
|
||||
{
|
||||
//Get the assembly that contains the internal class
|
||||
Assembly assembly = Assembly.GetAssembly(typeof(SettingsSection));
|
||||
if (assembly != null)
|
||||
{
|
||||
//Use the assembly in order to get the internal type for the internal class
|
||||
Type settingsSectionType = assembly.GetType("System.Net.Configuration.SettingsSectionInternal");
|
||||
if (settingsSectionType != null)
|
||||
{
|
||||
//Use the internal static property to get an instance of the internal settings class.
|
||||
//If the static instance isn't created already invoking the property will create it for us.
|
||||
object anInstance = settingsSectionType.InvokeMember("Section", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { });
|
||||
if (anInstance != null)
|
||||
{
|
||||
//Locate the private bool field that tells the framework if unsafe header parsing is allowed
|
||||
FieldInfo aUseUnsafeHeaderParsing = settingsSectionType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (aUseUnsafeHeaderParsing != null)
|
||||
{
|
||||
aUseUnsafeHeaderParsing.SetValue(anInstance, enable);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Networking/IPScannerLib/IPRanges.cs
Normal file
53
Networking/IPScannerLib/IPRanges.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace IPScanner
|
||||
{
|
||||
public static class IPRanges
|
||||
{
|
||||
public static List<Tuple<IPAddress, IPAddress>> GetOperationalIPRanges()
|
||||
{
|
||||
List<Tuple<IPAddress, IPAddress>> ranges = new List<Tuple<IPAddress, IPAddress>>();
|
||||
|
||||
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
if (netInterface.OperationalStatus != OperationalStatus.Up)
|
||||
continue;
|
||||
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
|
||||
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
|
||||
{
|
||||
if (addr.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
ranges.Add(new Tuple<IPAddress, IPAddress>(GetLowestInRange(addr.Address, addr.IPv4Mask), GetHighestInRange(addr.Address, addr.IPv4Mask)));
|
||||
}
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
private static IPAddress GetLowestInRange(IPAddress address, IPAddress mask)
|
||||
{
|
||||
byte[] addressBytes = address.GetAddressBytes();
|
||||
byte[] maskBytes = mask.GetAddressBytes();
|
||||
if (addressBytes.Length != 4 || maskBytes.Length != 4)
|
||||
return IPAddress.None;
|
||||
byte[] lowest = new byte[4];
|
||||
for (var i = 0; i < 4; i++)
|
||||
lowest[i] = (byte)(addressBytes[i] & maskBytes[i]);
|
||||
return new IPAddress(lowest);
|
||||
}
|
||||
private static IPAddress GetHighestInRange(IPAddress address, IPAddress mask)
|
||||
{
|
||||
byte[] addressBytes = address.GetAddressBytes();
|
||||
byte[] maskBytes = mask.GetAddressBytes();
|
||||
if (addressBytes.Length != 4 || maskBytes.Length != 4)
|
||||
return IPAddress.None;
|
||||
byte[] highest = new byte[4];
|
||||
for (var i = 0; i < 4; i++)
|
||||
highest[i] = (byte)((addressBytes[i] & maskBytes[i]) | ~maskBytes[i]);
|
||||
return new IPAddress(highest);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Networking/IPScannerLib/IPScanResult.cs
Normal file
29
Networking/IPScannerLib/IPScanResult.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
namespace IPScanner
|
||||
{
|
||||
public class IPScanResult
|
||||
{
|
||||
public IPAddress ip;
|
||||
public int ping = -1;
|
||||
public string host;
|
||||
public ScanStatus status = ScanStatus.Initializing;
|
||||
public string identification = "...";
|
||||
public HttpResponseData response;
|
||||
|
||||
public IPScanResult(IPAddress ip)
|
||||
{
|
||||
this.ip = ip;
|
||||
}
|
||||
//public IPScanResult(IPAddress ip, int ping, string host)
|
||||
//{
|
||||
// this.ip = ip;
|
||||
// this.ping = ping;
|
||||
// this.host = host;
|
||||
// this.status = ScanStatus.Complete;
|
||||
//}
|
||||
}
|
||||
}
|
||||
238
Networking/IPScannerLib/NetworkScanner.cs
Normal file
238
Networking/IPScannerLib/NetworkScanner.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Amib.Threading;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace IPScanner
|
||||
{
|
||||
public class NetworkScanner
|
||||
{
|
||||
private static Regex rxHtmlTitle = new Regex("<title>([^<]+?)</title>", RegexOptions.Compiled);
|
||||
SmartThreadPool Pool = new SmartThreadPool(1000, 256, 0);
|
||||
public NetworkScanner()
|
||||
{
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
System.Net.ServicePointManager.MaxServicePoints = int.MaxValue;
|
||||
}
|
||||
|
||||
public List<IPScanResult> BeginScan(IPAddress ipFrom, IPAddress ipTo)
|
||||
{
|
||||
Amib.Threading.Action<IPAddress, List<IPScanResult>, int> ipScanAction = new Amib.Threading.Action<IPAddress, List<IPScanResult>, int>(ScanIPAsync);
|
||||
// Count the IP addresses included in this range
|
||||
byte[] addyEnd = ipTo.GetAddressBytes();
|
||||
byte[] addyNext = ipFrom.GetAddressBytes();
|
||||
|
||||
List<IPScanResult> Results = new List<IPScanResult>();
|
||||
while (CompareIPs(addyNext, addyEnd) < 1)
|
||||
{
|
||||
Results.Add(new IPScanResult(new IPAddress(addyNext)));
|
||||
IncrementIP(addyNext);
|
||||
}
|
||||
|
||||
for (int i = 0; i < Results.Count; i++)
|
||||
Pool.QueueWorkItem(ipScanAction, Results[i].ip, Results, i);
|
||||
return Results;
|
||||
}
|
||||
private void ScanIPAsync(IPAddress ip, List<IPScanResult> results, int listIndex)
|
||||
{
|
||||
bool foundHost = false;
|
||||
results[listIndex].status = ScanStatus.Initializing;
|
||||
|
||||
// Attempt Ordinary Ping
|
||||
try
|
||||
{
|
||||
using (Ping p = new Ping())
|
||||
{
|
||||
PingReply pingReply = p.Send(ip, 5000);
|
||||
if (pingReply.Status == IPStatus.Success)
|
||||
{
|
||||
foundHost = true;
|
||||
results[listIndex].status = ScanStatus.Partial;
|
||||
results[listIndex].ping = (int)pingReply.RoundtripTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
// Attempt DNS Lookup
|
||||
try
|
||||
{
|
||||
Stopwatch timer = new Stopwatch();
|
||||
timer.Start();
|
||||
IPHostEntry ipe = Dns.GetHostEntry(ip);
|
||||
timer.Stop();
|
||||
int dnsLookupTime = (int)timer.ElapsedMilliseconds;
|
||||
|
||||
foundHost = true;
|
||||
//if (results[listIndex].ping < 0 || dnsLookupTime < results[listIndex].ping)
|
||||
// results[listIndex].ping = dnsLookupTime;
|
||||
results[listIndex].host = ipe.HostName.ToString();
|
||||
results[listIndex].status = ScanStatus.Complete;
|
||||
}
|
||||
//catch (SocketException ex)
|
||||
//{
|
||||
// //if (ex.SocketErrorCode == SocketError.HostNotFound)
|
||||
// // return;
|
||||
// Console.WriteLine(ex.Message);
|
||||
//}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (foundHost)
|
||||
{
|
||||
// Try to identify
|
||||
HttpResponseData response;
|
||||
results[listIndex].identification = IdentifyHost(ip, out response);
|
||||
results[listIndex].status = ScanStatus.Complete;
|
||||
results[listIndex].response = response;
|
||||
}
|
||||
else
|
||||
results[listIndex].status = ScanStatus.NotFound;
|
||||
}
|
||||
|
||||
private string IdentifyHost(IPAddress ip, out HttpResponseData response)
|
||||
{
|
||||
response = null;
|
||||
Stopwatch sw = new Stopwatch();
|
||||
try
|
||||
{
|
||||
sw.Start();
|
||||
response = HttpHelper.GetHttpResponseData("http://" + ip.ToString() + "/");
|
||||
if (response.GetHeaderValue("server").StartsWith("lighttpd") && response.GetHeaderValue("set-cookie").Contains("AIROS_") && response.data.Contains("<title>Error 404"))
|
||||
return "Ubiquiti";
|
||||
else if (response.GetHeaderValue("server").StartsWith("Boa") && response.data.Contains("<OBJECT ID=\"TSConfigIPCCtrl\""))
|
||||
return "Generic IP Cam"; // CCDCam EC-IP5911
|
||||
else if (response.data.Contains("flow_slct = get_slctid('flowtype');"))
|
||||
return "IPS Cam";
|
||||
else if (response.GetHeaderValue("server") == "GoAhead-Webs" && response.data.Contains("document.location = '/live.asp?"))
|
||||
return "Edimax Cam";
|
||||
else if (response.GetHeaderValue("server").StartsWith("App-webs/") && response.data.Contains("window.location.href = \"doc/page/login.asp"))
|
||||
return "Hikvision";
|
||||
else if (response.data.Contains("src=\"jsCore/LAB.js\"") || response.data.Contains("var lt = \"?WebVersion=") || response.data.Contains("src=\"jsCore/rpcCore.js"))
|
||||
return "Dahua";
|
||||
else if (response.GetHeaderValue("www-authenticate").Contains("realm=\"tomato\""))
|
||||
return "Tomato";
|
||||
else if (response.GetHeaderValue("server") == "Web Server" && response.data.Contains("<TITLE>NETGEAR FS728TP</TITLE>"))
|
||||
return "Netgear FS728TP";
|
||||
else if (response.GetHeaderValue("set-cookie").Contains("DLILPC=") && response.data.Contains("<title>Power Controller"))
|
||||
return "Web Power Switch";
|
||||
else if (response.data == "The server committed a protocol violation. Section=ResponseStatusLine")
|
||||
return "? WeatherDirect ?";
|
||||
else if (response.data == "The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF")
|
||||
return "? Web Power Switch ?";
|
||||
else if (response.data.Contains("NetDAQ ND-100"))
|
||||
return "NetDAQ ND-100";
|
||||
else if (response.GetHeaderValue("server") == "nginx" && response.data.Contains("<title>airVision:"))
|
||||
return "AirVision NVR";
|
||||
else if (response.GetHeaderValue("server") == "nginx" && response.data.Contains("<title>airVision:"))
|
||||
return "AirVision NVR";
|
||||
else if (response.GetHeaderValue("server").StartsWith("BlueIris-"))
|
||||
return "Blue Iris";
|
||||
//else if (response.data.Contains("<title>iTach"))
|
||||
// return "iTach";
|
||||
else if (response.data.Contains("href=\"/cmh\""))
|
||||
return "Vera";
|
||||
else if (response.data.Contains("WDMyCloud"))
|
||||
return "WDMyCloud";
|
||||
//else if (response.data.Contains("<title>DD-WRT"))
|
||||
// return "DD-WRT";
|
||||
else if (response.data.Contains("= \"Peplink\""))
|
||||
return "Peplink";
|
||||
else if (response.data.Contains("GSViewerX.ocx"))
|
||||
return "GrandStream";
|
||||
else if (response.data.Contains("content=\"Canon Inc.\""))
|
||||
return "Canon printer";
|
||||
else if (response.GetHeaderValue("server") == "tsbox" && response.GetHeaderValue("www-authenticate") == "Basic realm=\"pbox\"")
|
||||
return "HDMI Encoder";
|
||||
else if (response.data.Contains("Rules of login password.\\n"))
|
||||
return "ACTi";
|
||||
else if (response.data.Contains("/static/freenas_favicon.ico"))
|
||||
return "FreeNAS";
|
||||
else if (response.data.Contains("CONTENT=\"0;url=cgi-bin/kvm.cgi\""))
|
||||
return "Avocent KVM";
|
||||
else if (response.GetHeaderValue("www-authenticate") == "Basic realm=\"TomatoUSB\"")
|
||||
return "TomatoUSB Router";
|
||||
else if (response.GetHeaderValue("auther") == "Steven Wu" && response.GetHeaderValue("server") == "Camera Web Server/1.0" && response.data.Contains("location.href=\"top.htm?Currenttime=\"+timeValue;"))
|
||||
return "TrendNET IP cam";
|
||||
else if (response.data.Contains(@"<meta http-equiv=""refresh"" content=""0;URL='/ui'""/>"))
|
||||
return "ESXi";
|
||||
else if (response.GetHeaderValue("server") == "Microsoft-HTTPAPI/2.0")
|
||||
return "IIS";
|
||||
else
|
||||
{
|
||||
Match m = rxHtmlTitle.Match(response.data);
|
||||
if (m.Success)
|
||||
return m.Groups[1].Value;
|
||||
string server = response.GetHeaderValue("server");
|
||||
if (!string.IsNullOrEmpty(server))
|
||||
return server;
|
||||
return "";
|
||||
}
|
||||
return response.data;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
sw.Stop();
|
||||
//Console.WriteLine("Spent " + sw.ElapsedMilliseconds + " on " + response.data.Length);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
Pool.Cancel(true);
|
||||
}
|
||||
bool ArraysMatch(Array a1, Array a2)
|
||||
{
|
||||
if (a1.Length != a2.Length)
|
||||
return false;
|
||||
for (int i = 0; i < a1.Length; i++)
|
||||
if (a1.GetValue(i) != a1.GetValue(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
int CompareIPs(byte[] ip1, byte[] ip2)
|
||||
{
|
||||
if (ip1 == null || ip1.Length != 4)
|
||||
return -1;
|
||||
if (ip2 == null || ip2.Length != 4)
|
||||
return 1;
|
||||
int comp = ip1[0].CompareTo(ip2[0]);
|
||||
if (comp == 0)
|
||||
comp = ip1[1].CompareTo(ip2[1]);
|
||||
if (comp == 0)
|
||||
comp = ip1[2].CompareTo(ip2[2]);
|
||||
if (comp == 0)
|
||||
comp = ip1[3].CompareTo(ip2[3]);
|
||||
return comp;
|
||||
}
|
||||
void IncrementIP(byte[] ip, int idx = 3)
|
||||
{
|
||||
if (ip == null || ip.Length != 4 || idx < 0)
|
||||
return;
|
||||
if (ip[idx] == 254)
|
||||
{
|
||||
ip[idx] = 1;
|
||||
IncrementIP(ip, idx - 1);
|
||||
}
|
||||
else
|
||||
ip[idx] = (byte)(ip[idx] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Networking/IPScannerLib/ScanStatus.cs
Normal file
15
Networking/IPScannerLib/ScanStatus.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace IPScanner
|
||||
{
|
||||
public enum ScanStatus
|
||||
{
|
||||
Initializing,
|
||||
Scanning,
|
||||
NotFound,
|
||||
Complete,
|
||||
Partial
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,13 @@
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="PTConverter.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\PTConverter.Plugin.1.0.2\lib\net472\PTConverter.Plugin.dll</HintPath>
|
||||
<HintPath>..\packages\PTConverter.Plugin.1.0.3\lib\net472\PTConverter.Plugin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
@@ -48,17 +51,71 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UIAutomationProvider" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="WindowsFormsIntegration" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="IPTool.cs" />
|
||||
<Compile Include="Networking.IPv4.xaml.cs">
|
||||
<DependentUpon>Networking.IPv4.xaml</DependentUpon>
|
||||
<Compile Include="IPScannerLib\HiResTimer.cs" />
|
||||
<Compile Include="IPScannerLib\HttpHelper.cs" />
|
||||
<Compile Include="IPScannerLib\IPRanges.cs" />
|
||||
<Compile Include="IPScannerLib\IPScanResult.cs" />
|
||||
<Compile Include="IPScannerLib\IPTool.cs" />
|
||||
<Compile Include="IPScannerLib\NetworkScanner.cs" />
|
||||
<Compile Include="IPScannerLib\ScanStatus.cs" />
|
||||
<Compile Include="Pages\IPScanner.xaml.cs">
|
||||
<DependentUpon>IPScanner.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\IPv4.xaml.cs">
|
||||
<DependentUpon>IPv4.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PortScanner.xaml.cs">
|
||||
<DependentUpon>PortScanner.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\WF_IPScanner.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Pages\WF_IPScanner.Designer.cs">
|
||||
<DependentUpon>WF_IPScanner.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="PluginInfo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SmartThreadPool\CallerThreadContext.cs" />
|
||||
<Compile Include="SmartThreadPool\CanceledWorkItemsGroup.cs" />
|
||||
<Compile Include="SmartThreadPool\EventWaitHandle.cs" />
|
||||
<Compile Include="SmartThreadPool\EventWaitHandleFactory.cs" />
|
||||
<Compile Include="SmartThreadPool\Exceptions.cs" />
|
||||
<Compile Include="SmartThreadPool\Interfaces.cs" />
|
||||
<Compile Include="SmartThreadPool\InternalInterfaces.cs" />
|
||||
<Compile Include="SmartThreadPool\PriorityQueue.cs" />
|
||||
<Compile Include="SmartThreadPool\SLExt.cs" />
|
||||
<Compile Include="SmartThreadPool\SmartThreadPool.cs" />
|
||||
<Compile Include="SmartThreadPool\SmartThreadPool.ThreadEntry.cs" />
|
||||
<Compile Include="SmartThreadPool\Stopwatch.cs" />
|
||||
<Compile Include="SmartThreadPool\STPEventWaitHandle.cs" />
|
||||
<Compile Include="SmartThreadPool\STPPerformanceCounter.cs" />
|
||||
<Compile Include="SmartThreadPool\STPStartInfo.cs" />
|
||||
<Compile Include="SmartThreadPool\SynchronizedDictionary.cs" />
|
||||
<Compile Include="SmartThreadPool\WIGStartInfo.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItem.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItem.WorkItemResult.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItemFactory.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItemInfo.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItemResultTWrapper.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItemsGroup.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItemsGroupBase.cs" />
|
||||
<Compile Include="SmartThreadPool\WorkItemsQueue.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="Networking.IPv4.xaml">
|
||||
<Page Include="Pages\IPScanner.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Pages\IPv4.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Pages\PortScanner.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@@ -69,5 +126,10 @@
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Pages\WF_IPScanner.resx">
|
||||
<DependentUpon>WF_IPScanner.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
12
Networking/Pages/IPScanner.xaml
Normal file
12
Networking/Pages/IPScanner.xaml
Normal file
@@ -0,0 +1,12 @@
|
||||
<UserControl x:Class="Networking.Pages.IPScanner"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Networking.Pages"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800" Background="White">
|
||||
<WindowsFormsHost HorizontalAlignment="Left" Height="450" VerticalAlignment="Top" Width="800">
|
||||
<local:WF_IPScanner/>
|
||||
</WindowsFormsHost>
|
||||
</UserControl>
|
||||
63
Networking/Pages/IPScanner.xaml.cs
Normal file
63
Networking/Pages/IPScanner.xaml.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using IPScanner;
|
||||
using PTConverter.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Networking.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für Networking.xaml
|
||||
/// </summary>
|
||||
public partial class IPScanner : UserControl, IPage
|
||||
{
|
||||
|
||||
public IPScanner()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string GetCategory() => "";
|
||||
|
||||
public UserControl GetPage() => new IPScanner();
|
||||
|
||||
public string GetUnderCategory() => "";
|
||||
|
||||
string IPtoString(byte[] array)
|
||||
{
|
||||
//
|
||||
// Concatenate all the elements into a StringBuilder.
|
||||
//
|
||||
StringBuilder strinbuilder = new StringBuilder();
|
||||
for (int i = 0; i < array.Count(); i++)
|
||||
{
|
||||
|
||||
strinbuilder.Append(array[i]);
|
||||
if (i != array.Count() - 1)
|
||||
strinbuilder.Append('.');
|
||||
}
|
||||
return strinbuilder.ToString();
|
||||
}
|
||||
|
||||
private string GetPingTime(IPScanResult result)
|
||||
{
|
||||
if (result.ping > -1)
|
||||
return result.ping + " ms";
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
<UserControl x:Class="Networking.Networking_IPv4"
|
||||
<UserControl x:Class="Networking.Pages.IPv4"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Networking"
|
||||
xmlns:local="clr-namespace:Networking.Pages"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800" Background="White">
|
||||
<Grid>
|
||||
@@ -15,37 +15,23 @@ using System.Windows.Shapes;
|
||||
using NetCalc;
|
||||
using PTConverter.Plugin;
|
||||
|
||||
namespace Networking
|
||||
namespace Networking.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für Networking.xaml
|
||||
/// </summary>
|
||||
public partial class Networking_IPv4 : UserControl, IPlugin, IPage
|
||||
public partial class IPv4 : UserControl, IPage
|
||||
{
|
||||
#region Declarations
|
||||
protected IPTool ip = null;
|
||||
protected bool fill = false; // lock events wenn updating
|
||||
protected bool isIP = false;
|
||||
|
||||
public string Author => "Kevin Krüger";
|
||||
|
||||
public string Company => "PeaceToke";
|
||||
|
||||
public string PluginName => "Networking";
|
||||
|
||||
public string Description => "Calculate networks very easy!";
|
||||
|
||||
public string Version => "1.0.0";
|
||||
|
||||
public string IconLink => "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.clipartmax.com%2Fpng%2Fmiddle%2F276-2769230_networking-deep-neural-network-icon.png&f=1&nofb=1";
|
||||
|
||||
public IPage Page => this;
|
||||
#endregion
|
||||
|
||||
private string _ipAddress = "0.0.0.0";
|
||||
private string IPAddress { get => tbIPAddressP1.Text + "." + tbIPAddressP2.Text + "." + tbIPAddressP3.Text + "." + tbIPAddressP4.Text; set => _ipAddress = value; }
|
||||
|
||||
public Networking_IPv4()
|
||||
public IPv4()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@@ -61,7 +47,7 @@ namespace Networking
|
||||
}
|
||||
public string GetCategory() => "Networking";
|
||||
public string GetUnderCategory() => "IPv4";
|
||||
public UserControl GetPage() => new Networking_IPv4();
|
||||
public UserControl GetPage() => new IPv4();
|
||||
|
||||
#region Methods Used
|
||||
protected void newIP()
|
||||
12
Networking/Pages/PortScanner.xaml
Normal file
12
Networking/Pages/PortScanner.xaml
Normal file
@@ -0,0 +1,12 @@
|
||||
<UserControl x:Class="Networking.Pages.PortScanner"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Networking.Pages"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800" Background="White">
|
||||
<Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
35
Networking/Pages/PortScanner.xaml.cs
Normal file
35
Networking/Pages/PortScanner.xaml.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using PTConverter.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Networking.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für Networking.xaml
|
||||
/// </summary>
|
||||
public partial class PortScanner : UserControl, IPage
|
||||
{
|
||||
public PortScanner()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string GetCategory() => "Networking";
|
||||
|
||||
public UserControl GetPage() => new PortScanner();
|
||||
|
||||
public string GetUnderCategory() => "PortScan";
|
||||
}
|
||||
}
|
||||
133
Networking/Pages/WF_IPScanner.Designer.cs
generated
Normal file
133
Networking/Pages/WF_IPScanner.Designer.cs
generated
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
namespace Networking.Pages
|
||||
{
|
||||
partial class WF_IPScanner
|
||||
{
|
||||
/// <summary>
|
||||
/// Erforderliche Designervariable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Verwendete Ressourcen bereinigen.
|
||||
/// </summary>
|
||||
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Vom Komponenten-Designer generierter Code
|
||||
|
||||
/// <summary>
|
||||
/// Erforderliche Methode für die Designerunterstützung.
|
||||
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.lvIPList = new System.Windows.Forms.ListView();
|
||||
this.chIP = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.chPing = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.chHost = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.chRecognized = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.btnScan = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.tbIPRange = new System.Windows.Forms.TextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lvIPList
|
||||
//
|
||||
this.lvIPList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.lvIPList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.chIP,
|
||||
this.chPing,
|
||||
this.chHost,
|
||||
this.chRecognized});
|
||||
this.lvIPList.FullRowSelect = true;
|
||||
this.lvIPList.HideSelection = false;
|
||||
this.lvIPList.Location = new System.Drawing.Point(12, 87);
|
||||
this.lvIPList.MultiSelect = false;
|
||||
this.lvIPList.Name = "lvIPList";
|
||||
this.lvIPList.Size = new System.Drawing.Size(714, 282);
|
||||
this.lvIPList.TabIndex = 1;
|
||||
this.lvIPList.UseCompatibleStateImageBehavior = false;
|
||||
this.lvIPList.View = System.Windows.Forms.View.Details;
|
||||
//
|
||||
// chIP
|
||||
//
|
||||
this.chIP.Text = "IP";
|
||||
this.chIP.Width = 93;
|
||||
//
|
||||
// chPing
|
||||
//
|
||||
this.chPing.Text = "Ping";
|
||||
//
|
||||
// chHost
|
||||
//
|
||||
this.chHost.Text = "Host";
|
||||
this.chHost.Width = 88;
|
||||
//
|
||||
// chRecognized
|
||||
//
|
||||
this.chRecognized.Text = "Recognized as";
|
||||
this.chRecognized.Width = 119;
|
||||
//
|
||||
// btnScan
|
||||
//
|
||||
this.btnScan.Location = new System.Drawing.Point(323, 58);
|
||||
this.btnScan.Name = "btnScan";
|
||||
this.btnScan.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnScan.TabIndex = 7;
|
||||
this.btnScan.Text = "Scan";
|
||||
this.btnScan.UseVisualStyleBackColor = true;
|
||||
this.btnScan.Click += new System.EventHandler(this.btnScan_Click);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(9, 64);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(50, 13);
|
||||
this.label1.TabIndex = 6;
|
||||
this.label1.Text = "IP range:";
|
||||
//
|
||||
// tbIPRange
|
||||
//
|
||||
this.tbIPRange.Location = new System.Drawing.Point(66, 61);
|
||||
this.tbIPRange.Name = "tbIPRange";
|
||||
this.tbIPRange.Size = new System.Drawing.Size(251, 20);
|
||||
this.tbIPRange.TabIndex = 8;
|
||||
//
|
||||
// WF_IPScanner
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tbIPRange);
|
||||
this.Controls.Add(this.btnScan);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.lvIPList);
|
||||
this.Name = "WF_IPScanner";
|
||||
this.Size = new System.Drawing.Size(800, 450);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ListView lvIPList;
|
||||
private System.Windows.Forms.ColumnHeader chIP;
|
||||
private System.Windows.Forms.ColumnHeader chPing;
|
||||
private System.Windows.Forms.ColumnHeader chHost;
|
||||
private System.Windows.Forms.ColumnHeader chRecognized;
|
||||
private System.Windows.Forms.Button btnScan;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox tbIPRange;
|
||||
}
|
||||
}
|
||||
109
Networking/Pages/WF_IPScanner.cs
Normal file
109
Networking/Pages/WF_IPScanner.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using IPScanner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Networking.Pages
|
||||
{
|
||||
public partial class WF_IPScanner : UserControl
|
||||
{
|
||||
NetworkScanner scanner = new NetworkScanner();
|
||||
Timer timer = new Timer();
|
||||
List<IPScanResult> results;
|
||||
public WF_IPScanner()
|
||||
{
|
||||
InitializeComponent();
|
||||
List<Tuple<IPAddress, IPAddress>> ipRanges = IPRanges.GetOperationalIPRanges();
|
||||
if (ipRanges.Count > 0)
|
||||
{
|
||||
//tbIPRange.Text = ipRanges[0].Item1.GetAddressBytes().ToString();
|
||||
tbIPRange.Text = IPtoString(ipRanges[0].Item1.GetAddressBytes()) + "-" + ipRanges[0].Item2.GetAddressBytes()[3].ToString();
|
||||
// ipTo.IPAddress = ipRanges[0].Item2;
|
||||
}
|
||||
}
|
||||
|
||||
string IPtoString(byte[] array)
|
||||
{
|
||||
//
|
||||
// Concatenate all the elements into a StringBuilder.
|
||||
//
|
||||
StringBuilder strinbuilder = new StringBuilder();
|
||||
for (int i = 0; i < array.Count(); i++)
|
||||
{
|
||||
|
||||
strinbuilder.Append(array[i]);
|
||||
if (i != array.Count() - 1)
|
||||
strinbuilder.Append('.');
|
||||
}
|
||||
return strinbuilder.ToString();
|
||||
}
|
||||
|
||||
private string GetPingTime(IPScanResult result)
|
||||
{
|
||||
if (result.ping > -1)
|
||||
return result.ping + " ms";
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
private void PopulateListView()
|
||||
{
|
||||
bool itemModified = false;
|
||||
for (int i = 0; i < results.Count; i++)
|
||||
{
|
||||
IPScanResult result = results[i];
|
||||
if (result.status == ScanStatus.Complete || result.status == ScanStatus.Partial)
|
||||
{
|
||||
string ip = result.ip.ToString();
|
||||
ListViewItem[] matchedItems = lvIPList.Items.Find(ip, false);
|
||||
if (matchedItems.Length > 0)
|
||||
{
|
||||
matchedItems[0].Tag = result.response;
|
||||
matchedItems[0].SubItems[0].Text = result.ip.ToString();
|
||||
matchedItems[0].SubItems[1].Text = GetPingTime(result);
|
||||
matchedItems[0].SubItems[2].Text = result.host;
|
||||
matchedItems[0].SubItems[3].Text = result.identification;
|
||||
}
|
||||
else
|
||||
{
|
||||
ListViewItem lvi = new ListViewItem(new string[] { result.ip.ToString(), GetPingTime(result), result.host, result.identification });
|
||||
lvi.Name = ip;
|
||||
lvIPList.Items.Add(lvi);
|
||||
}
|
||||
itemModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
PopulateListView();
|
||||
}
|
||||
|
||||
private void btnScan_Click(object sender, EventArgs e)
|
||||
{
|
||||
timer.Stop();
|
||||
lvIPList.Items.Clear();
|
||||
|
||||
IPAddress ipFrom = IPAddress.Parse(tbIPRange.Text.Split(new Char[] { '-' })[0]);
|
||||
|
||||
IPAddress ipTo = IPAddress.Parse(ipFrom.GetAddressBytes()[0] + "." +
|
||||
ipFrom.GetAddressBytes()[1] + "." +
|
||||
ipFrom.GetAddressBytes()[2] + "." +
|
||||
byte.Parse(tbIPRange.Text.Split(new Char[] { '-' })[1].ToString()));
|
||||
results = scanner.BeginScan(ipFrom, ipTo);
|
||||
timer.Interval = 1000;
|
||||
timer.Tick += timer_Tick;
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Networking/Pages/WF_IPScanner.resx
Normal file
120
Networking/Pages/WF_IPScanner.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
32
Networking/PluginInfo.cs
Normal file
32
Networking/PluginInfo.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Networking.Pages;
|
||||
using PTConverter.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Networking
|
||||
{
|
||||
public class PluginInfo : IPlugin
|
||||
{
|
||||
public string Author => "Kevin Krüger";
|
||||
|
||||
public string Company => "";
|
||||
|
||||
public string PluginName => "Networking";
|
||||
|
||||
public string Description => "This Plugin provides Network features.";
|
||||
|
||||
public string Version => "1.0.0";
|
||||
|
||||
public string IconLink => null;
|
||||
|
||||
public IEnumerable<IPage> RegisterPages => new List<IPage>()
|
||||
{
|
||||
{new IPv4() },
|
||||
{new PortScanner() },
|
||||
{new Pages.IPScanner() }
|
||||
};
|
||||
}
|
||||
}
|
||||
138
Networking/SmartThreadPool/CallerThreadContext.cs
Normal file
138
Networking/SmartThreadPool/CallerThreadContext.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
#region CallerThreadContext class
|
||||
|
||||
/// <summary>
|
||||
/// This class stores the caller call context in order to restore
|
||||
/// it when the work item is executed in the thread pool environment.
|
||||
/// </summary>
|
||||
internal class CallerThreadContext
|
||||
{
|
||||
#region Prepare reflection information
|
||||
|
||||
// Cached type information.
|
||||
private static readonly MethodInfo getLogicalCallContextMethodInfo =
|
||||
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
private static readonly MethodInfo setLogicalCallContextMethodInfo =
|
||||
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
private static string HttpContextSlotName = GetHttpContextSlotName();
|
||||
|
||||
private static string GetHttpContextSlotName()
|
||||
{
|
||||
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
if (fi != null)
|
||||
{
|
||||
return (string) fi.GetValue(null);
|
||||
}
|
||||
|
||||
return "HttpContext";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private fields
|
||||
|
||||
private HttpContext _httpContext;
|
||||
private LogicalCallContext _callContext;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
private CallerThreadContext()
|
||||
{
|
||||
}
|
||||
|
||||
public bool CapturedCallContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return (null != _callContext);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CapturedHttpContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return (null != _httpContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Captures the current thread context
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static CallerThreadContext Capture(
|
||||
bool captureCallContext,
|
||||
bool captureHttpContext)
|
||||
{
|
||||
Debug.Assert(captureCallContext || captureHttpContext);
|
||||
|
||||
CallerThreadContext callerThreadContext = new CallerThreadContext();
|
||||
|
||||
// TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
|
||||
// Capture Call Context
|
||||
if(captureCallContext && (getLogicalCallContextMethodInfo != null))
|
||||
{
|
||||
callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
|
||||
if (callerThreadContext._callContext != null)
|
||||
{
|
||||
callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
// Capture httpContext
|
||||
if (captureHttpContext && (null != HttpContext.Current))
|
||||
{
|
||||
callerThreadContext._httpContext = HttpContext.Current;
|
||||
}
|
||||
|
||||
return callerThreadContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the thread context stored earlier
|
||||
/// </summary>
|
||||
/// <param name="callerThreadContext"></param>
|
||||
public static void Apply(CallerThreadContext callerThreadContext)
|
||||
{
|
||||
if (null == callerThreadContext)
|
||||
{
|
||||
throw new ArgumentNullException("callerThreadContext");
|
||||
}
|
||||
|
||||
// Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
|
||||
// Restore call context
|
||||
if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
|
||||
{
|
||||
setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
|
||||
}
|
||||
|
||||
// Restore HttpContext
|
||||
if (callerThreadContext._httpContext != null)
|
||||
{
|
||||
HttpContext.Current = callerThreadContext._httpContext;
|
||||
//CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
14
Networking/SmartThreadPool/CanceledWorkItemsGroup.cs
Normal file
14
Networking/SmartThreadPool/CanceledWorkItemsGroup.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
internal class CanceledWorkItemsGroup
|
||||
{
|
||||
public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||
|
||||
public CanceledWorkItemsGroup()
|
||||
{
|
||||
IsCanceled = false;
|
||||
}
|
||||
|
||||
public bool IsCanceled { get; set; }
|
||||
}
|
||||
}
|
||||
104
Networking/SmartThreadPool/EventWaitHandle.cs
Normal file
104
Networking/SmartThreadPool/EventWaitHandle.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
#if (_WINDOWS_CE)
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// EventWaitHandle class
|
||||
/// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation.
|
||||
/// So I wrote this class to implement these two methods with some of their overloads.
|
||||
/// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny.
|
||||
/// Note that this class doesn't even inherit from WaitHandle!
|
||||
/// </summary>
|
||||
public class STPEventWaitHandle
|
||||
{
|
||||
#region Public Constants
|
||||
|
||||
public const int WaitTimeout = Timeout.Infinite;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private External Constants
|
||||
|
||||
private const Int32 WAIT_FAILED = -1;
|
||||
private const Int32 WAIT_TIMEOUT = 0x102;
|
||||
private const UInt32 INFINITE = 0xFFFFFFFF;
|
||||
|
||||
#endregion
|
||||
|
||||
#region WaitAll and WaitAny
|
||||
|
||||
internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return waitHandle.WaitOne(millisecondsTimeout, exitContext);
|
||||
}
|
||||
|
||||
private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles)
|
||||
{
|
||||
IntPtr[] nativeHandles = new IntPtr[waitHandles.Length];
|
||||
for (int i = 0; i < waitHandles.Length; i++)
|
||||
{
|
||||
nativeHandles[i] = waitHandles[i].Handle;
|
||||
}
|
||||
return nativeHandles;
|
||||
}
|
||||
|
||||
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
|
||||
|
||||
IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
|
||||
|
||||
int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout);
|
||||
|
||||
if (result == WAIT_TIMEOUT || result == WAIT_FAILED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
|
||||
|
||||
IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
|
||||
|
||||
int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout);
|
||||
|
||||
if (result >= 0 && result < waitHandles.Length)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int WaitAny(WaitHandle[] waitHandles)
|
||||
{
|
||||
return WaitAny(waitHandles, Timeout.Infinite, false);
|
||||
}
|
||||
|
||||
public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
|
||||
{
|
||||
int millisecondsTimeout = (int)timeout.TotalMilliseconds;
|
||||
|
||||
return WaitAny(waitHandles, millisecondsTimeout, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region External methods
|
||||
|
||||
[DllImport("coredll.dll", SetLastError = true)]
|
||||
public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
#endif
|
||||
82
Networking/SmartThreadPool/EventWaitHandleFactory.cs
Normal file
82
Networking/SmartThreadPool/EventWaitHandleFactory.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.Threading;
|
||||
|
||||
#if (_WINDOWS_CE)
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// EventWaitHandleFactory class.
|
||||
/// This is a static class that creates AutoResetEvent and ManualResetEvent objects.
|
||||
/// In WindowCE the WaitForMultipleObjects API fails to use the Handle property
|
||||
/// of XxxResetEvent. It can use only handles that were created by the CreateEvent API.
|
||||
/// Consequently this class creates the needed XxxResetEvent and replaces the handle if
|
||||
/// it's a WindowsCE OS.
|
||||
/// </summary>
|
||||
public static class EventWaitHandleFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new AutoResetEvent object
|
||||
/// </summary>
|
||||
/// <returns>Return a new AutoResetEvent object</returns>
|
||||
public static AutoResetEvent CreateAutoResetEvent()
|
||||
{
|
||||
AutoResetEvent waitHandle = new AutoResetEvent(false);
|
||||
|
||||
#if (_WINDOWS_CE)
|
||||
ReplaceEventHandle(waitHandle, false, false);
|
||||
#endif
|
||||
|
||||
return waitHandle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new ManualResetEvent object
|
||||
/// </summary>
|
||||
/// <returns>Return a new ManualResetEvent object</returns>
|
||||
public static ManualResetEvent CreateManualResetEvent(bool initialState)
|
||||
{
|
||||
ManualResetEvent waitHandle = new ManualResetEvent(initialState);
|
||||
|
||||
#if (_WINDOWS_CE)
|
||||
ReplaceEventHandle(waitHandle, true, initialState);
|
||||
#endif
|
||||
|
||||
return waitHandle;
|
||||
}
|
||||
|
||||
#if (_WINDOWS_CE)
|
||||
|
||||
/// <summary>
|
||||
/// Replace the event handle
|
||||
/// </summary>
|
||||
/// <param name="waitHandle">The WaitHandle object which its handle needs to be replaced.</param>
|
||||
/// <param name="manualReset">Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)</param>
|
||||
/// <param name="initialState">The initial state of the event</param>
|
||||
private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState)
|
||||
{
|
||||
// Store the old handle
|
||||
IntPtr oldHandle = waitHandle.Handle;
|
||||
|
||||
// Create a new event
|
||||
IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null);
|
||||
|
||||
// Replace the old event with the new event
|
||||
waitHandle.Handle = newHandle;
|
||||
|
||||
// Close the old event
|
||||
CloseHandle (oldHandle);
|
||||
}
|
||||
|
||||
[DllImport("coredll.dll", SetLastError = true)]
|
||||
public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
|
||||
|
||||
//Handle
|
||||
[DllImport("coredll.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
144
Networking/SmartThreadPool/Exceptions.cs
Normal file
144
Networking/SmartThreadPool/Exceptions.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
#if !(_WINDOWS_CE)
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
#region Exceptions
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
||||
/// </summary>
|
||||
public sealed partial class WorkItemCancelException : Exception
|
||||
{
|
||||
public WorkItemCancelException()
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemCancelException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemCancelException(string message, Exception e)
|
||||
: base(message, e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||
/// </summary>
|
||||
public sealed partial class WorkItemTimeoutException : Exception
|
||||
{
|
||||
public WorkItemTimeoutException()
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemTimeoutException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemTimeoutException(string message, Exception e)
|
||||
: base(message, e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||
/// </summary>
|
||||
public sealed partial class WorkItemResultException : Exception
|
||||
{
|
||||
public WorkItemResultException()
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemResultException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemResultException(string message, Exception e)
|
||||
: base(message, e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception in case the STP queue is full and work item cannot be queued.
|
||||
/// Relevant when the STP has a queue size limit
|
||||
/// </summary>
|
||||
public sealed partial class QueueRejectedException : Exception
|
||||
{
|
||||
public QueueRejectedException()
|
||||
{
|
||||
}
|
||||
|
||||
public QueueRejectedException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public QueueRejectedException(string message, Exception e)
|
||||
: base(message, e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
/// <summary>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed partial class WorkItemCancelException
|
||||
{
|
||||
public WorkItemCancelException(SerializationInfo si, StreamingContext sc)
|
||||
: base(si, sc)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed partial class WorkItemTimeoutException
|
||||
{
|
||||
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc)
|
||||
: base(si, sc)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed partial class WorkItemResultException
|
||||
{
|
||||
public WorkItemResultException(SerializationInfo si, StreamingContext sc)
|
||||
: base(si, sc)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed partial class QueueRejectedException
|
||||
{
|
||||
public QueueRejectedException(SerializationInfo si, StreamingContext sc)
|
||||
: base(si, sc)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
603
Networking/SmartThreadPool/Interfaces.cs
Normal file
603
Networking/SmartThreadPool/Interfaces.cs
Normal file
@@ -0,0 +1,603 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
#region Delegates
|
||||
|
||||
/// <summary>
|
||||
/// A delegate that represents the method to run as the work item
|
||||
/// </summary>
|
||||
/// <param name="state">A state object for the method to run</param>
|
||||
public delegate object WorkItemCallback(object state);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to call after the WorkItemCallback completed
|
||||
/// </summary>
|
||||
/// <param name="wir">The work item result object</param>
|
||||
public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to call after the WorkItemCallback completed
|
||||
/// </summary>
|
||||
/// <param name="wir">The work item result object</param>
|
||||
public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to call when a WorkItemsGroup becomes idle
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
|
||||
public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to call after a thread is created, but before
|
||||
/// it's first use.
|
||||
/// </summary>
|
||||
public delegate void ThreadInitializationHandler();
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to call when a thread is about to exit, after
|
||||
/// it is no longer belong to the pool.
|
||||
/// </summary>
|
||||
public delegate void ThreadTerminationHandler();
|
||||
|
||||
#endregion
|
||||
|
||||
#region WorkItem Priority
|
||||
|
||||
/// <summary>
|
||||
/// Defines the availeable priorities of a work item.
|
||||
/// The higher the priority a work item has, the sooner
|
||||
/// it will be executed.
|
||||
/// </summary>
|
||||
public enum WorkItemPriority
|
||||
{
|
||||
Lowest,
|
||||
BelowNormal,
|
||||
Normal,
|
||||
AboveNormal,
|
||||
Highest,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWorkItemsGroup interface
|
||||
|
||||
/// <summary>
|
||||
/// IWorkItemsGroup interface
|
||||
/// Created by SmartThreadPool.CreateWorkItemsGroup()
|
||||
/// </summary>
|
||||
public interface IWorkItemsGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// Get/Set the name of the WorkItemsGroup
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
|
||||
/// </summary>
|
||||
int Concurrency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of work items waiting in the queue.
|
||||
/// </summary>
|
||||
int WaitingCallbacks { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of currently executing work items
|
||||
/// </summary>
|
||||
int InUseThreads { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get an array with all the state objects of the currently running items.
|
||||
/// The array represents a snap shot and impact performance.
|
||||
/// </summary>
|
||||
object[] GetStates();
|
||||
|
||||
/// <summary>
|
||||
/// Get the WorkItemsGroup start information
|
||||
/// </summary>
|
||||
WIGStartInfo WIGStartInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Starts to execute work items
|
||||
/// </summary>
|
||||
void Start();
|
||||
|
||||
/// <summary>
|
||||
/// Cancel all the work items.
|
||||
/// Same as Cancel(false)
|
||||
/// </summary>
|
||||
void Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Cancel all work items using thread abortion
|
||||
/// </summary>
|
||||
/// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
|
||||
void Cancel(bool abortExecution);
|
||||
|
||||
/// <summary>
|
||||
/// Wait for all work item to complete.
|
||||
/// </summary>
|
||||
void WaitForIdle();
|
||||
|
||||
/// <summary>
|
||||
/// Wait for all work item to complete, until timeout expired
|
||||
/// </summary>
|
||||
/// <param name="timeout">How long to wait for the work items to complete</param>
|
||||
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
|
||||
bool WaitForIdle(TimeSpan timeout);
|
||||
|
||||
/// <summary>
|
||||
/// Wait for all work item to complete, until timeout expired
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param>
|
||||
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
|
||||
bool WaitForIdle(int millisecondsTimeout);
|
||||
|
||||
/// <summary>
|
||||
/// IsIdle is true when there are no work items running or queued.
|
||||
/// </summary>
|
||||
bool IsIdle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This event is fired when all work items are completed.
|
||||
/// (When IsIdle changes to true)
|
||||
/// This event only work on WorkItemsGroup. On SmartThreadPool
|
||||
/// it throws the NotImplementedException.
|
||||
/// </summary>
|
||||
event WorkItemsGroupIdleHandler OnIdle;
|
||||
|
||||
#region QueueWorkItem
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="workItemPriority">The priority of the work item</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="workItemInfo">Work item info</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="workItemInfo">Work item information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
|
||||
|
||||
#endregion
|
||||
|
||||
#region QueueWorkItem(Action<...>)
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||
IWorkItemResult QueueWorkItem(Action action, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||
IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||
IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||
IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||
IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
#endregion
|
||||
|
||||
#region QueueWorkItem(Func<...>)
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||
/// its GetResult() returns a TResult object</returns>
|
||||
IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||
/// its GetResult() returns a TResult object</returns>
|
||||
IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||
/// its GetResult() returns a TResult object</returns>
|
||||
IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||
/// its GetResult() returns a TResult object</returns>
|
||||
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||
/// its GetResult() returns a TResult object</returns>
|
||||
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CallToPostExecute enumerator
|
||||
|
||||
[Flags]
|
||||
public enum CallToPostExecute
|
||||
{
|
||||
/// <summary>
|
||||
/// Never call to the PostExecute call back
|
||||
/// </summary>
|
||||
Never = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Call to the PostExecute only when the work item is cancelled
|
||||
/// </summary>
|
||||
WhenWorkItemCanceled = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Call to the PostExecute only when the work item is not cancelled
|
||||
/// </summary>
|
||||
WhenWorkItemNotCanceled = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Always call to the PostExecute
|
||||
/// </summary>
|
||||
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWorkItemResult interface
|
||||
|
||||
/// <summary>
|
||||
/// The common interface of IWorkItemResult and IWorkItemResult<T>
|
||||
/// </summary>
|
||||
public interface IWaitableResult
|
||||
{
|
||||
/// <summary>
|
||||
/// This method intent is for internal use.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IWorkItemResult GetWorkItemResult();
|
||||
|
||||
/// <summary>
|
||||
/// This method intent is for internal use.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IWorkItemResult<TResult> GetWorkItemResultT<TResult>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IWorkItemResult interface.
|
||||
/// Created when a WorkItemCallback work item is queued.
|
||||
/// </summary>
|
||||
public interface IWorkItemResult : IWorkItemResult<object>
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IWorkItemResult<TResult> interface.
|
||||
/// Created when a Func<TResult> work item is queued.
|
||||
/// </summary>
|
||||
public interface IWorkItemResult<TResult> : IWaitableResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits.
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
TResult GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout.
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout.
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
|
||||
/// <param name="exitContext">
|
||||
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||
/// </param>
|
||||
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits.
|
||||
/// </summary>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
TResult GetResult(out Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout.
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <param name="exitContext"></param>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
out Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout.
|
||||
/// </summary>
|
||||
/// <param name="exitContext"></param>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext,
|
||||
out Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
|
||||
/// <param name="exitContext">
|
||||
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||
/// </param>
|
||||
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle,
|
||||
out Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// <param name="cancelWaitHandle"></param>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="exitContext"></param>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle,
|
||||
out Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication whether the asynchronous operation has completed.
|
||||
/// </summary>
|
||||
bool IsCompleted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication whether the asynchronous operation has been canceled.
|
||||
/// </summary>
|
||||
bool IsCanceled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user-defined object that contains context data
|
||||
/// for the work item method.
|
||||
/// </summary>
|
||||
object State { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Same as Cancel(false).
|
||||
/// </summary>
|
||||
bool Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Cancel the work item execution.
|
||||
/// If the work item is in the queue then it won't execute
|
||||
/// If the work item is completed, it will remain completed
|
||||
/// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled
|
||||
/// property to check if the work item has been cancelled. If the abortExecution is set to true then
|
||||
/// the Smart Thread Pool will send an AbortException to the running thread to stop the execution
|
||||
/// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException.
|
||||
/// If the work item is already cancelled it will remain cancelled
|
||||
/// </summary>
|
||||
/// <param name="abortExecution">When true send an AbortException to the executing thread.</param>
|
||||
/// <returns>Returns true if the work item was not completed, otherwise false.</returns>
|
||||
bool Cancel(bool abortExecution);
|
||||
|
||||
/// <summary>
|
||||
/// Get the work item's priority
|
||||
/// </summary>
|
||||
WorkItemPriority WorkItemPriority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the result, same as GetResult()
|
||||
/// </summary>
|
||||
TResult Result { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the exception if occured otherwise returns null.
|
||||
/// </summary>
|
||||
object Exception { get; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region .NET 3.5
|
||||
|
||||
// All these delegate are built-in .NET 3.5
|
||||
// Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity.
|
||||
|
||||
public delegate void Action();
|
||||
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
|
||||
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
|
||||
public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
|
||||
|
||||
public delegate TResult Func<TResult>();
|
||||
public delegate TResult Func<T, TResult>(T arg1);
|
||||
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
|
||||
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
|
||||
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
|
||||
|
||||
#endregion
|
||||
}
|
||||
27
Networking/SmartThreadPool/InternalInterfaces.cs
Normal file
27
Networking/SmartThreadPool/InternalInterfaces.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// An internal delegate to call when the WorkItem starts or completes
|
||||
/// </summary>
|
||||
internal delegate void WorkItemStateCallback(WorkItem workItem);
|
||||
|
||||
internal interface IInternalWorkItemResult
|
||||
{
|
||||
event WorkItemStateCallback OnWorkItemStarted;
|
||||
event WorkItemStateCallback OnWorkItemCompleted;
|
||||
}
|
||||
|
||||
internal interface IInternalWaitableResult
|
||||
{
|
||||
/// <summary>
|
||||
/// This method is intent for internal use.
|
||||
/// </summary>
|
||||
IWorkItemResult GetWorkItemResult();
|
||||
}
|
||||
|
||||
public interface IHasWorkItemPriority
|
||||
{
|
||||
WorkItemPriority WorkItemPriority { get; }
|
||||
}
|
||||
}
|
||||
239
Networking/SmartThreadPool/PriorityQueue.cs
Normal file
239
Networking/SmartThreadPool/PriorityQueue.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
#region PriorityQueue class
|
||||
|
||||
/// <summary>
|
||||
/// PriorityQueue class
|
||||
/// This class is not thread safe because we use external lock
|
||||
/// </summary>
|
||||
public sealed class PriorityQueue : IEnumerable
|
||||
{
|
||||
#region Private members
|
||||
|
||||
/// <summary>
|
||||
/// The number of queues, there is one for each type of priority
|
||||
/// </summary>
|
||||
private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
|
||||
|
||||
/// <summary>
|
||||
/// Work items queues. There is one for each type of priority
|
||||
/// </summary>
|
||||
private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
|
||||
|
||||
/// <summary>
|
||||
/// The total number of work items within the queues
|
||||
/// </summary>
|
||||
private int _workItemsCount;
|
||||
|
||||
/// <summary>
|
||||
/// Use with IEnumerable interface
|
||||
/// </summary>
|
||||
private int _version;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contructor
|
||||
|
||||
public PriorityQueue()
|
||||
{
|
||||
for(int i = 0; i < _queues.Length; ++i)
|
||||
{
|
||||
_queues[i] = new LinkedList<IHasWorkItemPriority>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue a work item.
|
||||
/// </summary>
|
||||
/// <param name="workItem">A work item</param>
|
||||
public void Enqueue(IHasWorkItemPriority workItem)
|
||||
{
|
||||
Debug.Assert(null != workItem);
|
||||
|
||||
int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
|
||||
Debug.Assert(queueIndex >= 0);
|
||||
Debug.Assert(queueIndex < _queuesCount);
|
||||
|
||||
_queues[queueIndex].AddLast(workItem);
|
||||
++_workItemsCount;
|
||||
++_version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dequeque a work item.
|
||||
/// </summary>
|
||||
/// <returns>Returns the next work item</returns>
|
||||
public IHasWorkItemPriority Dequeue()
|
||||
{
|
||||
IHasWorkItemPriority workItem = null;
|
||||
|
||||
if(_workItemsCount > 0)
|
||||
{
|
||||
int queueIndex = GetNextNonEmptyQueue(-1);
|
||||
Debug.Assert(queueIndex >= 0);
|
||||
workItem = _queues[queueIndex].First.Value;
|
||||
_queues[queueIndex].RemoveFirst();
|
||||
Debug.Assert(null != workItem);
|
||||
--_workItemsCount;
|
||||
++_version;
|
||||
}
|
||||
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next non empty queue starting at queue queueIndex+1
|
||||
/// </summary>
|
||||
/// <param name="queueIndex">The index-1 to start from</param>
|
||||
/// <returns>
|
||||
/// The index of the next non empty queue or -1 if all the queues are empty
|
||||
/// </returns>
|
||||
private int GetNextNonEmptyQueue(int queueIndex)
|
||||
{
|
||||
for(int i = queueIndex+1; i < _queuesCount; ++i)
|
||||
{
|
||||
if(_queues[i].Count > 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of work items
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItemsCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all the work items
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
if (_workItemsCount > 0)
|
||||
{
|
||||
foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
|
||||
{
|
||||
queue.Clear();
|
||||
}
|
||||
_workItemsCount = 0;
|
||||
++_version;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable Members
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator to iterate over the work items
|
||||
/// </summary>
|
||||
/// <returns>Returns an enumerator</returns>
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return new PriorityQueueEnumerator(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PriorityQueueEnumerator
|
||||
|
||||
/// <summary>
|
||||
/// The class the implements the enumerator
|
||||
/// </summary>
|
||||
private class PriorityQueueEnumerator : IEnumerator
|
||||
{
|
||||
private readonly PriorityQueue _priorityQueue;
|
||||
private int _version;
|
||||
private int _queueIndex;
|
||||
private IEnumerator _enumerator;
|
||||
|
||||
public PriorityQueueEnumerator(PriorityQueue priorityQueue)
|
||||
{
|
||||
_priorityQueue = priorityQueue;
|
||||
_version = _priorityQueue._version;
|
||||
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
|
||||
if (_queueIndex >= 0)
|
||||
{
|
||||
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
_enumerator = null;
|
||||
}
|
||||
}
|
||||
|
||||
#region IEnumerator Members
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_version = _priorityQueue._version;
|
||||
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
|
||||
if (_queueIndex >= 0)
|
||||
{
|
||||
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
_enumerator = null;
|
||||
}
|
||||
}
|
||||
|
||||
public object Current
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(null != _enumerator);
|
||||
return _enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (null == _enumerator)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(_version != _priorityQueue._version)
|
||||
{
|
||||
throw new InvalidOperationException("The collection has been modified");
|
||||
|
||||
}
|
||||
if (!_enumerator.MoveNext())
|
||||
{
|
||||
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
|
||||
if(-1 == _queueIndex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
|
||||
_enumerator.MoveNext();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
16
Networking/SmartThreadPool/SLExt.cs
Normal file
16
Networking/SmartThreadPool/SLExt.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
#if _SILVERLIGHT
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
public enum ThreadPriority
|
||||
{
|
||||
Lowest,
|
||||
BelowNormal,
|
||||
Normal,
|
||||
AboveNormal,
|
||||
Highest,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
62
Networking/SmartThreadPool/STPEventWaitHandle.cs
Normal file
62
Networking/SmartThreadPool/STPEventWaitHandle.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
#if !(_WINDOWS_CE)
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
#if _SILVERLIGHT || WINDOWS_PHONE
|
||||
internal static class STPEventWaitHandle
|
||||
{
|
||||
public const int WaitTimeout = Timeout.Infinite;
|
||||
|
||||
internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return WaitHandle.WaitAll(waitHandles, millisecondsTimeout);
|
||||
}
|
||||
|
||||
internal static int WaitAny(WaitHandle[] waitHandles)
|
||||
{
|
||||
return WaitHandle.WaitAny(waitHandles);
|
||||
}
|
||||
|
||||
internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return WaitHandle.WaitAny(waitHandles, millisecondsTimeout);
|
||||
}
|
||||
|
||||
internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return waitHandle.WaitOne(millisecondsTimeout);
|
||||
}
|
||||
}
|
||||
#else
|
||||
internal static class STPEventWaitHandle
|
||||
{
|
||||
public const int WaitTimeout = Timeout.Infinite;
|
||||
|
||||
internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
|
||||
}
|
||||
|
||||
internal static int WaitAny(WaitHandle[] waitHandles)
|
||||
{
|
||||
return WaitHandle.WaitAny(waitHandles);
|
||||
}
|
||||
|
||||
internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
|
||||
}
|
||||
|
||||
internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return waitHandle.WaitOne(millisecondsTimeout, exitContext);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
448
Networking/SmartThreadPool/STPPerformanceCounter.cs
Normal file
448
Networking/SmartThreadPool/STPPerformanceCounter.cs
Normal file
@@ -0,0 +1,448 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
public interface ISTPPerformanceCountersReader
|
||||
{
|
||||
long InUseThreads { get; }
|
||||
long ActiveThreads { get; }
|
||||
long WorkItemsQueued { get; }
|
||||
long WorkItemsProcessed { get; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
internal interface ISTPInstancePerformanceCounters : IDisposable
|
||||
{
|
||||
void Close();
|
||||
void SampleThreads(long activeThreads, long inUseThreads);
|
||||
void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
|
||||
void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
|
||||
void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
|
||||
}
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
|
||||
internal enum STPPerformanceCounterType
|
||||
{
|
||||
// Fields
|
||||
ActiveThreads = 0,
|
||||
InUseThreads = 1,
|
||||
OverheadThreads = 2,
|
||||
OverheadThreadsPercent = 3,
|
||||
OverheadThreadsPercentBase = 4,
|
||||
|
||||
WorkItems = 5,
|
||||
WorkItemsInQueue = 6,
|
||||
WorkItemsProcessed = 7,
|
||||
|
||||
WorkItemsQueuedPerSecond = 8,
|
||||
WorkItemsProcessedPerSecond = 9,
|
||||
|
||||
AvgWorkItemWaitTime = 10,
|
||||
AvgWorkItemWaitTimeBase = 11,
|
||||
|
||||
AvgWorkItemProcessTime = 12,
|
||||
AvgWorkItemProcessTimeBase = 13,
|
||||
|
||||
WorkItemsGroups = 14,
|
||||
|
||||
LastCounter = 14,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Summary description for STPPerformanceCounter.
|
||||
/// </summary>
|
||||
internal class STPPerformanceCounter
|
||||
{
|
||||
// Fields
|
||||
private readonly PerformanceCounterType _pcType;
|
||||
protected string _counterHelp;
|
||||
protected string _counterName;
|
||||
|
||||
// Methods
|
||||
public STPPerformanceCounter(
|
||||
string counterName,
|
||||
string counterHelp,
|
||||
PerformanceCounterType pcType)
|
||||
{
|
||||
_counterName = counterName;
|
||||
_counterHelp = counterHelp;
|
||||
_pcType = pcType;
|
||||
}
|
||||
|
||||
public void AddCounterToCollection(CounterCreationDataCollection counterData)
|
||||
{
|
||||
CounterCreationData counterCreationData = new CounterCreationData(
|
||||
_counterName,
|
||||
_counterHelp,
|
||||
_pcType);
|
||||
|
||||
counterData.Add(counterCreationData);
|
||||
}
|
||||
|
||||
// Properties
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _counterName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class STPPerformanceCounters
|
||||
{
|
||||
// Fields
|
||||
internal STPPerformanceCounter[] _stpPerformanceCounters;
|
||||
private static readonly STPPerformanceCounters _instance;
|
||||
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
|
||||
internal const string _stpCategoryName = "SmartThreadPool";
|
||||
|
||||
// Methods
|
||||
static STPPerformanceCounters()
|
||||
{
|
||||
_instance = new STPPerformanceCounters();
|
||||
}
|
||||
|
||||
private STPPerformanceCounters()
|
||||
{
|
||||
STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[]
|
||||
{
|
||||
new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32),
|
||||
new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32),
|
||||
new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32),
|
||||
new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction),
|
||||
new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase),
|
||||
|
||||
new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32),
|
||||
new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32),
|
||||
new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32),
|
||||
|
||||
new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32),
|
||||
new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32),
|
||||
|
||||
new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64),
|
||||
new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase),
|
||||
|
||||
new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64),
|
||||
new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase),
|
||||
|
||||
new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32),
|
||||
};
|
||||
|
||||
_stpPerformanceCounters = stpPerformanceCounters;
|
||||
SetupCategory();
|
||||
}
|
||||
|
||||
private void SetupCategory()
|
||||
{
|
||||
if (!PerformanceCounterCategory.Exists(_stpCategoryName))
|
||||
{
|
||||
CounterCreationDataCollection counters = new CounterCreationDataCollection();
|
||||
|
||||
for (int i = 0; i < _stpPerformanceCounters.Length; i++)
|
||||
{
|
||||
_stpPerformanceCounters[i].AddCounterToCollection(counters);
|
||||
}
|
||||
|
||||
PerformanceCounterCategory.Create(
|
||||
_stpCategoryName,
|
||||
_stpCategoryHelp,
|
||||
PerformanceCounterCategoryType.MultiInstance,
|
||||
counters);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Properties
|
||||
public static STPPerformanceCounters Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class STPInstancePerformanceCounter : IDisposable
|
||||
{
|
||||
// Fields
|
||||
private bool _isDisposed;
|
||||
private PerformanceCounter _pcs;
|
||||
|
||||
// Methods
|
||||
protected STPInstancePerformanceCounter()
|
||||
{
|
||||
_isDisposed = false;
|
||||
}
|
||||
|
||||
public STPInstancePerformanceCounter(
|
||||
string instance,
|
||||
STPPerformanceCounterType spcType) : this()
|
||||
{
|
||||
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
|
||||
_pcs = new PerformanceCounter(
|
||||
STPPerformanceCounters._stpCategoryName,
|
||||
counters._stpPerformanceCounters[(int) spcType].Name,
|
||||
instance,
|
||||
false);
|
||||
_pcs.RawValue = _pcs.RawValue;
|
||||
}
|
||||
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_pcs != null)
|
||||
{
|
||||
_pcs.RemoveInstance();
|
||||
_pcs.Close();
|
||||
_pcs = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
public virtual void Increment()
|
||||
{
|
||||
_pcs.Increment();
|
||||
}
|
||||
|
||||
public virtual void IncrementBy(long val)
|
||||
{
|
||||
_pcs.IncrementBy(val);
|
||||
}
|
||||
|
||||
public virtual void Set(long val)
|
||||
{
|
||||
_pcs.RawValue = val;
|
||||
}
|
||||
}
|
||||
|
||||
internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
|
||||
{
|
||||
// Methods
|
||||
public override void Increment() {}
|
||||
public override void IncrementBy(long value) {}
|
||||
public override void Set(long val) {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters
|
||||
{
|
||||
private bool _isDisposed;
|
||||
// Fields
|
||||
private STPInstancePerformanceCounter[] _pcs;
|
||||
private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
|
||||
|
||||
// Methods
|
||||
static STPInstancePerformanceCounters()
|
||||
{
|
||||
_stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter();
|
||||
}
|
||||
|
||||
public STPInstancePerformanceCounters(string instance)
|
||||
{
|
||||
_isDisposed = false;
|
||||
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
|
||||
|
||||
// Call the STPPerformanceCounters.Instance so the static constructor will
|
||||
// intialize the STPPerformanceCounters singleton.
|
||||
STPPerformanceCounters.Instance.GetHashCode();
|
||||
|
||||
for (int i = 0; i < _pcs.Length; i++)
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
_pcs[i] = new STPInstancePerformanceCounter(
|
||||
instance,
|
||||
(STPPerformanceCounterType) i);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pcs[i] = _stpInstanceNullPerformanceCounter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (null != _pcs)
|
||||
{
|
||||
for (int i = 0; i < _pcs.Length; i++)
|
||||
{
|
||||
if (null != _pcs[i])
|
||||
{
|
||||
_pcs[i].Dispose();
|
||||
}
|
||||
}
|
||||
_pcs = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
|
||||
{
|
||||
return _pcs[(int) spcType];
|
||||
}
|
||||
|
||||
public void SampleThreads(long activeThreads, long inUseThreads)
|
||||
{
|
||||
GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads);
|
||||
GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads);
|
||||
GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
|
||||
|
||||
GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
|
||||
GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
|
||||
}
|
||||
|
||||
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
|
||||
{
|
||||
GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed);
|
||||
GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued);
|
||||
GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
|
||||
|
||||
GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
|
||||
GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
|
||||
}
|
||||
|
||||
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
|
||||
{
|
||||
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds);
|
||||
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
|
||||
}
|
||||
|
||||
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
|
||||
{
|
||||
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds);
|
||||
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
|
||||
{
|
||||
private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters();
|
||||
|
||||
public static NullSTPInstancePerformanceCounters Instance
|
||||
{
|
||||
get { return _instance; }
|
||||
}
|
||||
|
||||
public void Close() {}
|
||||
public void Dispose() {}
|
||||
|
||||
public void SampleThreads(long activeThreads, long inUseThreads) {}
|
||||
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
|
||||
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
|
||||
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
|
||||
public long InUseThreads
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public long ActiveThreads
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public long WorkItemsQueued
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public long WorkItemsProcessed
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
}
|
||||
|
||||
internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
|
||||
{
|
||||
public void Close() { }
|
||||
public void Dispose() { }
|
||||
|
||||
private long _activeThreads;
|
||||
private long _inUseThreads;
|
||||
private long _workItemsQueued;
|
||||
private long _workItemsProcessed;
|
||||
|
||||
public long InUseThreads
|
||||
{
|
||||
get { return _inUseThreads; }
|
||||
}
|
||||
|
||||
public long ActiveThreads
|
||||
{
|
||||
get { return _activeThreads; }
|
||||
}
|
||||
|
||||
public long WorkItemsQueued
|
||||
{
|
||||
get { return _workItemsQueued; }
|
||||
}
|
||||
|
||||
public long WorkItemsProcessed
|
||||
{
|
||||
get { return _workItemsProcessed; }
|
||||
}
|
||||
|
||||
public void SampleThreads(long activeThreads, long inUseThreads)
|
||||
{
|
||||
_activeThreads = activeThreads;
|
||||
_inUseThreads = inUseThreads;
|
||||
}
|
||||
|
||||
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
|
||||
{
|
||||
_workItemsQueued = workItemsQueued;
|
||||
_workItemsProcessed = workItemsProcessed;
|
||||
}
|
||||
|
||||
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
|
||||
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
}
|
||||
}
|
||||
235
Networking/SmartThreadPool/STPStartInfo.cs
Normal file
235
Networking/SmartThreadPool/STPStartInfo.cs
Normal file
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for STPStartInfo.
|
||||
/// </summary>
|
||||
public class STPStartInfo : WIGStartInfo
|
||||
{
|
||||
private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||
private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
||||
private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||
#if !(WINDOWS_PHONE)
|
||||
private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||
#endif
|
||||
private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||
private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground;
|
||||
private bool _enableLocalPerformanceCounters;
|
||||
private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
|
||||
private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize;
|
||||
private int? _maxQueueLength = SmartThreadPool.DefaultMaxQueueLength;
|
||||
|
||||
public STPStartInfo()
|
||||
{
|
||||
_performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||
#if !(WINDOWS_PHONE)
|
||||
_threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||
#endif
|
||||
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||
_idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||
_minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
||||
}
|
||||
|
||||
public STPStartInfo(STPStartInfo stpStartInfo)
|
||||
: base(stpStartInfo)
|
||||
{
|
||||
_idleTimeout = stpStartInfo.IdleTimeout;
|
||||
_minWorkerThreads = stpStartInfo.MinWorkerThreads;
|
||||
_maxWorkerThreads = stpStartInfo.MaxWorkerThreads;
|
||||
#if !(WINDOWS_PHONE)
|
||||
_threadPriority = stpStartInfo.ThreadPriority;
|
||||
#endif
|
||||
_performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName;
|
||||
_enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters;
|
||||
_threadPoolName = stpStartInfo._threadPoolName;
|
||||
_areThreadsBackground = stpStartInfo.AreThreadsBackground;
|
||||
_maxQueueLength = stpStartInfo.MaxQueueLength;
|
||||
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
_apartmentState = stpStartInfo._apartmentState;
|
||||
#endif
|
||||
_maxStackSize = stpStartInfo._maxStackSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the idle timeout in milliseconds.
|
||||
/// If a thread is idle (starved) longer than IdleTimeout then it may quit.
|
||||
/// </summary>
|
||||
public virtual int IdleTimeout
|
||||
{
|
||||
get { return _idleTimeout; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_idleTimeout = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the lower limit of threads in the pool.
|
||||
/// </summary>
|
||||
public virtual int MinWorkerThreads
|
||||
{
|
||||
get { return _minWorkerThreads; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_minWorkerThreads = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the upper limit of threads in the pool.
|
||||
/// </summary>
|
||||
public virtual int MaxWorkerThreads
|
||||
{
|
||||
get { return _maxWorkerThreads; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_maxWorkerThreads = value;
|
||||
}
|
||||
}
|
||||
|
||||
#if !(WINDOWS_PHONE)
|
||||
/// <summary>
|
||||
/// Get/Set the scheduling priority of the threads in the pool.
|
||||
/// The Os handles the scheduling.
|
||||
/// </summary>
|
||||
public virtual ThreadPriority ThreadPriority
|
||||
{
|
||||
get { return _threadPriority; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_threadPriority = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Get/Set the thread pool name. Threads will get names depending on this.
|
||||
/// </summary>
|
||||
public virtual string ThreadPoolName {
|
||||
get { return _threadPoolName; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly ();
|
||||
_threadPoolName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the performance counter instance name of this SmartThreadPool
|
||||
/// The default is null which indicate not to use performance counters at all.
|
||||
/// </summary>
|
||||
public virtual string PerformanceCounterInstanceName
|
||||
{
|
||||
get { return _performanceCounterInstanceName; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_performanceCounterInstanceName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable/Disable the local performance counter.
|
||||
/// This enables the user to get some performance information about the SmartThreadPool
|
||||
/// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.)
|
||||
/// The default is false.
|
||||
/// </summary>
|
||||
public virtual bool EnableLocalPerformanceCounters
|
||||
{
|
||||
get { return _enableLocalPerformanceCounters; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_enableLocalPerformanceCounters = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set backgroundness of thread in thread pool.
|
||||
/// </summary>
|
||||
public virtual bool AreThreadsBackground
|
||||
{
|
||||
get { return _areThreadsBackground; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly ();
|
||||
_areThreadsBackground = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of items allowed in the queue. Items attempting to be queued
|
||||
/// when the queue is at its maximum will throw a QueueRejectedException.
|
||||
///
|
||||
/// Value must be > 0. A <code>null</code> value will leave the queue unbounded (i.e.
|
||||
/// bounded only by available resources).
|
||||
///
|
||||
/// Ignored when <code>Enqueue()</code>ing on a Thread Pool from within a
|
||||
/// <code>WorkItemsGroup</code>.
|
||||
/// </summary>
|
||||
public virtual int? MaxQueueLength
|
||||
{
|
||||
get { return _maxQueueLength; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_maxQueueLength = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a readonly version of this STPStartInfo.
|
||||
/// </summary>
|
||||
/// <returns>Returns a readonly reference to this STPStartInfo</returns>
|
||||
public new STPStartInfo AsReadOnly()
|
||||
{
|
||||
return new STPStartInfo(this) { _readOnly = true };
|
||||
}
|
||||
|
||||
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
|
||||
private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState;
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the apartment state of threads in the thread pool
|
||||
/// </summary>
|
||||
public ApartmentState ApartmentState
|
||||
{
|
||||
get { return _apartmentState; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_apartmentState = value;
|
||||
}
|
||||
}
|
||||
|
||||
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the max stack size of threads in the thread pool
|
||||
/// </summary>
|
||||
public int? MaxStackSize
|
||||
{
|
||||
get { return _maxStackSize; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
if (value.HasValue && value.Value < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value", "Value must be greater than 0.");
|
||||
}
|
||||
_maxStackSize = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
60
Networking/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
Normal file
60
Networking/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
using System;
|
||||
using Amib.Threading.Internal;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
public partial class SmartThreadPool
|
||||
{
|
||||
#region ThreadEntry class
|
||||
|
||||
internal class ThreadEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The thread creation time
|
||||
/// The value is stored as UTC value.
|
||||
/// </summary>
|
||||
private readonly DateTime _creationTime;
|
||||
|
||||
/// <summary>
|
||||
/// The last time this thread has been running
|
||||
/// It is updated by IAmAlive() method
|
||||
/// The value is stored as UTC value.
|
||||
/// </summary>
|
||||
private DateTime _lastAliveTime;
|
||||
|
||||
/// <summary>
|
||||
/// A reference from each thread in the thread pool to its SmartThreadPool
|
||||
/// object container.
|
||||
/// With this variable a thread can know whatever it belongs to a
|
||||
/// SmartThreadPool.
|
||||
/// </summary>
|
||||
private readonly SmartThreadPool _associatedSmartThreadPool;
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the current work item a thread from the thread pool
|
||||
/// is executing.
|
||||
/// </summary>
|
||||
public WorkItem CurrentWorkItem { get; set; }
|
||||
|
||||
public ThreadEntry(SmartThreadPool stp)
|
||||
{
|
||||
_associatedSmartThreadPool = stp;
|
||||
_creationTime = DateTime.UtcNow;
|
||||
_lastAliveTime = DateTime.MinValue;
|
||||
}
|
||||
|
||||
public SmartThreadPool AssociatedSmartThreadPool
|
||||
{
|
||||
get { return _associatedSmartThreadPool; }
|
||||
}
|
||||
|
||||
public void IAmAlive()
|
||||
{
|
||||
_lastAliveTime = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1811
Networking/SmartThreadPool/SmartThreadPool.cs
Normal file
1811
Networking/SmartThreadPool/SmartThreadPool.cs
Normal file
File diff suppressed because it is too large
Load Diff
108
Networking/SmartThreadPool/Stopwatch.cs
Normal file
108
Networking/SmartThreadPool/Stopwatch.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Stopwatch class
|
||||
/// Used with WindowsCE and Silverlight which don't have Stopwatch
|
||||
/// </summary>
|
||||
internal class Stopwatch
|
||||
{
|
||||
private long _elapsed;
|
||||
private bool _isRunning;
|
||||
private long _startTimeStamp;
|
||||
|
||||
public Stopwatch()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
private long GetElapsedDateTimeTicks()
|
||||
{
|
||||
long rawElapsedTicks = GetRawElapsedTicks();
|
||||
return rawElapsedTicks;
|
||||
}
|
||||
|
||||
private long GetRawElapsedTicks()
|
||||
{
|
||||
long elapsed = _elapsed;
|
||||
if (_isRunning)
|
||||
{
|
||||
long ticks = GetTimestamp() - _startTimeStamp;
|
||||
elapsed += ticks;
|
||||
}
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
public static long GetTimestamp()
|
||||
{
|
||||
return DateTime.UtcNow.Ticks;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_elapsed = 0L;
|
||||
_isRunning = false;
|
||||
_startTimeStamp = 0L;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_startTimeStamp = GetTimestamp();
|
||||
_isRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static Stopwatch StartNew()
|
||||
{
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
return stopwatch;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_isRunning)
|
||||
{
|
||||
long ticks = GetTimestamp() - _startTimeStamp;
|
||||
_elapsed += ticks;
|
||||
_isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Properties
|
||||
public TimeSpan Elapsed
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TimeSpan(GetElapsedDateTimeTicks());
|
||||
}
|
||||
}
|
||||
|
||||
public long ElapsedMilliseconds
|
||||
{
|
||||
get
|
||||
{
|
||||
return (GetElapsedDateTimeTicks() / 0x2710L);
|
||||
}
|
||||
}
|
||||
|
||||
public long ElapsedTicks
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetRawElapsedTicks();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isRunning;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
Networking/SmartThreadPool/SynchronizedDictionary.cs
Normal file
89
Networking/SmartThreadPool/SynchronizedDictionary.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
internal class SynchronizedDictionary<TKey, TValue>
|
||||
{
|
||||
private readonly Dictionary<TKey, TValue> _dictionary;
|
||||
private readonly object _lock;
|
||||
|
||||
public SynchronizedDictionary()
|
||||
{
|
||||
_lock = new object();
|
||||
_dictionary = new Dictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _dictionary.Count; }
|
||||
}
|
||||
|
||||
public bool Contains(TKey key)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _dictionary.ContainsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(TKey key)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_dictionary.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public object SyncRoot
|
||||
{
|
||||
get { return _lock; }
|
||||
}
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _dictionary[key];
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_dictionary[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<TKey, TValue>.KeyCollection Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _dictionary.Keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<TKey, TValue>.ValueCollection Values
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _dictionary.Values;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_dictionary.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
171
Networking/SmartThreadPool/WIGStartInfo.cs
Normal file
171
Networking/SmartThreadPool/WIGStartInfo.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for WIGStartInfo.
|
||||
/// </summary>
|
||||
public class WIGStartInfo
|
||||
{
|
||||
private bool _useCallerCallContext;
|
||||
private bool _useCallerHttpContext;
|
||||
private bool _disposeOfStateObjects;
|
||||
private CallToPostExecute _callToPostExecute;
|
||||
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
|
||||
private bool _startSuspended;
|
||||
private WorkItemPriority _workItemPriority;
|
||||
private bool _fillStateWithArgs;
|
||||
|
||||
protected bool _readOnly;
|
||||
|
||||
public WIGStartInfo()
|
||||
{
|
||||
_fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
|
||||
_workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||
_startSuspended = SmartThreadPool.DefaultStartSuspended;
|
||||
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||
}
|
||||
|
||||
public WIGStartInfo(WIGStartInfo wigStartInfo)
|
||||
{
|
||||
_useCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
_useCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
_disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
_callToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
_postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||
_workItemPriority = wigStartInfo.WorkItemPriority;
|
||||
_startSuspended = wigStartInfo.StartSuspended;
|
||||
_fillStateWithArgs = wigStartInfo.FillStateWithArgs;
|
||||
}
|
||||
|
||||
protected void ThrowIfReadOnly()
|
||||
{
|
||||
if (_readOnly)
|
||||
{
|
||||
throw new NotSupportedException("This is a readonly instance and set is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set if to use the caller's security context
|
||||
/// </summary>
|
||||
public virtual bool UseCallerCallContext
|
||||
{
|
||||
get { return _useCallerCallContext; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_useCallerCallContext = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set if to use the caller's HTTP context
|
||||
/// </summary>
|
||||
public virtual bool UseCallerHttpContext
|
||||
{
|
||||
get { return _useCallerHttpContext; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_useCallerHttpContext = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set if to dispose of the state object of a work item
|
||||
/// </summary>
|
||||
public virtual bool DisposeOfStateObjects
|
||||
{
|
||||
get { return _disposeOfStateObjects; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_disposeOfStateObjects = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the run the post execute options
|
||||
/// </summary>
|
||||
public virtual CallToPostExecute CallToPostExecute
|
||||
{
|
||||
get { return _callToPostExecute; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_callToPostExecute = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the default post execute callback
|
||||
/// </summary>
|
||||
public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback
|
||||
{
|
||||
get { return _postExecuteWorkItemCallback; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_postExecuteWorkItemCallback = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set if the work items execution should be suspended until the Start()
|
||||
/// method is called.
|
||||
/// </summary>
|
||||
public virtual bool StartSuspended
|
||||
{
|
||||
get { return _startSuspended; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_startSuspended = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the default priority that a work item gets when it is enqueued
|
||||
/// </summary>
|
||||
public virtual WorkItemPriority WorkItemPriority
|
||||
{
|
||||
get { return _workItemPriority; }
|
||||
set { _workItemPriority = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the
|
||||
/// arguments as an object array into the state of the work item.
|
||||
/// The arguments can be access later by IWorkItemResult.State.
|
||||
/// </summary>
|
||||
public virtual bool FillStateWithArgs
|
||||
{
|
||||
get { return _fillStateWithArgs; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_fillStateWithArgs = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a readonly version of this WIGStartInfo
|
||||
/// </summary>
|
||||
/// <returns>Returns a readonly reference to this WIGStartInfoRO</returns>
|
||||
public WIGStartInfo AsReadOnly()
|
||||
{
|
||||
return new WIGStartInfo(this) { _readOnly = true };
|
||||
}
|
||||
}
|
||||
}
|
||||
190
Networking/SmartThreadPool/WorkItem.WorkItemResult.cs
Normal file
190
Networking/SmartThreadPool/WorkItem.WorkItemResult.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
public partial class WorkItem
|
||||
{
|
||||
#region WorkItemResult class
|
||||
|
||||
private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult
|
||||
{
|
||||
/// <summary>
|
||||
/// A back reference to the work item
|
||||
/// </summary>
|
||||
private readonly WorkItem _workItem;
|
||||
|
||||
public WorkItemResult(WorkItem workItem)
|
||||
{
|
||||
_workItem = workItem;
|
||||
}
|
||||
|
||||
internal WorkItem GetWorkItem()
|
||||
{
|
||||
return _workItem;
|
||||
}
|
||||
|
||||
#region IWorkItemResult Members
|
||||
|
||||
public bool IsCompleted
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItem.IsCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCanceled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItem.IsCanceled;
|
||||
}
|
||||
}
|
||||
|
||||
public object GetResult()
|
||||
{
|
||||
return _workItem.GetResult(Timeout.Infinite, true, null);
|
||||
}
|
||||
|
||||
public object GetResult(int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return _workItem.GetResult(millisecondsTimeout, exitContext, null);
|
||||
}
|
||||
|
||||
public object GetResult(TimeSpan timeout, bool exitContext)
|
||||
{
|
||||
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
|
||||
}
|
||||
|
||||
public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||
{
|
||||
return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
|
||||
}
|
||||
|
||||
public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||
{
|
||||
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
|
||||
}
|
||||
|
||||
public object GetResult(out Exception e)
|
||||
{
|
||||
return _workItem.GetResult(Timeout.Infinite, true, null, out e);
|
||||
}
|
||||
|
||||
public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
|
||||
{
|
||||
return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
|
||||
}
|
||||
|
||||
public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
|
||||
{
|
||||
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
|
||||
}
|
||||
|
||||
public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||
{
|
||||
return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
||||
}
|
||||
|
||||
public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||
{
|
||||
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
|
||||
}
|
||||
|
||||
public bool Cancel()
|
||||
{
|
||||
return Cancel(false);
|
||||
}
|
||||
|
||||
public bool Cancel(bool abortExecution)
|
||||
{
|
||||
return _workItem.Cancel(abortExecution);
|
||||
}
|
||||
|
||||
public object State
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItem._state;
|
||||
}
|
||||
}
|
||||
|
||||
public WorkItemPriority WorkItemPriority
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItem._workItemInfo.WorkItemPriority;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the result, same as GetResult()
|
||||
/// </summary>
|
||||
public object Result
|
||||
{
|
||||
get { return GetResult(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the exception if occured otherwise returns null.
|
||||
/// This value is valid only after the work item completed,
|
||||
/// before that it is always null.
|
||||
/// </summary>
|
||||
public object Exception
|
||||
{
|
||||
get { return _workItem._exception; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IInternalWorkItemResult Members
|
||||
|
||||
public event WorkItemStateCallback OnWorkItemStarted
|
||||
{
|
||||
add
|
||||
{
|
||||
_workItem.OnWorkItemStarted += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_workItem.OnWorkItemStarted -= value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public event WorkItemStateCallback OnWorkItemCompleted
|
||||
{
|
||||
add
|
||||
{
|
||||
_workItem.OnWorkItemCompleted += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_workItem.OnWorkItemCompleted -= value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IInternalWorkItemResult Members
|
||||
|
||||
public IWorkItemResult GetWorkItemResult()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public IWorkItemResult<TResult> GetWorkItemResultT<TResult>()
|
||||
{
|
||||
return new WorkItemResultTWrapper<TResult>(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
994
Networking/SmartThreadPool/WorkItem.cs
Normal file
994
Networking/SmartThreadPool/WorkItem.cs
Normal file
@@ -0,0 +1,994 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Amib.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds a callback delegate and the state for that delegate.
|
||||
/// </summary>
|
||||
public partial class WorkItem : IHasWorkItemPriority
|
||||
{
|
||||
#region WorkItemState enum
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the state of the work item in the thread pool
|
||||
/// </summary>
|
||||
private enum WorkItemState
|
||||
{
|
||||
InQueue = 0, // Nexts: InProgress, Canceled
|
||||
InProgress = 1, // Nexts: Completed, Canceled
|
||||
Completed = 2, // Stays Completed
|
||||
Canceled = 3, // Stays Canceled
|
||||
}
|
||||
|
||||
private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
switch (currentState)
|
||||
{
|
||||
case WorkItemState.InQueue:
|
||||
valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState);
|
||||
break;
|
||||
case WorkItemState.InProgress:
|
||||
valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState);
|
||||
break;
|
||||
case WorkItemState.Completed:
|
||||
case WorkItemState.Canceled:
|
||||
// Cannot be changed
|
||||
break;
|
||||
default:
|
||||
// Unknown state
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Callback delegate for the callback.
|
||||
/// </summary>
|
||||
private readonly WorkItemCallback _callback;
|
||||
|
||||
/// <summary>
|
||||
/// State with which to call the callback delegate.
|
||||
/// </summary>
|
||||
private object _state;
|
||||
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
/// <summary>
|
||||
/// Stores the caller's context
|
||||
/// </summary>
|
||||
private readonly CallerThreadContext _callerContext;
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Holds the result of the mehtod
|
||||
/// </summary>
|
||||
private object _result;
|
||||
|
||||
/// <summary>
|
||||
/// Hold the exception if the method threw it
|
||||
/// </summary>
|
||||
private Exception _exception;
|
||||
|
||||
/// <summary>
|
||||
/// Hold the state of the work item
|
||||
/// </summary>
|
||||
private WorkItemState _workItemState;
|
||||
|
||||
/// <summary>
|
||||
/// A ManualResetEvent to indicate that the result is ready
|
||||
/// </summary>
|
||||
private ManualResetEvent _workItemCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// A reference count to the _workItemCompleted.
|
||||
/// When it reaches to zero _workItemCompleted is Closed
|
||||
/// </summary>
|
||||
private int _workItemCompletedRefCount;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result state of the work item
|
||||
/// </summary>
|
||||
private readonly WorkItemResult _workItemResult;
|
||||
|
||||
/// <summary>
|
||||
/// Work item info
|
||||
/// </summary>
|
||||
private readonly WorkItemInfo _workItemInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the WorkItem starts
|
||||
/// </summary>
|
||||
private event WorkItemStateCallback _workItemStartedEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the WorkItem completes
|
||||
/// </summary>
|
||||
private event WorkItemStateCallback _workItemCompletedEvent;
|
||||
|
||||
/// <summary>
|
||||
/// A reference to an object that indicates whatever the
|
||||
/// WorkItemsGroup has been canceled
|
||||
/// </summary>
|
||||
private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
|
||||
|
||||
/// <summary>
|
||||
/// A reference to an object that indicates whatever the
|
||||
/// SmartThreadPool has been canceled
|
||||
/// </summary>
|
||||
private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
|
||||
|
||||
/// <summary>
|
||||
/// The work item group this work item belong to.
|
||||
/// </summary>
|
||||
private readonly IWorkItemsGroup _workItemsGroup;
|
||||
|
||||
/// <summary>
|
||||
/// The thread that executes this workitem.
|
||||
/// This field is available for the period when the work item is executed, before and after it is null.
|
||||
/// </summary>
|
||||
private Thread _executingThread;
|
||||
|
||||
/// <summary>
|
||||
/// The absulote time when the work item will be timeout
|
||||
/// </summary>
|
||||
private long _expirationTime;
|
||||
|
||||
#region Performance Counter fields
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stores how long the work item waited on the stp queue
|
||||
/// </summary>
|
||||
private Stopwatch _waitingOnQueueStopwatch;
|
||||
|
||||
/// <summary>
|
||||
/// Stores how much time it took the work item to execute after it went out of the queue
|
||||
/// </summary>
|
||||
private Stopwatch _processingStopwatch;
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public TimeSpan WaitingTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return _waitingOnQueueStopwatch.Elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan ProcessTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return _processingStopwatch.Elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
internal WorkItemInfo WorkItemInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItemInfo;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the callback holding object.
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The workItemGroup of the workitem</param>
|
||||
/// <param name="workItemInfo">The WorkItemInfo of te workitem</param>
|
||||
/// <param name="callback">Callback delegate for the callback.</param>
|
||||
/// <param name="state">State with which to call the callback delegate.</param>
|
||||
///
|
||||
/// We assume that the WorkItem object is created within the thread
|
||||
/// that meant to run the callback
|
||||
public WorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WorkItemInfo workItemInfo,
|
||||
WorkItemCallback callback,
|
||||
object state)
|
||||
{
|
||||
_workItemsGroup = workItemsGroup;
|
||||
_workItemInfo = workItemInfo;
|
||||
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
|
||||
{
|
||||
_callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
_callback = callback;
|
||||
_state = state;
|
||||
_workItemResult = new WorkItemResult(this);
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
// The _workItemState is changed directly instead of using the SetWorkItemState
|
||||
// method since we don't want to go throught IsValidStateTransition.
|
||||
_workItemState = WorkItemState.InQueue;
|
||||
|
||||
_workItemCompleted = null;
|
||||
_workItemCompletedRefCount = 0;
|
||||
_waitingOnQueueStopwatch = new Stopwatch();
|
||||
_processingStopwatch = new Stopwatch();
|
||||
_expirationTime =
|
||||
_workItemInfo.Timeout > 0 ?
|
||||
DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond :
|
||||
long.MaxValue;
|
||||
}
|
||||
|
||||
internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
|
||||
{
|
||||
return (workItemsGroup == _workItemsGroup);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
internal CanceledWorkItemsGroup CanceledWorkItemsGroup
|
||||
{
|
||||
get { return _canceledWorkItemsGroup; }
|
||||
set { _canceledWorkItemsGroup = value; }
|
||||
}
|
||||
|
||||
internal CanceledWorkItemsGroup CanceledSmartThreadPool
|
||||
{
|
||||
get { return _canceledSmartThreadPool; }
|
||||
set { _canceledSmartThreadPool = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the state of the work item to in progress if it wasn't canceled.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Return true on success or false in case the work item was canceled.
|
||||
/// If the work item needs to run a post execute then the method will return true.
|
||||
/// </returns>
|
||||
public bool StartingWorkItem()
|
||||
{
|
||||
_waitingOnQueueStopwatch.Stop();
|
||||
_processingStopwatch.Start();
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (IsCanceled)
|
||||
{
|
||||
bool result = false;
|
||||
if ((_workItemInfo.PostExecuteWorkItemCallback != null) &&
|
||||
((_workItemInfo.CallToPostExecute & CallToPostExecute.WhenWorkItemCanceled) == CallToPostExecute.WhenWorkItemCanceled))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
|
||||
|
||||
// No need for a lock yet, only after the state has changed to InProgress
|
||||
_executingThread = Thread.CurrentThread;
|
||||
|
||||
SetWorkItemState(WorkItemState.InProgress);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the work item and the post execute
|
||||
/// </summary>
|
||||
public void Execute()
|
||||
{
|
||||
CallToPostExecute currentCallToPostExecute = 0;
|
||||
|
||||
// Execute the work item if we are in the correct state
|
||||
switch (GetWorkItemState())
|
||||
{
|
||||
case WorkItemState.InProgress:
|
||||
currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled;
|
||||
ExecuteWorkItem();
|
||||
break;
|
||||
case WorkItemState.Canceled:
|
||||
currentCallToPostExecute |= CallToPostExecute.WhenWorkItemCanceled;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
// Run the post execute as needed
|
||||
if ((currentCallToPostExecute & _workItemInfo.CallToPostExecute) != 0)
|
||||
{
|
||||
PostExecute();
|
||||
}
|
||||
|
||||
_processingStopwatch.Stop();
|
||||
}
|
||||
|
||||
internal void FireWorkItemCompleted()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (null != _workItemCompletedEvent)
|
||||
{
|
||||
_workItemCompletedEvent(this);
|
||||
}
|
||||
}
|
||||
catch // Suppress exceptions
|
||||
{ }
|
||||
}
|
||||
|
||||
internal void FireWorkItemStarted()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (null != _workItemStartedEvent)
|
||||
{
|
||||
_workItemStartedEvent(this);
|
||||
}
|
||||
}
|
||||
catch // Suppress exceptions
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the work item
|
||||
/// </summary>
|
||||
private void ExecuteWorkItem()
|
||||
{
|
||||
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
CallerThreadContext ctc = null;
|
||||
if (null != _callerContext)
|
||||
{
|
||||
ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
|
||||
CallerThreadContext.Apply(_callerContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
Exception exception = null;
|
||||
object result = null;
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
result = _callback(_state);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Save the exception so we can rethrow it later
|
||||
exception = e;
|
||||
}
|
||||
|
||||
// Remove the value of the execution thread, so it will be impossible to cancel the work item,
|
||||
// since it is already completed.
|
||||
// Cancelling a work item that already completed may cause the abortion of the next work item!!!
|
||||
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||
|
||||
if (null == executionThread)
|
||||
{
|
||||
// Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException
|
||||
Thread.Sleep(60 * 1000);
|
||||
|
||||
// If after 1 minute this thread was not aborted then let it continue working.
|
||||
}
|
||||
}
|
||||
// We must treat the ThreadAbortException or else it will be stored in the exception variable
|
||||
catch (ThreadAbortException tae)
|
||||
{
|
||||
tae.GetHashCode();
|
||||
// Check if the work item was cancelled
|
||||
// If we got a ThreadAbortException and the STP is not shutting down, it means the
|
||||
// work items was cancelled.
|
||||
if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown)
|
||||
{
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
Thread.ResetAbort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
if (null != _callerContext)
|
||||
{
|
||||
CallerThreadContext.Apply(ctc);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!SmartThreadPool.IsWorkItemCanceled)
|
||||
{
|
||||
SetResult(result, exception);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the post execute callback
|
||||
/// </summary>
|
||||
private void PostExecute()
|
||||
{
|
||||
if (null != _workItemInfo.PostExecuteWorkItemCallback)
|
||||
{
|
||||
try
|
||||
{
|
||||
_workItemInfo.PostExecuteWorkItemCallback(_workItemResult);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Assert(null != e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the result of the work item to return
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the work item</param>
|
||||
/// <param name="exception">The exception that was throw while the workitem executed, null
|
||||
/// if there was no exception.</param>
|
||||
internal void SetResult(object result, Exception exception)
|
||||
{
|
||||
_result = result;
|
||||
_exception = exception;
|
||||
SignalComplete(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the work item result
|
||||
/// </summary>
|
||||
/// <returns>The work item result</returns>
|
||||
internal IWorkItemResult GetWorkItemResult()
|
||||
{
|
||||
return _workItemResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for all work items to complete
|
||||
/// </summary>
|
||||
/// <param name="waitableResults">Array of work item result objects</param>
|
||||
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
||||
/// <param name="exitContext">
|
||||
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||
/// </param>
|
||||
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
|
||||
/// <returns>
|
||||
/// true when every work item in waitableResults has completed; otherwise false.
|
||||
/// </returns>
|
||||
internal static bool WaitAll(
|
||||
IWaitableResult[] waitableResults,
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle)
|
||||
{
|
||||
if (0 == waitableResults.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool success;
|
||||
WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
|
||||
GetWaitHandles(waitableResults, waitHandles);
|
||||
|
||||
if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
|
||||
{
|
||||
success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = true;
|
||||
int millisecondsLeft = millisecondsTimeout;
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
|
||||
WaitHandle[] whs;
|
||||
if (null != cancelWaitHandle)
|
||||
{
|
||||
whs = new WaitHandle[] { null, cancelWaitHandle };
|
||||
}
|
||||
else
|
||||
{
|
||||
whs = new WaitHandle[] { null };
|
||||
}
|
||||
|
||||
bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
|
||||
// Iterate over the wait handles and wait for each one to complete.
|
||||
// We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
|
||||
// won't affect it.
|
||||
// Each iteration we update the time left for the timeout.
|
||||
for (int i = 0; i < waitableResults.Length; ++i)
|
||||
{
|
||||
// WaitAny don't work with negative numbers
|
||||
if (!waitInfinitely && (millisecondsLeft < 0))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
whs[0] = waitHandles[i];
|
||||
int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
|
||||
if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!waitInfinitely)
|
||||
{
|
||||
// Update the time left to wait
|
||||
millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Release the wait handles
|
||||
ReleaseWaitHandles(waitableResults);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for any of the work items in the specified array to complete, cancel, or timeout
|
||||
/// </summary>
|
||||
/// <param name="waitableResults">Array of work item result objects</param>
|
||||
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
||||
/// <param name="exitContext">
|
||||
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||
/// </param>
|
||||
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
|
||||
/// <returns>
|
||||
/// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
|
||||
/// </returns>
|
||||
internal static int WaitAny(
|
||||
IWaitableResult[] waitableResults,
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle)
|
||||
{
|
||||
WaitHandle[] waitHandles;
|
||||
|
||||
if (null != cancelWaitHandle)
|
||||
{
|
||||
waitHandles = new WaitHandle[waitableResults.Length + 1];
|
||||
GetWaitHandles(waitableResults, waitHandles);
|
||||
waitHandles[waitableResults.Length] = cancelWaitHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
waitHandles = new WaitHandle[waitableResults.Length];
|
||||
GetWaitHandles(waitableResults, waitHandles);
|
||||
}
|
||||
|
||||
int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
|
||||
|
||||
// Treat cancel as timeout
|
||||
if (null != cancelWaitHandle)
|
||||
{
|
||||
if (result == waitableResults.Length)
|
||||
{
|
||||
result = STPEventWaitHandle.WaitTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseWaitHandles(waitableResults);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill an array of wait handles with the work items wait handles.
|
||||
/// </summary>
|
||||
/// <param name="waitableResults">An array of work item results</param>
|
||||
/// <param name="waitHandles">An array of wait handles to fill</param>
|
||||
private static void GetWaitHandles(
|
||||
IWaitableResult[] waitableResults,
|
||||
WaitHandle[] waitHandles)
|
||||
{
|
||||
for (int i = 0; i < waitableResults.Length; ++i)
|
||||
{
|
||||
WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult;
|
||||
Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects");
|
||||
|
||||
waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release the work items' wait handles
|
||||
/// </summary>
|
||||
/// <param name="waitableResults">An array of work item results</param>
|
||||
private static void ReleaseWaitHandles(IWaitableResult[] waitableResults)
|
||||
{
|
||||
for (int i = 0; i < waitableResults.Length; ++i)
|
||||
{
|
||||
WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult();
|
||||
|
||||
wir.GetWorkItem().ReleaseWaitHandle();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Members
|
||||
|
||||
private WorkItemState GetWorkItemState()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (WorkItemState.Completed == _workItemState)
|
||||
{
|
||||
return _workItemState;
|
||||
}
|
||||
|
||||
long nowTicks = DateTime.UtcNow.Ticks;
|
||||
|
||||
if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime)
|
||||
{
|
||||
_workItemState = WorkItemState.Canceled;
|
||||
}
|
||||
|
||||
if (WorkItemState.InProgress == _workItemState)
|
||||
{
|
||||
return _workItemState;
|
||||
}
|
||||
|
||||
if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled)
|
||||
{
|
||||
return WorkItemState.Canceled;
|
||||
}
|
||||
|
||||
return _workItemState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the work item's state
|
||||
/// </summary>
|
||||
/// <param name="workItemState">The state to set the work item to</param>
|
||||
private void SetWorkItemState(WorkItemState workItemState)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (IsValidStatesTransition(_workItemState, workItemState))
|
||||
{
|
||||
_workItemState = workItemState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals that work item has been completed or canceled
|
||||
/// </summary>
|
||||
/// <param name="canceled">Indicates that the work item has been canceled</param>
|
||||
private void SignalComplete(bool canceled)
|
||||
{
|
||||
SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed);
|
||||
lock (this)
|
||||
{
|
||||
// If someone is waiting then signal.
|
||||
if (null != _workItemCompleted)
|
||||
{
|
||||
_workItemCompleted.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void WorkItemIsQueued()
|
||||
{
|
||||
_waitingOnQueueStopwatch.Start();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Members exposed by WorkItemResult
|
||||
|
||||
/// <summary>
|
||||
/// Cancel the work item if it didn't start running yet.
|
||||
/// </summary>
|
||||
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
|
||||
private bool Cancel(bool abortExecution)
|
||||
{
|
||||
#if (_WINDOWS_CE)
|
||||
if(abortExecution)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
|
||||
}
|
||||
#endif
|
||||
bool success = false;
|
||||
bool signalComplete = false;
|
||||
|
||||
lock (this)
|
||||
{
|
||||
switch (GetWorkItemState())
|
||||
{
|
||||
case WorkItemState.Canceled:
|
||||
//Debug.WriteLine("Work item already canceled");
|
||||
if (abortExecution)
|
||||
{
|
||||
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||
if (null != executionThread)
|
||||
{
|
||||
executionThread.Abort(); // "Cancel"
|
||||
// No need to signalComplete, because we already cancelled this work item
|
||||
// so it already signaled its completion.
|
||||
//signalComplete = true;
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
case WorkItemState.Completed:
|
||||
//Debug.WriteLine("Work item cannot be canceled");
|
||||
break;
|
||||
case WorkItemState.InProgress:
|
||||
if (abortExecution)
|
||||
{
|
||||
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||
if (null != executionThread)
|
||||
{
|
||||
executionThread.Abort(); // "Cancel"
|
||||
success = true;
|
||||
signalComplete = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = true;
|
||||
signalComplete = true;
|
||||
}
|
||||
break;
|
||||
case WorkItemState.InQueue:
|
||||
// Signal to the wait for completion that the work
|
||||
// item has been completed (canceled). There is no
|
||||
// reason to wait for it to get out of the queue
|
||||
signalComplete = true;
|
||||
//Debug.WriteLine("Work item canceled");
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (signalComplete)
|
||||
{
|
||||
SignalComplete(true);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits for the result, timeout, or cancel.
|
||||
/// In case of error the method throws and exception
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
private object GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle)
|
||||
{
|
||||
Exception e;
|
||||
object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
||||
if (null != e)
|
||||
{
|
||||
throw new WorkItemResultException("The work item caused an excpetion, see the inner exception for details", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits for the result, timeout, or cancel.
|
||||
/// In case of error the e argument is filled with the exception
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
private object GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle,
|
||||
out Exception e)
|
||||
{
|
||||
e = null;
|
||||
|
||||
// Check for cancel
|
||||
if (WorkItemState.Canceled == GetWorkItemState())
|
||||
{
|
||||
throw new WorkItemCancelException("Work item canceled");
|
||||
}
|
||||
|
||||
// Check for completion
|
||||
if (IsCompleted)
|
||||
{
|
||||
e = _exception;
|
||||
return _result;
|
||||
}
|
||||
|
||||
// If no cancelWaitHandle is provided
|
||||
if (null == cancelWaitHandle)
|
||||
{
|
||||
WaitHandle wh = GetWaitHandle();
|
||||
|
||||
bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext);
|
||||
|
||||
ReleaseWaitHandle();
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
throw new WorkItemTimeoutException("Work item timeout");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitHandle wh = GetWaitHandle();
|
||||
int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
|
||||
ReleaseWaitHandle();
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
// The work item signaled
|
||||
// Note that the signal could be also as a result of canceling the
|
||||
// work item (not the get result)
|
||||
break;
|
||||
case 1:
|
||||
case STPEventWaitHandle.WaitTimeout:
|
||||
throw new WorkItemTimeoutException("Work item timeout");
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Check for cancel
|
||||
if (WorkItemState.Canceled == GetWorkItemState())
|
||||
{
|
||||
throw new WorkItemCancelException("Work item canceled");
|
||||
}
|
||||
|
||||
Debug.Assert(IsCompleted);
|
||||
|
||||
e = _exception;
|
||||
|
||||
// Return the result
|
||||
return _result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wait handle to wait for completion, cancel, or timeout
|
||||
/// </summary>
|
||||
private WaitHandle GetWaitHandle()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (null == _workItemCompleted)
|
||||
{
|
||||
_workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
|
||||
}
|
||||
++_workItemCompletedRefCount;
|
||||
}
|
||||
return _workItemCompleted;
|
||||
}
|
||||
|
||||
private void ReleaseWaitHandle()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (null != _workItemCompleted)
|
||||
{
|
||||
--_workItemCompletedRefCount;
|
||||
if (0 == _workItemCompletedRefCount)
|
||||
{
|
||||
_workItemCompleted.Close();
|
||||
_workItemCompleted = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when the work item has completed or canceled
|
||||
/// </summary>
|
||||
private bool IsCompleted
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
WorkItemState workItemState = GetWorkItemState();
|
||||
return ((workItemState == WorkItemState.Completed) ||
|
||||
(workItemState == WorkItemState.Canceled));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when the work item has canceled
|
||||
/// </summary>
|
||||
public bool IsCanceled
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return (GetWorkItemState() == WorkItemState.Canceled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHasWorkItemPriority Members
|
||||
|
||||
/// <summary>
|
||||
/// Returns the priority of the work item
|
||||
/// </summary>
|
||||
public WorkItemPriority WorkItemPriority
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItemInfo.WorkItemPriority;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal event WorkItemStateCallback OnWorkItemStarted
|
||||
{
|
||||
add
|
||||
{
|
||||
_workItemStartedEvent += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_workItemStartedEvent -= value;
|
||||
}
|
||||
}
|
||||
|
||||
internal event WorkItemStateCallback OnWorkItemCompleted
|
||||
{
|
||||
add
|
||||
{
|
||||
_workItemCompletedEvent += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_workItemCompletedEvent -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public void DisposeOfState()
|
||||
{
|
||||
if (_workItemInfo.DisposeOfStateObjects)
|
||||
{
|
||||
IDisposable disp = _state as IDisposable;
|
||||
if (null != disp)
|
||||
{
|
||||
disp.Dispose();
|
||||
_state = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
343
Networking/SmartThreadPool/WorkItemFactory.cs
Normal file
343
Networking/SmartThreadPool/WorkItemFactory.cs
Normal file
@@ -0,0 +1,343 @@
|
||||
using System;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
#region WorkItemFactory class
|
||||
|
||||
public class WorkItemFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback)
|
||||
{
|
||||
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="workItemPriority">The priority of the work item</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback,
|
||||
WorkItemPriority workItemPriority)
|
||||
{
|
||||
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="workItemInfo">Work item info</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemInfo workItemInfo,
|
||||
WorkItemCallback callback)
|
||||
{
|
||||
return CreateWorkItem(
|
||||
workItemsGroup,
|
||||
wigStartInfo,
|
||||
workItemInfo,
|
||||
callback,
|
||||
null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback,
|
||||
object state)
|
||||
{
|
||||
ValidateCallback(callback);
|
||||
|
||||
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
workItemInfo,
|
||||
callback,
|
||||
state);
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
WorkItemPriority workItemPriority)
|
||||
{
|
||||
ValidateCallback(callback);
|
||||
|
||||
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = workItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
workItemInfo,
|
||||
callback,
|
||||
state);
|
||||
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="workItemInfo">Work item information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemInfo workItemInfo,
|
||||
WorkItemCallback callback,
|
||||
object state)
|
||||
{
|
||||
ValidateCallback(callback);
|
||||
ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
new WorkItemInfo(workItemInfo),
|
||||
callback,
|
||||
state);
|
||||
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback)
|
||||
{
|
||||
ValidateCallback(callback);
|
||||
ValidateCallback(postExecuteWorkItemCallback);
|
||||
|
||||
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
workItemInfo,
|
||||
callback,
|
||||
state);
|
||||
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||
WorkItemPriority workItemPriority)
|
||||
{
|
||||
ValidateCallback(callback);
|
||||
ValidateCallback(postExecuteWorkItemCallback);
|
||||
|
||||
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = workItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
workItemInfo,
|
||||
callback,
|
||||
state);
|
||||
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||
CallToPostExecute callToPostExecute)
|
||||
{
|
||||
ValidateCallback(callback);
|
||||
ValidateCallback(postExecuteWorkItemCallback);
|
||||
|
||||
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = callToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
workItemInfo,
|
||||
callback,
|
||||
state);
|
||||
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
public static WorkItem CreateWorkItem(
|
||||
IWorkItemsGroup workItemsGroup,
|
||||
WIGStartInfo wigStartInfo,
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||
CallToPostExecute callToPostExecute,
|
||||
WorkItemPriority workItemPriority)
|
||||
{
|
||||
|
||||
ValidateCallback(callback);
|
||||
ValidateCallback(postExecuteWorkItemCallback);
|
||||
|
||||
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = callToPostExecute;
|
||||
workItemInfo.WorkItemPriority = workItemPriority;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
workItemInfo,
|
||||
callback,
|
||||
state);
|
||||
|
||||
return workItem;
|
||||
}
|
||||
|
||||
private static void ValidateCallback(Delegate callback)
|
||||
{
|
||||
if (callback != null && callback.GetInvocationList().Length > 1)
|
||||
{
|
||||
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
69
Networking/SmartThreadPool/WorkItemInfo.cs
Normal file
69
Networking/SmartThreadPool/WorkItemInfo.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
namespace Amib.Threading
|
||||
{
|
||||
#region WorkItemInfo class
|
||||
|
||||
/// <summary>
|
||||
/// Summary description for WorkItemInfo.
|
||||
/// </summary>
|
||||
public class WorkItemInfo
|
||||
{
|
||||
public WorkItemInfo()
|
||||
{
|
||||
UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||
UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||
DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||
CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||
PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||
WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||
}
|
||||
|
||||
public WorkItemInfo(WorkItemInfo workItemInfo)
|
||||
{
|
||||
UseCallerCallContext = workItemInfo.UseCallerCallContext;
|
||||
UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
|
||||
DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
|
||||
CallToPostExecute = workItemInfo.CallToPostExecute;
|
||||
PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
|
||||
WorkItemPriority = workItemInfo.WorkItemPriority;
|
||||
Timeout = workItemInfo.Timeout;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set if to use the caller's security context
|
||||
/// </summary>
|
||||
public bool UseCallerCallContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set if to use the caller's HTTP context
|
||||
/// </summary>
|
||||
public bool UseCallerHttpContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set if to dispose of the state object of a work item
|
||||
/// </summary>
|
||||
public bool DisposeOfStateObjects { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the run the post execute options
|
||||
/// </summary>
|
||||
public CallToPostExecute CallToPostExecute { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the post execute callback
|
||||
/// </summary>
|
||||
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the work item's priority
|
||||
/// </summary>
|
||||
public WorkItemPriority WorkItemPriority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the work item's timout in milliseconds.
|
||||
/// This is a passive timout. When the timout expires the work item won't be actively aborted!
|
||||
/// </summary>
|
||||
public long Timeout { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
128
Networking/SmartThreadPool/WorkItemResultTWrapper.cs
Normal file
128
Networking/SmartThreadPool/WorkItemResultTWrapper.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
#region WorkItemResultTWrapper class
|
||||
|
||||
internal class WorkItemResultTWrapper<TResult> : IWorkItemResult<TResult>, IInternalWaitableResult
|
||||
{
|
||||
private readonly IWorkItemResult _workItemResult;
|
||||
|
||||
public WorkItemResultTWrapper(IWorkItemResult workItemResult)
|
||||
{
|
||||
_workItemResult = workItemResult;
|
||||
}
|
||||
|
||||
#region IWorkItemResult<TResult> Members
|
||||
|
||||
public TResult GetResult()
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult();
|
||||
}
|
||||
|
||||
public TResult GetResult(int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext);
|
||||
}
|
||||
|
||||
public TResult GetResult(TimeSpan timeout, bool exitContext)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(timeout, exitContext);
|
||||
}
|
||||
|
||||
public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
|
||||
}
|
||||
|
||||
public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle);
|
||||
}
|
||||
|
||||
public TResult GetResult(out Exception e)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(out e);
|
||||
}
|
||||
|
||||
public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e);
|
||||
}
|
||||
|
||||
public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(timeout, exitContext, out e);
|
||||
}
|
||||
|
||||
public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
||||
}
|
||||
|
||||
public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||
{
|
||||
return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e);
|
||||
}
|
||||
|
||||
public bool IsCompleted
|
||||
{
|
||||
get { return _workItemResult.IsCompleted; }
|
||||
}
|
||||
|
||||
public bool IsCanceled
|
||||
{
|
||||
get { return _workItemResult.IsCanceled; }
|
||||
}
|
||||
|
||||
public object State
|
||||
{
|
||||
get { return _workItemResult.State; }
|
||||
}
|
||||
|
||||
public bool Cancel()
|
||||
{
|
||||
return _workItemResult.Cancel();
|
||||
}
|
||||
|
||||
public bool Cancel(bool abortExecution)
|
||||
{
|
||||
return _workItemResult.Cancel(abortExecution);
|
||||
}
|
||||
|
||||
public WorkItemPriority WorkItemPriority
|
||||
{
|
||||
get { return _workItemResult.WorkItemPriority; }
|
||||
}
|
||||
|
||||
public TResult Result
|
||||
{
|
||||
get { return (TResult)_workItemResult.Result; }
|
||||
}
|
||||
|
||||
public object Exception
|
||||
{
|
||||
get { return _workItemResult.Exception; }
|
||||
}
|
||||
|
||||
#region IInternalWorkItemResult Members
|
||||
|
||||
public IWorkItemResult GetWorkItemResult()
|
||||
{
|
||||
return _workItemResult.GetWorkItemResult();
|
||||
}
|
||||
|
||||
public IWorkItemResult<TRes> GetWorkItemResultT<TRes>()
|
||||
{
|
||||
return (IWorkItemResult<TRes>)this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
369
Networking/SmartThreadPool/WorkItemsGroup.cs
Normal file
369
Networking/SmartThreadPool/WorkItemsGroup.cs
Normal file
@@ -0,0 +1,369 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
|
||||
#region WorkItemsGroup class
|
||||
|
||||
/// <summary>
|
||||
/// Summary description for WorkItemsGroup.
|
||||
/// </summary>
|
||||
public class WorkItemsGroup : WorkItemsGroupBase
|
||||
{
|
||||
#region Private members
|
||||
|
||||
private readonly object _lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the SmartThreadPool instance that created this
|
||||
/// WorkItemsGroup.
|
||||
/// </summary>
|
||||
private readonly SmartThreadPool _stp;
|
||||
|
||||
/// <summary>
|
||||
/// The OnIdle event
|
||||
/// </summary>
|
||||
private event WorkItemsGroupIdleHandler _onIdle;
|
||||
|
||||
/// <summary>
|
||||
/// A flag to indicate if the Work Items Group is now suspended.
|
||||
/// </summary>
|
||||
private bool _isSuspended;
|
||||
|
||||
/// <summary>
|
||||
/// Defines how many work items of this WorkItemsGroup can run at once.
|
||||
/// </summary>
|
||||
private int _concurrency;
|
||||
|
||||
/// <summary>
|
||||
/// Priority queue to hold work items before they are passed
|
||||
/// to the SmartThreadPool.
|
||||
/// </summary>
|
||||
private readonly PriorityQueue _workItemsQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate how many work items are waiting in the SmartThreadPool
|
||||
/// queue.
|
||||
/// This value is used to apply the concurrency.
|
||||
/// </summary>
|
||||
private int _workItemsInStpQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate how many work items are currently running in the SmartThreadPool.
|
||||
/// This value is used with the Cancel, to calculate if we can send new
|
||||
/// work items to the STP.
|
||||
/// </summary>
|
||||
private int _workItemsExecutingInStp = 0;
|
||||
|
||||
/// <summary>
|
||||
/// WorkItemsGroup start information
|
||||
/// </summary>
|
||||
private readonly WIGStartInfo _workItemsGroupStartInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Signaled when all of the WorkItemsGroup's work item completed.
|
||||
/// </summary>
|
||||
//private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
|
||||
private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
|
||||
|
||||
/// <summary>
|
||||
/// A common object for all the work items that this work items group
|
||||
/// generate so we can mark them to cancel in O(1)
|
||||
/// </summary>
|
||||
private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
public WorkItemsGroup(
|
||||
SmartThreadPool stp,
|
||||
int concurrency,
|
||||
WIGStartInfo wigStartInfo)
|
||||
{
|
||||
if (concurrency <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
"concurrency",
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
concurrency,
|
||||
#endif
|
||||
"concurrency must be greater than zero");
|
||||
}
|
||||
_stp = stp;
|
||||
_concurrency = concurrency;
|
||||
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
|
||||
_workItemsQueue = new PriorityQueue();
|
||||
Name = "WorkItemsGroup";
|
||||
|
||||
// The _workItemsInStpQueue gets the number of currently executing work items,
|
||||
// because once a work item is executing, it cannot be cancelled.
|
||||
_workItemsInStpQueue = _workItemsExecutingInStp;
|
||||
|
||||
_isSuspended = _workItemsGroupStartInfo.StartSuspended;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WorkItemsGroupBase Overrides
|
||||
|
||||
public override int Concurrency
|
||||
{
|
||||
get { return _concurrency; }
|
||||
set
|
||||
{
|
||||
Debug.Assert(value > 0);
|
||||
|
||||
int diff = value - _concurrency;
|
||||
_concurrency = value;
|
||||
if (diff > 0)
|
||||
{
|
||||
EnqueueToSTPNextNWorkItem(diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int InUseThreads
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItemsExecutingInStp;
|
||||
}
|
||||
}
|
||||
|
||||
public override int WaitingCallbacks
|
||||
{
|
||||
get { return _workItemsQueue.Count; }
|
||||
}
|
||||
|
||||
public override object[] GetStates()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
object[] states = new object[_workItemsQueue.Count];
|
||||
int i = 0;
|
||||
foreach (WorkItem workItem in _workItemsQueue)
|
||||
{
|
||||
states[i] = workItem.GetWorkItemResult().State;
|
||||
++i;
|
||||
}
|
||||
return states;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WorkItemsGroup start information
|
||||
/// </summary>
|
||||
public override WIGStartInfo WIGStartInfo
|
||||
{
|
||||
get { return _workItemsGroupStartInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the Work Items Group if it was started suspended
|
||||
/// </summary>
|
||||
public override void Start()
|
||||
{
|
||||
// If the Work Items Group already started then quit
|
||||
if (!_isSuspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_isSuspended = false;
|
||||
|
||||
EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
|
||||
}
|
||||
|
||||
public override void Cancel(bool abortExecution)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_canceledWorkItemsGroup.IsCanceled = true;
|
||||
_workItemsQueue.Clear();
|
||||
_workItemsInStpQueue = 0;
|
||||
_canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||
}
|
||||
|
||||
if (abortExecution)
|
||||
{
|
||||
_stp.CancelAbortWorkItemsGroup(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for the thread pool to be idle
|
||||
/// </summary>
|
||||
public override bool WaitForIdle(int millisecondsTimeout)
|
||||
{
|
||||
SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
|
||||
return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
|
||||
}
|
||||
|
||||
public override event WorkItemsGroupIdleHandler OnIdle
|
||||
{
|
||||
add { _onIdle += value; }
|
||||
remove { _onIdle -= value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
|
||||
{
|
||||
IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
|
||||
iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
|
||||
iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
|
||||
}
|
||||
|
||||
public void OnSTPIsStarting()
|
||||
{
|
||||
if (_isSuspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnqueueToSTPNextNWorkItem(_concurrency);
|
||||
}
|
||||
|
||||
public void EnqueueToSTPNextNWorkItem(int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
private object FireOnIdle(object state)
|
||||
{
|
||||
FireOnIdleImpl(_onIdle);
|
||||
return null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
|
||||
{
|
||||
if(null == onIdle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Delegate[] delegates = onIdle.GetInvocationList();
|
||||
foreach(WorkItemsGroupIdleHandler eh in delegates)
|
||||
{
|
||||
try
|
||||
{
|
||||
eh(this);
|
||||
}
|
||||
catch { } // Suppress exceptions
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWorkItemStartedCallback(WorkItem workItem)
|
||||
{
|
||||
lock(_lock)
|
||||
{
|
||||
++_workItemsExecutingInStp;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWorkItemCompletedCallback(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(null, true);
|
||||
}
|
||||
|
||||
internal override void Enqueue(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(workItem);
|
||||
}
|
||||
|
||||
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(workItem, false);
|
||||
}
|
||||
|
||||
private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
|
||||
{
|
||||
lock(_lock)
|
||||
{
|
||||
// Got here from OnWorkItemCompletedCallback()
|
||||
if (decrementWorkItemsInStpQueue)
|
||||
{
|
||||
--_workItemsInStpQueue;
|
||||
|
||||
if(_workItemsInStpQueue < 0)
|
||||
{
|
||||
_workItemsInStpQueue = 0;
|
||||
}
|
||||
|
||||
--_workItemsExecutingInStp;
|
||||
|
||||
if(_workItemsExecutingInStp < 0)
|
||||
{
|
||||
_workItemsExecutingInStp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If the work item is not null then enqueue it
|
||||
if (null != workItem)
|
||||
{
|
||||
workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
|
||||
|
||||
RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
|
||||
_workItemsQueue.Enqueue(workItem);
|
||||
//_stp.IncrementWorkItemsCount();
|
||||
|
||||
if ((1 == _workItemsQueue.Count) &&
|
||||
(0 == _workItemsInStpQueue))
|
||||
{
|
||||
_stp.RegisterWorkItemsGroup(this);
|
||||
IsIdle = false;
|
||||
_isIdleWaitHandle.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// If the work items queue of the group is empty than quit
|
||||
if (0 == _workItemsQueue.Count)
|
||||
{
|
||||
if (0 == _workItemsInStpQueue)
|
||||
{
|
||||
_stp.UnregisterWorkItemsGroup(this);
|
||||
IsIdle = true;
|
||||
_isIdleWaitHandle.Set();
|
||||
if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
|
||||
{
|
||||
_stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isSuspended)
|
||||
{
|
||||
if (_workItemsInStpQueue < _concurrency)
|
||||
{
|
||||
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
|
||||
try
|
||||
{
|
||||
_stp.Enqueue(nextWorkItem);
|
||||
}
|
||||
catch (ObjectDisposedException e)
|
||||
{
|
||||
e.GetHashCode();
|
||||
// The STP has been shutdown
|
||||
}
|
||||
|
||||
++_workItemsInStpQueue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
449
Networking/SmartThreadPool/WorkItemsGroupBase.cs
Normal file
449
Networking/SmartThreadPool/WorkItemsGroupBase.cs
Normal file
@@ -0,0 +1,449 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
public abstract class WorkItemsGroupBase : IWorkItemsGroup
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the name of this instance of SmartThreadPool.
|
||||
/// Can be changed by the user.
|
||||
/// </summary>
|
||||
private string _name = "WorkItemsGroupBase";
|
||||
|
||||
public WorkItemsGroupBase()
|
||||
{
|
||||
IsIdle = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWorkItemsGroup Members
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { _name = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Abstract Methods
|
||||
|
||||
public abstract int Concurrency { get; set; }
|
||||
public abstract int WaitingCallbacks { get; }
|
||||
public abstract int InUseThreads { get; }
|
||||
|
||||
public abstract object[] GetStates();
|
||||
public abstract WIGStartInfo WIGStartInfo { get; }
|
||||
public abstract void Start();
|
||||
public abstract void Cancel(bool abortExecution);
|
||||
public abstract bool WaitForIdle(int millisecondsTimeout);
|
||||
public abstract event WorkItemsGroupIdleHandler OnIdle;
|
||||
|
||||
internal abstract void Enqueue(WorkItem workItem);
|
||||
internal virtual void PreQueueWorkItem() { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Common Base Methods
|
||||
|
||||
/// <summary>
|
||||
/// Cancel all the work items.
|
||||
/// Same as Cancel(false)
|
||||
/// </summary>
|
||||
public virtual void Cancel()
|
||||
{
|
||||
Cancel(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
|
||||
/// </summary>
|
||||
public void WaitForIdle()
|
||||
{
|
||||
WaitForIdle(Timeout.Infinite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
|
||||
/// </summary>
|
||||
public bool WaitForIdle(TimeSpan timeout)
|
||||
{
|
||||
return WaitForIdle((int)timeout.TotalMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IsIdle is true when there are no work items running or queued.
|
||||
/// </summary>
|
||||
public bool IsIdle { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region QueueWorkItem
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
|
||||
{
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="workItemPriority">The priority of the work item</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="workItemInfo">Work item info</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
|
||||
{
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="workItemInfo">Work item information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||
WorkItemPriority workItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||
CallToPostExecute callToPostExecute)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
/// The context object of the work item. Used for passing arguments to the work item.
|
||||
/// </param>
|
||||
/// <param name="postExecuteWorkItemCallback">
|
||||
/// A delegate to call after the callback completion
|
||||
/// </param>
|
||||
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||
/// <param name="workItemPriority">The work item priority</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(
|
||||
WorkItemCallback callback,
|
||||
object state,
|
||||
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||
CallToPostExecute callToPostExecute,
|
||||
WorkItemPriority workItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
|
||||
Enqueue(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region QueueWorkItem(Action<...>)
|
||||
|
||||
public IWorkItemResult QueueWorkItem(Action action, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem ();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||
this,
|
||||
WIGStartInfo,
|
||||
delegate
|
||||
{
|
||||
action.Invoke ();
|
||||
return null;
|
||||
}, priority);
|
||||
Enqueue (workItem);
|
||||
return workItem.GetWorkItemResult ();
|
||||
}
|
||||
|
||||
public IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem ();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
action.Invoke (arg);
|
||||
return null;
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority);
|
||||
Enqueue (workItem);
|
||||
return workItem.GetWorkItemResult ();
|
||||
}
|
||||
|
||||
public IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem ();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
action.Invoke (arg1, arg2);
|
||||
return null;
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority);
|
||||
Enqueue (workItem);
|
||||
return workItem.GetWorkItemResult ();
|
||||
}
|
||||
|
||||
public IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem ();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
action.Invoke (arg1, arg2, arg3);
|
||||
return null;
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority);
|
||||
Enqueue (workItem);
|
||||
return workItem.GetWorkItemResult ();
|
||||
}
|
||||
|
||||
public IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (
|
||||
Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem ();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
action.Invoke (arg1, arg2, arg3, arg4);
|
||||
return null;
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority);
|
||||
Enqueue (workItem);
|
||||
return workItem.GetWorkItemResult ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region QueueWorkItem(Func<...>)
|
||||
|
||||
public IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
return func.Invoke();
|
||||
}, priority);
|
||||
Enqueue(workItem);
|
||||
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||
}
|
||||
|
||||
public IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
return func.Invoke(arg);
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null,
|
||||
priority);
|
||||
Enqueue(workItem);
|
||||
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||
}
|
||||
|
||||
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
return func.Invoke(arg1, arg2);
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null,
|
||||
priority);
|
||||
Enqueue(workItem);
|
||||
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||
}
|
||||
|
||||
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(
|
||||
Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
return func.Invoke(arg1, arg2, arg3);
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null,
|
||||
priority);
|
||||
Enqueue(workItem);
|
||||
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||
}
|
||||
|
||||
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(
|
||||
Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||
{
|
||||
PreQueueWorkItem();
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||
this,
|
||||
WIGStartInfo,
|
||||
state =>
|
||||
{
|
||||
return func.Invoke(arg1, arg2, arg3, arg4);
|
||||
},
|
||||
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null,
|
||||
priority);
|
||||
Enqueue(workItem);
|
||||
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
645
Networking/SmartThreadPool/WorkItemsQueue.cs
Normal file
645
Networking/SmartThreadPool/WorkItemsQueue.cs
Normal file
@@ -0,0 +1,645 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
#region WorkItemsQueue class
|
||||
|
||||
/// <summary>
|
||||
/// WorkItemsQueue class.
|
||||
/// </summary>
|
||||
public class WorkItemsQueue : IDisposable
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
/// <summary>
|
||||
/// Waiters queue (implemented as stack).
|
||||
/// </summary>
|
||||
private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
|
||||
|
||||
/// <summary>
|
||||
/// Waiters count
|
||||
/// </summary>
|
||||
private int _waitersCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Work items queue
|
||||
/// </summary>
|
||||
private readonly PriorityQueue _workItems = new PriorityQueue();
|
||||
|
||||
/// <summary>
|
||||
/// Indicate that work items are allowed to be queued
|
||||
/// </summary>
|
||||
private bool _isWorkItemsQueueActive = true;
|
||||
|
||||
|
||||
#if (WINDOWS_PHONE)
|
||||
private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>();
|
||||
#elif (_WINDOWS_CE)
|
||||
private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
|
||||
#else
|
||||
|
||||
[ThreadStatic]
|
||||
private static WaiterEntry _waiterEntry;
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Each thread in the thread pool keeps its own waiter entry.
|
||||
/// </summary>
|
||||
private static WaiterEntry CurrentWaiterEntry
|
||||
{
|
||||
#if (WINDOWS_PHONE)
|
||||
get
|
||||
{
|
||||
lock (_waiterEntries)
|
||||
{
|
||||
WaiterEntry waiterEntry;
|
||||
if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry))
|
||||
{
|
||||
return waiterEntry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_waiterEntries)
|
||||
{
|
||||
_waiterEntries[Thread.CurrentThread.ManagedThreadId] = value;
|
||||
}
|
||||
}
|
||||
#elif (_WINDOWS_CE)
|
||||
get
|
||||
{
|
||||
return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
|
||||
}
|
||||
set
|
||||
{
|
||||
Thread.SetData(_waiterEntrySlot, value);
|
||||
}
|
||||
#else
|
||||
get
|
||||
{
|
||||
return _waiterEntry;
|
||||
}
|
||||
set
|
||||
{
|
||||
_waiterEntry = value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A flag that indicates if the WorkItemsQueue has been disposed.
|
||||
/// </summary>
|
||||
private bool _isDisposed = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current number of work items in the queue
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItems.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current number of waiters
|
||||
/// </summary>
|
||||
public int WaitersCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return _waitersCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public methods
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue a work item to the queue.
|
||||
/// </summary>
|
||||
public bool EnqueueWorkItem(WorkItem workItem)
|
||||
{
|
||||
// A work item cannot be null, since null is used in the
|
||||
// WaitForWorkItem() method to indicate timeout or cancel
|
||||
if (null == workItem)
|
||||
{
|
||||
throw new ArgumentNullException("workItem" , "workItem cannot be null");
|
||||
}
|
||||
|
||||
bool enqueue = true;
|
||||
|
||||
// First check if there is a waiter waiting for work item. During
|
||||
// the check, timed out waiters are ignored. If there is no
|
||||
// waiter then the work item is queued.
|
||||
lock(this)
|
||||
{
|
||||
ValidateNotDisposed();
|
||||
|
||||
if (!_isWorkItemsQueueActive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while(_waitersCount > 0)
|
||||
{
|
||||
// Dequeue a waiter.
|
||||
WaiterEntry waiterEntry = PopWaiter();
|
||||
|
||||
// Signal the waiter. On success break the loop
|
||||
if (waiterEntry.Signal(workItem))
|
||||
{
|
||||
enqueue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (enqueue)
|
||||
{
|
||||
// Enqueue the work item
|
||||
_workItems.Enqueue(workItem);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Waits for a work item or exits on timeout or cancel
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout">Timeout in milliseconds</param>
|
||||
/// <param name="cancelEvent">Cancel wait handle</param>
|
||||
/// <returns>Returns true if the resource was granted</returns>
|
||||
public WorkItem DequeueWorkItem(
|
||||
int millisecondsTimeout,
|
||||
WaitHandle cancelEvent)
|
||||
{
|
||||
// This method cause the caller to wait for a work item.
|
||||
// If there is at least one waiting work item then the
|
||||
// method returns immidiately with it.
|
||||
//
|
||||
// If there are no waiting work items then the caller
|
||||
// is queued between other waiters for a work item to arrive.
|
||||
//
|
||||
// If a work item didn't come within millisecondsTimeout or
|
||||
// the user canceled the wait by signaling the cancelEvent
|
||||
// then the method returns null to indicate that the caller
|
||||
// didn't get a work item.
|
||||
|
||||
WaiterEntry waiterEntry;
|
||||
WorkItem workItem = null;
|
||||
lock (this)
|
||||
{
|
||||
ValidateNotDisposed();
|
||||
|
||||
// If there are waiting work items then take one and return.
|
||||
if (_workItems.Count > 0)
|
||||
{
|
||||
workItem = _workItems.Dequeue() as WorkItem;
|
||||
return workItem;
|
||||
}
|
||||
|
||||
// No waiting work items ...
|
||||
|
||||
// Get the waiter entry for the waiters queue
|
||||
waiterEntry = GetThreadWaiterEntry();
|
||||
|
||||
// Put the waiter with the other waiters
|
||||
PushWaiter(waiterEntry);
|
||||
}
|
||||
|
||||
// Prepare array of wait handle for the WaitHandle.WaitAny()
|
||||
WaitHandle [] waitHandles = new WaitHandle[] {
|
||||
waiterEntry.WaitHandle,
|
||||
cancelEvent };
|
||||
|
||||
// Wait for an available resource, cancel event, or timeout.
|
||||
|
||||
// During the wait we are supposes to exit the synchronization
|
||||
// domain. (Placing true as the third argument of the WaitAny())
|
||||
// It just doesn't work, I don't know why, so I have two lock(this)
|
||||
// statments instead of one.
|
||||
|
||||
int index = STPEventWaitHandle.WaitAny(
|
||||
waitHandles,
|
||||
millisecondsTimeout,
|
||||
true);
|
||||
|
||||
lock(this)
|
||||
{
|
||||
// success is true if it got a work item.
|
||||
bool success = (0 == index);
|
||||
|
||||
// The timeout variable is used only for readability.
|
||||
// (We treat cancel as timeout)
|
||||
bool timeout = !success;
|
||||
|
||||
// On timeout update the waiterEntry that it is timed out
|
||||
if (timeout)
|
||||
{
|
||||
// The Timeout() fails if the waiter has already been signaled
|
||||
timeout = waiterEntry.Timeout();
|
||||
|
||||
// On timeout remove the waiter from the queue.
|
||||
// Note that the complexity is O(1).
|
||||
if(timeout)
|
||||
{
|
||||
RemoveWaiter(waiterEntry, false);
|
||||
}
|
||||
|
||||
// Again readability
|
||||
success = !timeout;
|
||||
}
|
||||
|
||||
// On success return the work item
|
||||
if (success)
|
||||
{
|
||||
workItem = waiterEntry.WorkItem;
|
||||
|
||||
if (null == workItem)
|
||||
{
|
||||
workItem = _workItems.Dequeue() as WorkItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
// On failure return null.
|
||||
return workItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup the work items queue, hence no more work
|
||||
/// items are allowed to be queue
|
||||
/// </summary>
|
||||
private void Cleanup()
|
||||
{
|
||||
lock(this)
|
||||
{
|
||||
// Deactivate only once
|
||||
if (!_isWorkItemsQueueActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't queue more work items
|
||||
_isWorkItemsQueueActive = false;
|
||||
|
||||
foreach(WorkItem workItem in _workItems)
|
||||
{
|
||||
workItem.DisposeOfState();
|
||||
}
|
||||
|
||||
// Clear the work items that are already queued
|
||||
_workItems.Clear();
|
||||
|
||||
// Note:
|
||||
// I don't iterate over the queue and dispose of work items's states,
|
||||
// since if a work item has a state object that is still in use in the
|
||||
// application then I must not dispose it.
|
||||
|
||||
// Tell the waiters that they were timed out.
|
||||
// It won't signal them to exit, but to ignore their
|
||||
// next work item.
|
||||
while(_waitersCount > 0)
|
||||
{
|
||||
WaiterEntry waiterEntry = PopWaiter();
|
||||
waiterEntry.Timeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object[] GetStates()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
object[] states = new object[_workItems.Count];
|
||||
int i = 0;
|
||||
foreach (WorkItem workItem in _workItems)
|
||||
{
|
||||
states[i] = workItem.GetWorkItemResult().State;
|
||||
++i;
|
||||
}
|
||||
return states;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns the WaiterEntry of the current thread
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// In order to avoid creation and destuction of WaiterEntry
|
||||
/// objects each thread has its own WaiterEntry object.
|
||||
private static WaiterEntry GetThreadWaiterEntry()
|
||||
{
|
||||
if (null == CurrentWaiterEntry)
|
||||
{
|
||||
CurrentWaiterEntry = new WaiterEntry();
|
||||
}
|
||||
CurrentWaiterEntry.Reset();
|
||||
return CurrentWaiterEntry;
|
||||
}
|
||||
|
||||
#region Waiters stack methods
|
||||
|
||||
/// <summary>
|
||||
/// Push a new waiter into the waiter's stack
|
||||
/// </summary>
|
||||
/// <param name="newWaiterEntry">A waiter to put in the stack</param>
|
||||
public void PushWaiter(WaiterEntry newWaiterEntry)
|
||||
{
|
||||
// Remove the waiter if it is already in the stack and
|
||||
// update waiter's count as needed
|
||||
RemoveWaiter(newWaiterEntry, false);
|
||||
|
||||
// If the stack is empty then newWaiterEntry is the new head of the stack
|
||||
if (null == _headWaiterEntry._nextWaiterEntry)
|
||||
{
|
||||
_headWaiterEntry._nextWaiterEntry = newWaiterEntry;
|
||||
newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
|
||||
|
||||
}
|
||||
// If the stack is not empty then put newWaiterEntry as the new head
|
||||
// of the stack.
|
||||
else
|
||||
{
|
||||
// Save the old first waiter entry
|
||||
WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
|
||||
|
||||
// Update the links
|
||||
_headWaiterEntry._nextWaiterEntry = newWaiterEntry;
|
||||
newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
|
||||
newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
|
||||
oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
|
||||
}
|
||||
|
||||
// Increment the number of waiters
|
||||
++_waitersCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop a waiter from the waiter's stack
|
||||
/// </summary>
|
||||
/// <returns>Returns the first waiter in the stack</returns>
|
||||
private WaiterEntry PopWaiter()
|
||||
{
|
||||
// Store the current stack head
|
||||
WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
|
||||
|
||||
// Store the new stack head
|
||||
WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
|
||||
|
||||
// Update the old stack head list links and decrement the number
|
||||
// waiters.
|
||||
RemoveWaiter(oldFirstWaiterEntry, true);
|
||||
|
||||
// Update the new stack head
|
||||
_headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
|
||||
if (null != newHeadWaiterEntry)
|
||||
{
|
||||
newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
|
||||
}
|
||||
|
||||
// Return the old stack head
|
||||
return oldFirstWaiterEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a waiter from the stack
|
||||
/// </summary>
|
||||
/// <param name="waiterEntry">A waiter entry to remove</param>
|
||||
/// <param name="popDecrement">If true the waiter count is always decremented</param>
|
||||
private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
|
||||
{
|
||||
// Store the prev entry in the list
|
||||
WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
|
||||
|
||||
// Store the next entry in the list
|
||||
WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
|
||||
|
||||
// A flag to indicate if we need to decrement the waiters count.
|
||||
// If we got here from PopWaiter then we must decrement.
|
||||
// If we got here from PushWaiter then we decrement only if
|
||||
// the waiter was already in the stack.
|
||||
bool decrementCounter = popDecrement;
|
||||
|
||||
// Null the waiter's entry links
|
||||
waiterEntry._prevWaiterEntry = null;
|
||||
waiterEntry._nextWaiterEntry = null;
|
||||
|
||||
// If the waiter entry had a prev link then update it.
|
||||
// It also means that the waiter is already in the list and we
|
||||
// need to decrement the waiters count.
|
||||
if (null != prevWaiterEntry)
|
||||
{
|
||||
prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
|
||||
decrementCounter = true;
|
||||
}
|
||||
|
||||
// If the waiter entry had a next link then update it.
|
||||
// It also means that the waiter is already in the list and we
|
||||
// need to decrement the waiters count.
|
||||
if (null != nextWaiterEntry)
|
||||
{
|
||||
nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
|
||||
decrementCounter = true;
|
||||
}
|
||||
|
||||
// Decrement the waiters count if needed
|
||||
if (decrementCounter)
|
||||
{
|
||||
--_waitersCount;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region WaiterEntry class
|
||||
|
||||
// A waiter entry in the _waiters queue.
|
||||
public sealed class WaiterEntry : IDisposable
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
/// <summary>
|
||||
/// Event to signal the waiter that it got the work item.
|
||||
/// </summary>
|
||||
//private AutoResetEvent _waitHandle = new AutoResetEvent(false);
|
||||
private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
|
||||
|
||||
/// <summary>
|
||||
/// Flag to know if this waiter already quited from the queue
|
||||
/// because of a timeout.
|
||||
/// </summary>
|
||||
private bool _isTimedout = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag to know if the waiter was signaled and got a work item.
|
||||
/// </summary>
|
||||
private bool _isSignaled = false;
|
||||
|
||||
/// <summary>
|
||||
/// A work item that passed directly to the waiter withou going
|
||||
/// through the queue
|
||||
/// </summary>
|
||||
private WorkItem _workItem = null;
|
||||
|
||||
private bool _isDisposed = false;
|
||||
|
||||
// Linked list members
|
||||
internal WaiterEntry _nextWaiterEntry = null;
|
||||
internal WaiterEntry _prevWaiterEntry = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
public WaiterEntry()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public methods
|
||||
|
||||
public WaitHandle WaitHandle
|
||||
{
|
||||
get { return _waitHandle; }
|
||||
}
|
||||
|
||||
public WorkItem WorkItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItem;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal the waiter that it got a work item.
|
||||
/// </summary>
|
||||
/// <returns>Return true on success</returns>
|
||||
/// The method fails if Timeout() preceded its call
|
||||
public bool Signal(WorkItem workItem)
|
||||
{
|
||||
lock(this)
|
||||
{
|
||||
if (!_isTimedout)
|
||||
{
|
||||
_workItem = workItem;
|
||||
_isSignaled = true;
|
||||
_waitHandle.Set();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the wait entry that it has been timed out
|
||||
/// </summary>
|
||||
/// <returns>Return true on success</returns>
|
||||
/// The method fails if Signal() preceded its call
|
||||
public bool Timeout()
|
||||
{
|
||||
lock(this)
|
||||
{
|
||||
// Time out can happen only if the waiter wasn't marked as
|
||||
// signaled
|
||||
if (!_isSignaled)
|
||||
{
|
||||
// We don't remove the waiter from the queue, the DequeueWorkItem
|
||||
// method skips _waiters that were timed out.
|
||||
_isTimedout = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the wait entry so it can be used again
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_workItem = null;
|
||||
_isTimedout = false;
|
||||
_isSignaled = false;
|
||||
_waitHandle.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free resources
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (null != _waitHandle)
|
||||
{
|
||||
_waitHandle.Close();
|
||||
_waitHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
private void ValidateNotDisposed()
|
||||
{
|
||||
if(_isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="PTConverter.Plugin" version="1.0.2" targetFramework="net472" />
|
||||
<package id="PTConverter.Plugin" version="1.0.3" targetFramework="net472" />
|
||||
</packages>
|
||||
6
WpfApp1/App.config
Normal file
6
WpfApp1/App.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
</configuration>
|
||||
9
WpfApp1/App.xaml
Normal file
9
WpfApp1/App.xaml
Normal file
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="WpfApp1.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:WpfApp1"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
17
WpfApp1/App.xaml.cs
Normal file
17
WpfApp1/App.xaml.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace WpfApp1
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für "App.xaml"
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
15
WpfApp1/MainWindow.xaml
Normal file
15
WpfApp1/MainWindow.xaml
Normal file
@@ -0,0 +1,15 @@
|
||||
<Window
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WpfApp1"
|
||||
xmlns:Pages="clr-namespace:Networking.Pages;assembly=Networking" x:Class="WpfApp1.MainWindow"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="450" Width="800">
|
||||
<Grid>
|
||||
|
||||
<Pages:IPScanner HorizontalAlignment="Left" Height="336" Margin="0,55,0,0" VerticalAlignment="Top" Width="782"/>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
28
WpfApp1/MainWindow.xaml.cs
Normal file
28
WpfApp1/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace WpfApp1
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
55
WpfApp1/Properties/AssemblyInfo.cs
Normal file
55
WpfApp1/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||
// die einer Assembly zugeordnet sind.
|
||||
[assembly: AssemblyTitle("WpfApp1")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("WpfApp1")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2022")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
|
||||
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
|
||||
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie
|
||||
//<UICulture>ImCodeVerwendeteKultur</UICulture> in der .csproj-Datei
|
||||
//in einer <PropertyGroup> fest. Wenn Sie in den Quelldateien beispielsweise Deutsch
|
||||
//(Deutschland) verwenden, legen Sie <UICulture> auf \"de-DE\" fest. Heben Sie dann die Auskommentierung
|
||||
//des nachstehenden NeutralResourceLanguage-Attributs auf. Aktualisieren Sie "en-US" in der nachstehenden Zeile,
|
||||
//sodass es mit der UICulture-Einstellung in der Projektdatei übereinstimmt.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //Speicherort der designspezifischen Ressourcenwörterbücher
|
||||
//(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird,
|
||||
// oder in den Anwendungsressourcen-Wörterbüchern nicht gefunden werden kann.)
|
||||
ResourceDictionaryLocation.SourceAssembly //Speicherort des generischen Ressourcenwörterbuchs
|
||||
//(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird,
|
||||
// designspezifischen Ressourcenwörterbuch nicht gefunden werden kann.)
|
||||
)]
|
||||
|
||||
|
||||
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
//
|
||||
// Hauptversion
|
||||
// Nebenversion
|
||||
// Buildnummer
|
||||
// Revision
|
||||
//
|
||||
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
|
||||
// indem Sie "*" wie unten gezeigt eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
70
WpfApp1/Properties/Resources.Designer.cs
generated
Normal file
70
WpfApp1/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// Dieser Code wurde von einem Tool generiert.
|
||||
// Laufzeitversion: 4.0.30319.42000
|
||||
//
|
||||
// Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn
|
||||
// der Code erneut generiert wird.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace WpfApp1.Properties
|
||||
{
|
||||
/// <summary>
|
||||
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
|
||||
/// </summary>
|
||||
// Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse
|
||||
// über ein Tool wie ResGen oder Visual Studio automatisch generiert.
|
||||
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
|
||||
// mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfApp1.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
|
||||
/// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
WpfApp1/Properties/Resources.resx
Normal file
117
WpfApp1/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
29
WpfApp1/Properties/Settings.Designer.cs
generated
Normal file
29
WpfApp1/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace WpfApp1.Properties
|
||||
{
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
WpfApp1/Properties/Settings.settings
Normal file
7
WpfApp1/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
112
WpfApp1/WpfApp1.csproj
Normal file
112
WpfApp1/WpfApp1.csproj
Normal file
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{89252909-F8E2-4BDB-8EA9-4DA1A329545C}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>WpfApp1</RootNamespace>
|
||||
<AssemblyName>WpfApp1</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="PTConverter.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\PTConverter.Plugin.1.0.3\lib\net472\PTConverter.Plugin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="UIAutomationProvider" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="WindowsFormsIntegration" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Networking\Networking.csproj">
|
||||
<Project>{85d8795c-e9dc-4a59-b669-e2a8eeac7a9e}</Project>
|
||||
<Name>Networking</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
4
WpfApp1/packages.config
Normal file
4
WpfApp1/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="PTConverter.Plugin" version="1.0.3" targetFramework="net48" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user