diff --git a/Microsoft.Bcl.Async/CodePlexKey.snk b/Microsoft.Bcl.Async/CodePlexKey.snk new file mode 100644 index 000000000..5d44ffe87 Binary files /dev/null and b/Microsoft.Bcl.Async/CodePlexKey.snk differ diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/AsyncPlatformExtensions.WebClient.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/AsyncPlatformExtensions.WebClient.cs new file mode 100644 index 000000000..cd2e44553 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/AsyncPlatformExtensions.WebClient.cs @@ -0,0 +1,465 @@ +using System; +using System.ComponentModel; +using System.IO; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +/// +/// Provides asynchronous wrappers for .NET Framework operations. +/// +public static partial class AsyncPlatformExtensions +{ + /// Downloads the resource with the specified URI as a string, asynchronously. + /// The WebClient. + /// The URI from which to download data. + /// A Task that contains the downloaded string. + public static Task DownloadStringTaskAsync(this WebClient webClient, string address) + { + return DownloadStringTaskAsync(webClient, webClient.GetUri(address)); + } + + /// Downloads the resource with the specified URI as a string, asynchronously. + /// The WebClient. + /// The URI from which to download data. + /// A Task that contains the downloaded string. + public static Task DownloadStringTaskAsync(this WebClient webClient, Uri address) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + DownloadStringCompletedEventHandler completedHandler = null; + completedHandler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => webClient.DownloadStringCompleted -= completedHandler); + webClient.DownloadStringCompleted += completedHandler; + + // Start the async operation. + try + { + webClient.DownloadStringAsync(address, tcs); + } + catch + { + webClient.DownloadStringCompleted -= completedHandler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } + + /// Opens a readable stream for the data downloaded from a resource, asynchronously. + /// The WebClient. + /// The URI for which the stream should be opened. + /// A Task that contains the opened stream. + public static Task OpenReadTaskAsync(this WebClient webClient, string address) + { + return OpenReadTaskAsync(webClient, webClient.GetUri(address)); + } + + /// Opens a readable stream for the data downloaded from a resource, asynchronously. + /// The WebClient. + /// The URI for which the stream should be opened. + /// A Task that contains the opened stream. + public static Task OpenReadTaskAsync(this WebClient webClient, Uri address) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + OpenReadCompletedEventHandler handler = null; + handler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => webClient.OpenReadCompleted -= handler); + webClient.OpenReadCompleted += handler; + + // Start the async operation. + try { webClient.OpenReadAsync(address, tcs); } + catch + { + webClient.OpenReadCompleted -= handler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } + + /// Opens a writeable stream for uploading data to a resource, asynchronously. + /// The WebClient. + /// The URI for which the stream should be opened. + /// A Task that contains the opened stream. + public static Task OpenWriteTaskAsync(this WebClient webClient, string address) + { + return OpenWriteTaskAsync(webClient, webClient.GetUri(address), null); + } + + /// Opens a writeable stream for uploading data to a resource, asynchronously. + /// The WebClient. + /// The URI for which the stream should be opened. + /// A Task that contains the opened stream. + public static Task OpenWriteTaskAsync(this WebClient webClient, Uri address) + { + return OpenWriteTaskAsync(webClient, address, null); + } + + /// Opens a writeable stream for uploading data to a resource, asynchronously. + /// The WebClient. + /// The URI for which the stream should be opened. + /// The HTTP method that should be used to open the stream. + /// A Task that contains the opened stream. + public static Task OpenWriteTaskAsync(this WebClient webClient, string address, string method) + { + return OpenWriteTaskAsync(webClient, webClient.GetUri(address), method); + } + + /// Opens a writeable stream for uploading data to a resource, asynchronously. + /// The WebClient. + /// The URI for which the stream should be opened. + /// The HTTP method that should be used to open the stream. + /// A Task that contains the opened stream. + public static Task OpenWriteTaskAsync(this WebClient webClient, Uri address, string method) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + OpenWriteCompletedEventHandler handler = null; + handler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => webClient.OpenWriteCompleted -= handler); + webClient.OpenWriteCompleted += handler; + + // Start the async operation. + try { webClient.OpenWriteAsync(address, method, tcs); } + catch + { + webClient.OpenWriteCompleted -= handler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } + + /// Uploads data in a string to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadStringTaskAsync(this WebClient webClient, string address, string data) + { + return UploadStringTaskAsync(webClient, address, null, data); + } + + /// Uploads data in a string to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadStringTaskAsync(this WebClient webClient, Uri address, string data) + { + return UploadStringTaskAsync(webClient, address, null, data); + } + + /// Uploads data in a string to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The HTTP method that should be used to upload the data. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadStringTaskAsync(this WebClient webClient, string address, string method, string data) + { + return UploadStringTaskAsync(webClient, webClient.GetUri(address), method, data); + } + + /// Uploads data in a string to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The HTTP method that should be used to upload the data. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadStringTaskAsync(this WebClient webClient, Uri address, string method, string data) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + UploadStringCompletedEventHandler handler = null; + handler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => webClient.UploadStringCompleted -= handler); + webClient.UploadStringCompleted += handler; + + // Start the async operation. + try { webClient.UploadStringAsync(address, method, data, tcs); } + catch + { + webClient.UploadStringCompleted -= handler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } + + /// Converts a path to a Uri using the WebClient's logic. + /// Based on WebClient's private GetUri method. + private static Uri GetUri(this WebClient webClient, string path) + { + Uri uri; + var baseAddress = webClient.BaseAddress; + if (!string.IsNullOrEmpty(baseAddress)) + { + if (!Uri.TryCreate(new Uri(baseAddress), path, out uri)) + { + return new Uri(path); + + } + } + else if (!Uri.TryCreate(path, UriKind.Absolute, out uri)) + { + return new Uri(path); + } + return GetUri(webClient, uri); + } + +#if SILVERLIGHT + /// Converts a path to a Uri using the WebClient's logic. + /// Based on WebClient's private GetUri method. + private static Uri GetUri(this WebClient webClient, Uri address) + { + if (address == null) throw new ArgumentNullException("address"); + Uri result = address; + if ((!address.IsAbsoluteUri && (!string.IsNullOrEmpty(webClient.BaseAddress))) && + !Uri.TryCreate(new Uri(webClient.BaseAddress), address, out result)) + { + return address; + } + return result; + } +#else + /// Converts a path to a Uri using the WebClient's logic. + /// Based on WebClient's private GetUri method. + private static Uri GetUri(this WebClient webClient, Uri address) + { + if (address == null) throw new ArgumentNullException("address"); + + Uri result = address; + var baseAddress = webClient.BaseAddress; + if ((!address.IsAbsoluteUri && (!string.IsNullOrEmpty(baseAddress))) && !Uri.TryCreate(webClient.GetUri(baseAddress), address, out result)) + { + return address; + } + if ((result.Query != null) && !(result.Query == string.Empty)) + { + return result; + } + + var builder = new StringBuilder(); + string str = string.Empty; + var queryString = webClient.QueryString; + for (int i = 0; i < queryString.Count; i++) + { + builder.Append(str + queryString.AllKeys[i] + "=" + queryString[i]); + str = "&"; + } + return new UriBuilder(result) { Query = builder.ToString() }.Uri; + } +#endif + +#if !SILVERLIGHT + /// Downloads the resource with the specified URI as a byte array, asynchronously. + /// The WebClient. + /// The URI from which to download data. + /// A Task that contains the downloaded data. + public static Task DownloadDataTaskAsync(this WebClient webClient, string address) + { + return DownloadDataTaskAsync(webClient, webClient.GetUri(address)); + } + + /// Downloads the resource with the specified URI as a byte array, asynchronously. + /// The WebClient. + /// The URI from which to download data. + /// A Task that contains the downloaded data. + public static Task DownloadDataTaskAsync(this WebClient webClient, Uri address) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + DownloadDataCompletedEventHandler completedHandler = null; + completedHandler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => webClient.DownloadDataCompleted -= completedHandler); + webClient.DownloadDataCompleted += completedHandler; + + // Start the async operation. + try + { + webClient.DownloadDataAsync(address, tcs); + } + catch + { + webClient.DownloadDataCompleted -= completedHandler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } + + /// Downloads the resource with the specified URI to a local file, asynchronously. + /// The WebClient. + /// The URI from which to download data. + /// The name of the local file that is to receive the data. + /// A Task that contains the downloaded data. + public static Task DownloadFileTaskAsync(this WebClient webClient, string address, string fileName) + { + return DownloadFileTaskAsync(webClient, webClient.GetUri(address), fileName); + } + + /// Downloads the resource with the specified URI to a local file, asynchronously. + /// The WebClient. + /// The URI from which to download data. + /// The name of the local file that is to receive the data. + /// A Task that contains the downloaded data. + public static Task DownloadFileTaskAsync(this WebClient webClient, Uri address, string fileName) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + AsyncCompletedEventHandler completedHandler = null; + completedHandler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => null, () => + { + webClient.DownloadFileCompleted -= completedHandler; + }); + webClient.DownloadFileCompleted += completedHandler; + + // Start the async operation. + try + { + webClient.DownloadFileAsync(address, fileName, tcs); + } + catch + { + webClient.DownloadFileCompleted -= completedHandler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } + + /// Uploads data to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadDataTaskAsync(this WebClient webClient, string address, byte[] data) + { + return UploadDataTaskAsync(webClient, webClient.GetUri(address), null, data); + } + + /// Uploads data to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadDataTaskAsync(this WebClient webClient, Uri address, byte[] data) + { + return UploadDataTaskAsync(webClient, address, null, data); + } + + /// Uploads data to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The HTTP method that should be used to upload the data. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadDataTaskAsync(this WebClient webClient, string address, string method, byte[] data) + { + return UploadDataTaskAsync(webClient, webClient.GetUri(address), method, data); + } + + /// Uploads data to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the data should be uploaded. + /// The HTTP method that should be used to upload the data. + /// The data to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadDataTaskAsync(this WebClient webClient, Uri address, string method, byte[] data) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + UploadDataCompletedEventHandler handler = null; + handler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => webClient.UploadDataCompleted -= handler); + webClient.UploadDataCompleted += handler; + + // Start the async operation. + try { webClient.UploadDataAsync(address, method, data, tcs); } + catch + { + webClient.UploadDataCompleted -= handler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } + + /// Uploads a file to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the file should be uploaded. + /// A path to the file to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadFileTaskAsync(this WebClient webClient, string address, string fileName) + { + return UploadFileTaskAsync(webClient, webClient.GetUri(address), null, fileName); + } + + /// Uploads a file to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the file should be uploaded. + /// A path to the file to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadFileTaskAsync(this WebClient webClient, Uri address, string fileName) + { + return UploadFileTaskAsync(webClient, address, null, fileName); + } + + /// Uploads a file to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the file should be uploaded. + /// The HTTP method that should be used to upload the file. + /// A path to the file to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadFileTaskAsync(this WebClient webClient, string address, string method, string fileName) + { + return UploadFileTaskAsync(webClient, webClient.GetUri(address), method, fileName); + } + + /// Uploads a file to the specified resource, asynchronously. + /// The WebClient. + /// The URI to which the file should be uploaded. + /// The HTTP method that should be used to upload the file. + /// A path to the file to upload. + /// A Task containing the data in the response from the upload. + public static Task UploadFileTaskAsync(this WebClient webClient, Uri address, string method, string fileName) + { + // Create the task to be returned + var tcs = new TaskCompletionSource(address); + + // Setup the callback event handler + UploadFileCompletedEventHandler handler = null; + handler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => webClient.UploadFileCompleted -= handler); + webClient.UploadFileCompleted += handler; + + // Start the async operation. + try { webClient.UploadFileAsync(address, method, fileName, tcs); } + catch + { + webClient.UploadFileCompleted -= handler; + throw; + } + + // Return the task that represents the async operation + return tcs.Task; + } +#endif +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/AsyncPlatformExtensions.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/AsyncPlatformExtensions.cs new file mode 100644 index 000000000..7fa1de24a --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/AsyncPlatformExtensions.cs @@ -0,0 +1,693 @@ +using System; +using System.Net; +using System.Net.Mail; +using System.Net.NetworkInformation; +using System.ServiceModel.Discovery; +using System.Threading.Tasks; + +/// +/// Provides asynchronous wrappers for .NET Framework operations. +/// +public static partial class AsyncPlatformExtensions +{ + ///Causes an online announcement (Hello) message to be sent asynchronously with the specified endpoint discovery metadata and user-defined state. The specified is called when the operation completes. + ///Task instance. + ///The endpoint discovery metadata. + ///The source. + public static Task AnnounceOnlineTaskAsync(this System.ServiceModel.Discovery.AnnouncementClient source, System.ServiceModel.Discovery.EndpointDiscoveryMetadata discoveryMetadata) + { + return Task.Factory.FromAsync(source.BeginAnnounceOnline, source.EndAnnounceOnline, discoveryMetadata, null); + } + + ///Causes an offline announcement (Bye) message to be sent asynchronously with the specified endpoint discovery metadata and user-defined state. The specified is called when the operation completes. + ///Task instance. + ///The endpoint discovery metadata. + ///The source. + public static Task AnnounceOfflineTaskAsync(this System.ServiceModel.Discovery.AnnouncementClient source, System.ServiceModel.Discovery.EndpointDiscoveryMetadata discoveryMetadata) + { + return Task.Factory.FromAsync(source.BeginAnnounceOffline, source.EndAnnounceOffline, discoveryMetadata, null); + } + + ///Begins asynchronously retrieving an incoming request. + ///Task object that indicates the status of the asynchronous operation. + ///A Win32 function call failed. Check the exception's property to determine the cause of the exception. + ///This object has not been started or is currently stopped. + ///This object is closed. + ///The source. + public static Task GetContextAsync(this System.Net.HttpListener source) + { + return Task.Factory.FromAsync(source.BeginGetContext, source.EndGetContext, null); + } + + ///Starts an asynchronous request for the client's X.509 v.3 certificate. + ///Task that indicates the status of the operation. + ///The source. + public static Task GetClientCertificateAsync(this System.Net.HttpListenerRequest source) + { + return Task.Factory.FromAsync(source.BeginGetClientCertificate, source.EndGetClientCertificate, null); + } + + ///Called by clients to begin an asynchronous operation to authenticate the client, and optionally the server, in a client-server connection. This method does not block. + ///Task object indicating the status of the asynchronous operation. + ///The authentication failed. You can use this object to retry the authentication. + ///The authentication failed. You can use this object to retry the authentication. + ///This object has been closed. + ///Authentication has already occurred.- or -This stream was used previously to attempt authentication as the server. You cannot use the stream to retry authentication as the client. + ///The source. + public static Task AuthenticateAsClientAsync(this System.Net.Security.NegotiateStream source) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsClient, source.EndAuthenticateAsClient, null); + } + + ///Called by clients to begin an asynchronous operation to authenticate the client, and optionally the server, in a client-server connection. The authentication process uses the specified credentials. This method does not block. + ///Task object indicating the status of the asynchronous operation. + ///The that is used to establish the identity of the client. + ///The Service Principal Name (SPN) that uniquely identifies the server to authenticate. + /// is null.- or - is null. + ///The authentication failed. You can use this object to retry the authentication. + ///The authentication failed. You can use this object to retry the authentication. + ///This object has been closed. + ///Authentication has already occurred.- or -This stream was used previously to attempt authentication as the server. You cannot use the stream to retry authentication as the client. + ///The source. + public static Task AuthenticateAsClientAsync(this System.Net.Security.NegotiateStream source, System.Net.NetworkCredential credential, string targetName) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsClient, source.EndAuthenticateAsClient, credential, targetName, null); + } + + ///Called by clients to begin an asynchronous operation to authenticate the client, and optionally the server, in a client-server connection. The authentication process uses the specified credentials and channel binding. This method does not block. + ///Task object indicating the status of the asynchronous operation. + ///The that is used to establish the identity of the client. + ///The that is used for extended protection. + ///The Service Principal Name (SPN) that uniquely identifies the server to authenticate. + /// is null.- or - is null. + ///The authentication failed. You can use this object to retry the authentication. + ///The authentication failed. You can use this object to retry the authentication. + ///Authentication has already occurred.- or -This stream was used previously to attempt authentication as the server. You cannot use the stream to retry authentication as the client. + ///This object has been closed. + ///The source. + public static Task AuthenticateAsClientAsync(this System.Net.Security.NegotiateStream source, System.Net.NetworkCredential credential, System.Security.Authentication.ExtendedProtection.ChannelBinding binding, string targetName) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsClient, source.EndAuthenticateAsClient, credential, binding, targetName, null); + } + + ///Called by servers to begin an asynchronous operation to authenticate the client, and optionally the server, in a client-server connection. This method does not block. + ///Task object indicating the status of the asynchronous operation. + ///The authentication failed. You can use this object to retry the authentication. + ///The authentication failed. You can use this object to retry the authentication. + ///This object has been closed. + ///Windows 95 and Windows 98 are not supported. + ///The source. + public static Task AuthenticateAsServerAsync(this System.Net.Security.NegotiateStream source) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsServer, source.EndAuthenticateAsServer, null); + } + + ///Called by servers to begin an asynchronous operation to authenticate the client, and optionally the server, in a client-server connection. The authentication process uses the specified extended protection policy. This method does not block. + ///Task object indicating the status of the asynchronous operation. + ///The that is used for extended protection. + ///The and on the extended protection policy passed in the parameter are both null. + ///The authentication failed. You can use this object to retry the authentication. + ///The authentication failed. You can use this object to retry the authentication. + ///Windows 95 and Windows 98 are not supported. + ///This object has been closed. + ///The source. + public static Task AuthenticateAsServerAsync(this System.Net.Security.NegotiateStream source, System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy policy) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsServer, source.EndAuthenticateAsServer, policy, null); + } + + ///Called by servers to begin an asynchronous operation to authenticate the client, and optionally the server, in a client-server connection. The authentication process uses the specified server credentials and authentication options. This method does not block. + ///Task object indicating the status of the asynchronous operation. + ///The that is used to establish the identity of the client. + ///One of the values, indicating the security services for the stream. + ///One of the values, indicating how the server can use the client's credentials to access resources. + /// is null. + /// must be , , or , + ///The authentication failed. You can use this object to retry the authentication. + ///The authentication failed. You can use this object to retry the authentication. + ///This object has been closed. + ///Authentication has already occurred.- or -This stream was used previously to attempt authentication as the client. You cannot use the stream to retry authentication as the server. + ///Windows 95 and Windows 98 are not supported. + ///The source. + public static Task AuthenticateAsServerAsync(this System.Net.Security.NegotiateStream source, System.Net.NetworkCredential credential, System.Net.Security.ProtectionLevel requiredProtectionLevel, System.Security.Principal.TokenImpersonationLevel requiredImpersonationLevel) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsServer, source.EndAuthenticateAsServer, credential, requiredProtectionLevel, requiredImpersonationLevel, null); + } + + ///Called by clients to begin an asynchronous operation to authenticate the server and optionally the client. + ///Task object that indicates the status of the asynchronous operation. + ///The name of the server that shares this . + /// is null. + ///The authentication failed and left this object in an unusable state. + ///Authentication has already occurred.-or-Server authentication using this was tried previously.-or- Authentication is already in progress. + ///This object has been closed. + ///The source. + public static Task AuthenticateAsClientAsync(this System.Net.Security.SslStream source, string targetHost) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsClient, source.EndAuthenticateAsClient, targetHost, null); + } + + ///Called by servers to begin an asynchronous operation to authenticate the client and optionally the server in a client-server connection. + ///Task object indicating the status of the asynchronous operation. + ///The X509Certificate used to authenticate the server. + /// is null. + ///The authentication failed and left this object in an unusable state. + ///Authentication has already occurred.-or-Client authentication using this was tried previously.-or- Authentication is already in progress. + ///This object has been closed. + ///The method is not supported on Windows 95, Windows 98, or Windows Millennium. + ///The source. + public static Task AuthenticateAsServerAsync(this System.Net.Security.SslStream source, System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate) + { + return Task.Factory.FromAsync(source.BeginAuthenticateAsServer, source.EndAuthenticateAsServer, serverCertificate, null); + } + + ///Starts an asynchronous request for a remote host connection. The host is specified by a host name and a port number. + ///Task that represents the asynchronous connection. + ///The name of the remote host. + ///The port number of the remote host. + /// is null. + ///The has been closed. + ///This method is valid for sockets in the or families. + ///The port number is not valid. + ///The is ing. + /// + ///The source. + public static Task ConnectAsync(this System.Net.Sockets.TcpClient source, string hostname, int port) + { + return Task.Factory.FromAsync(source.BeginConnect, source.EndConnect, hostname, port, null); + } + + ///Starts an asynchronous request for a remote host connection. The host is specified by an and a port number. + ///Task that represents the asynchronous connection. + ///The of the remote host. + ///The port number of the remote host. + /// is null. + ///An error occurred when attempting to access the socket. See the Remarks section for more information. + ///The has been closed. + ///The is not in the socket family. + ///The port number is not valid. + ///The length of is zero. + ///The is ing. + /// + ///The source. + public static Task ConnectAsync(this System.Net.Sockets.TcpClient source, System.Net.IPAddress address, int port) + { + return Task.Factory.FromAsync(source.BeginConnect, source.EndConnect, address, port, null); + } + + ///Starts an asynchronous request for a remote host connection. The host is specified by an array and a port number. + ///Task that represents the asynchronous connections. + ///At least one , designating the remote host. + ///The port number of the remote host. + /// is null. + ///An error occurred when attempting to access the socket. See the Remarks section for more information. + ///The has been closed. + ///This method is valid for sockets that use or . + ///The port number is not valid. + ///The length of is zero. + ///The is ing. + /// + ///The source. + public static Task ConnectAsync(this System.Net.Sockets.TcpClient source, System.Net.IPAddress[] ipAddresses, int port) + { + return Task.Factory.FromAsync(source.BeginConnect, source.EndConnect, ipAddresses, port, null); + } + + ///Starts an asynchronous operation to accept an incoming connection attempt. + ///Task that represents the asynchronous creation of the . + ///An error occurred while attempting to access the socket. See the Remarks section for more information. + ///The has been closed. + /// + ///The source. + public static Task AcceptSocketAsync(this System.Net.Sockets.TcpListener source) + { + return Task.Factory.FromAsync(source.BeginAcceptSocket, source.EndAcceptSocket, null); + } + + ///Starts an asynchronous operation to accept an incoming connection attempt. + ///Task that represents the asynchronous creation of the . + ///An error occurred while attempting to access the socket. See the Remarks section for more information. + ///The has been closed. + /// + ///The source. + public static Task AcceptTcpClientAsync(this System.Net.Sockets.TcpListener source) + { + return Task.Factory.FromAsync(source.BeginAcceptTcpClient, source.EndAcceptTcpClient, null); + } + + ///Sends a datagram to a destination asynchronously. The destination is specified by a . + ///Task object that represents the asynchronous send. + ///A array that contains the data to be sent. + ///The number of bytes to send. + ///The that represents the destination for the data. + ///The source. + public static Task SendAsync(this System.Net.Sockets.UdpClient source, byte[] datagram, int bytes, System.Net.IPEndPoint endPoint) + { + return Task.Factory.FromAsync(source.BeginSend, source.EndSend, datagram, bytes, endPoint, null); + } + + ///Sends a datagram to a remote host asynchronously. The destination was specified previously by a call to . + ///Task object that represents the asynchronous send. + ///A array that contains the data to be sent. + ///The number of bytes to send. + ///The source. + public static Task SendAsync(this System.Net.Sockets.UdpClient source, byte[] datagram, int bytes) + { + return Task.Factory.FromAsync(source.BeginSend, source.EndSend, datagram, bytes, null); + } + + ///Sends a datagram to a remote host asynchronously. The destination was specified previously by a call to . + ///Task object that represents the asynchronous send. + ///A array that contains the data to be sent. + ///The number of bytes to send. + ///The host name. + ///The host name. + ///The source. + public static Task SendAsync(this System.Net.Sockets.UdpClient source, byte[] datagram, int bytes, string hostname, int port) + { + return Task.Factory.FromAsync((callback, state) => source.BeginSend(datagram, bytes, hostname, port, callback, state), source.EndSend, null); + } + + ///Starts an asynchronous request to retrieve the stable unicast IP address table on the local computer. + ///Task that represents the asynchronous request. + ///This method is not implemented on the platform. This method uses the native NotifyStableUnicastIpAddressTable function that is supported on Windows Vista and later. + ///The call to the native NotifyStableUnicastIpAddressTable function failed. + ///The source. + public static Task GetUnicastAddressesAsync(this System.Net.NetworkInformation.IPGlobalProperties source) + { + return Task.Factory.FromAsync(source.BeginGetUnicastAddresses, source.EndGetUnicastAddresses, null); + } + + /// Opens the connection asynchronously. + /// The source. + /// Task that represents the asynchronous request. + public static Task OpenAsync(this System.Data.SqlClient.SqlConnection source) + { + return OpenAsync(source, System.Threading.CancellationToken.None); + } + + /// Opens the connection asynchronously. + /// The source. + /// The cancellation token. + ///Task that represents the asynchronous request. + public static Task OpenAsync(this System.Data.SqlClient.SqlConnection source, System.Threading.CancellationToken cancellationToken) + { + return Task.Factory.StartNew(() => source.Open(), cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + } + + ///Initiates the asynchronous execution of the Transact-SQL statement or stored procedure that is described by this , given a callback procedure and state information. + ///Task that can be used to poll or wait for results, or both; this value is also needed when invoking , which returns the number of affected rows. + ///Any error that occurred while executing the command text. + ///The name/value pair "Asynchronous Processing=true" was not included within the connection string defining the connection for this . + ///2 + ///The source. + public static Task ExecuteNonQueryAsync(this System.Data.SqlClient.SqlCommand source) + { + return ExecuteNonQueryAsync(source, System.Threading.CancellationToken.None); + } + + ///Initiates the asynchronous execution of the Transact-SQL statement or stored procedure that is described by this , given a callback procedure and state information. + ///Task that can be used to poll or wait for results, or both; this value is also needed when invoking , which returns the number of affected rows. + ///Any error that occurred while executing the command text. + ///The name/value pair "Asynchronous Processing=true" was not included within the connection string defining the connection for this . + ///2 + ///The cancellation token. + ///The source. + public static Task ExecuteNonQueryAsync(this System.Data.SqlClient.SqlCommand source, System.Threading.CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + return TaskServices.FromCancellation(cancellationToken); + return Task.Factory.FromAsync(source.BeginExecuteNonQuery, source.EndExecuteNonQuery, null); + } + + ///Initiates the asynchronous execution of the Transact-SQL statement or stored procedure that is described by this and returns results as an object, using a callback procedure. + ///Task that can be used to poll, wait for results, or both; this value is also needed when the is called, which returns the results of the command as XML. + ///Any error that occurred while executing the command text. + ///The name/value pair "Asynchronous Processing=true" was not included within the connection string defining the connection for this . + ///2 + ///The source. + public static Task ExecuteXmlReaderAsync(this System.Data.SqlClient.SqlCommand source) + { + return ExecuteXmlReaderAsync(source, System.Threading.CancellationToken.None); + } + + ///Initiates the asynchronous execution of the Transact-SQL statement or stored procedure that is described by this and returns results as an object, using a callback procedure. + ///Task that can be used to poll, wait for results, or both; this value is also needed when the is called, which returns the results of the command as XML. + ///Any error that occurred while executing the command text. + ///The name/value pair "Asynchronous Processing=true" was not included within the connection string defining the connection for this . + ///2 + ///The cancellation token. + ///The source. + public static Task ExecuteXmlReaderAsync(this System.Data.SqlClient.SqlCommand source, System.Threading.CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + return TaskServices.FromCancellation(cancellationToken); + return Task.Factory.FromAsync(source.BeginExecuteXmlReader, source.EndExecuteXmlReader, null); + } + + ///Initiates the asynchronous execution of the Transact-SQL statement or stored procedure that is described by this and retrieves one or more result sets from the server, given a callback procedure and state information. + ///Task that can be used to poll, wait for results, or both; this value is also needed when invoking , which returns a instance which can be used to retrieve the returned rows. + ///Any error that occurred while executing the command text. + ///The name/value pair "Asynchronous Processing=true" was not included within the connection string defining the connection for this . + ///2 + ///The source. + public static Task ExecuteReaderAsync(this System.Data.SqlClient.SqlCommand source) + { + return ExecuteReaderAsync(source, System.Threading.CancellationToken.None); + } + + ///Initiates the asynchronous execution of the Transact-SQL statement or stored procedure that is described by this and retrieves one or more result sets from the server, given a callback procedure and state information. + ///Task that can be used to poll, wait for results, or both; this value is also needed when invoking , which returns a instance which can be used to retrieve the returned rows. + ///Any error that occurred while executing the command text. + ///The name/value pair "Asynchronous Processing=true" was not included within the connection string defining the connection for this . + ///2 + ///The cancellation token. + ///The source. + public static Task ExecuteReaderAsync(this System.Data.SqlClient.SqlCommand source, System.Threading.CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + return TaskServices.FromCancellation(cancellationToken); + return Task.Factory.FromAsync(source.BeginExecuteReader, source.EndExecuteReader, null); + } + + ///Starts an asynchronous method call that returns a . + ///The metadata. + ///The source. + public static Task GetMetadataAsync(this System.ServiceModel.Description.MetadataExchangeClient source) + { + return Task.Factory.FromAsync(source.BeginGetMetadata, source.EndGetMetadata, null); + } + + ///Starts an asynchronous method call that returns a using the specified address, callback, asynchronous state, and download mechanism. + ///The metadata obtained from the specified . + ///The address of the metadata. + ///The value to use when downloading the metadata. + ///The source. + public static Task GetMetadataAsync(this System.ServiceModel.Description.MetadataExchangeClient source, System.Uri address, System.ServiceModel.Description.MetadataExchangeClientMode mode) + { + return Task.Factory.FromAsync(source.BeginGetMetadata, source.EndGetMetadata, address, mode, null); + } + + ///Starts an asynchronous method call that returns a using the specified address, callback, and asynchronous state. + ///The metadata obtained from the specified . + ///The address of the metadata. + ///The source. + public static Task GetMetadataAsync(this System.ServiceModel.Description.MetadataExchangeClient source, System.ServiceModel.EndpointAddress address) + { + return Task.Factory.FromAsync(source.BeginGetMetadata, source.EndGetMetadata, address, null); + } + + /// + /// Begins an asynchronous find operation with the specified criteria. + /// + /// The discovery client. + /// The criteria for finding services. + /// A Task that represents the asynchronous operation. + public static Task FindTaskAsync( + this DiscoveryClient discoveryClient, FindCriteria criteria) + { + // Validate arguments + if (discoveryClient == null) throw new ArgumentNullException("discoveryClient"); + + // Create a TaskCompletionSource to represent the operation + var tcs = new TaskCompletionSource(discoveryClient); + + // Register a handler that will transfer completion results to the TCS Task + EventHandler completedHandler = null; + completedHandler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => discoveryClient.FindCompleted -= completedHandler); + discoveryClient.FindCompleted += completedHandler; + + // Start the async operation. + try { discoveryClient.FindAsync(criteria, tcs); } + catch + { + discoveryClient.FindCompleted -= completedHandler; + throw; + } + + // Return the task to represent the asynchronous operation + return tcs.Task; + } + + /// + /// Begins an asynchronous resolve operation with the specified criteria. + /// + /// The discovery client. + /// The criteria for matching a service endpoint. + /// A Task that represents the asynchronous operation. + public static Task ResolveTaskAsync( + this DiscoveryClient discoveryClient, ResolveCriteria criteria) + { + // Validate arguments + if (discoveryClient == null) throw new ArgumentNullException("discoveryClient"); + + // Create a TaskCompletionSource to represent the operation + var tcs = new TaskCompletionSource(discoveryClient); + + // Register a handler that will transfer completion results to the TCS Task + EventHandler completedHandler = null; + completedHandler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Result, () => discoveryClient.ResolveCompleted -= completedHandler); + discoveryClient.ResolveCompleted += completedHandler; + + // Start the async operation. + try { discoveryClient.ResolveAsync(criteria, tcs); } + catch + { + discoveryClient.ResolveCompleted -= completedHandler; + throw; + } + + // Return the task to represent the asynchronous operation + return tcs.Task; + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// An IPAddress that identifies the computer that is the destination for the ICMP echo message. + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, IPAddress address) + { + return SendTaskAsyncCore(ping, address, tcs => ping.SendAsync(address, tcs)); + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// + /// A String that identifies the computer that is the destination for the ICMP echo message. + /// The value specified for this parameter can be a host name or a string representation of an IP address. + /// + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, string hostNameOrAddress) + { + return SendTaskAsyncCore(ping, hostNameOrAddress, tcs => ping.SendAsync(hostNameOrAddress, tcs)); + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// An IPAddress that identifies the computer that is the destination for the ICMP echo message. + /// + /// An Int32 value that specifies the maximum number of milliseconds (after sending the echo message) + /// to wait for the ICMP echo reply message. + /// + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, IPAddress address, int timeout) + { + return SendTaskAsyncCore(ping, address, tcs => ping.SendAsync(address, timeout, tcs)); + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// + /// A String that identifies the computer that is the destination for the ICMP echo message. + /// The value specified for this parameter can be a host name or a string representation of an IP address. + /// + /// + /// An Int32 value that specifies the maximum number of milliseconds (after sending the echo message) + /// to wait for the ICMP echo reply message. + /// + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, string hostNameOrAddress, int timeout) + { + return SendTaskAsyncCore(ping, hostNameOrAddress, tcs => ping.SendAsync(hostNameOrAddress, timeout, tcs)); + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// An IPAddress that identifies the computer that is the destination for the ICMP echo message. + /// + /// An Int32 value that specifies the maximum number of milliseconds (after sending the echo message) + /// to wait for the ICMP echo reply message. + /// + /// + /// A Byte array that contains data to be sent with the ICMP echo message and returned + /// in the ICMP echo reply message. The array cannot contain more than 65,500 bytes. + /// + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, IPAddress address, int timeout, byte[] buffer) + { + return SendTaskAsyncCore(ping, address, tcs => ping.SendAsync(address, timeout, buffer, tcs)); + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// + /// A String that identifies the computer that is the destination for the ICMP echo message. + /// The value specified for this parameter can be a host name or a string representation of an IP address. + /// + /// + /// An Int32 value that specifies the maximum number of milliseconds (after sending the echo message) + /// to wait for the ICMP echo reply message. + /// + /// + /// A Byte array that contains data to be sent with the ICMP echo message and returned + /// in the ICMP echo reply message. The array cannot contain more than 65,500 bytes. + /// + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, string hostNameOrAddress, int timeout, byte[] buffer) + { + return SendTaskAsyncCore(ping, hostNameOrAddress, tcs => ping.SendAsync(hostNameOrAddress, timeout, buffer, tcs)); + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// An IPAddress that identifies the computer that is the destination for the ICMP echo message. + /// + /// An Int32 value that specifies the maximum number of milliseconds (after sending the echo message) + /// to wait for the ICMP echo reply message. + /// + /// + /// A Byte array that contains data to be sent with the ICMP echo message and returned + /// in the ICMP echo reply message. The array cannot contain more than 65,500 bytes. + /// + /// A PingOptions object used to control fragmentation and Time-to-Live values for the ICMP echo message packet. + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, IPAddress address, int timeout, byte[] buffer, PingOptions options) + { + return SendTaskAsyncCore(ping, address, tcs => ping.SendAsync(address, timeout, buffer, options, tcs)); + } + + /// + /// Asynchronously attempts to send an Internet Control Message Protocol (ICMP) echo message. + /// + /// The Ping. + /// + /// A String that identifies the computer that is the destination for the ICMP echo message. + /// The value specified for this parameter can be a host name or a string representation of an IP address. + /// + /// + /// An Int32 value that specifies the maximum number of milliseconds (after sending the echo message) + /// to wait for the ICMP echo reply message. + /// + /// + /// A Byte array that contains data to be sent with the ICMP echo message and returned + /// in the ICMP echo reply message. The array cannot contain more than 65,500 bytes. + /// + /// A PingOptions object used to control fragmentation and Time-to-Live values for the ICMP echo message packet. + /// A task that represents the asynchronous operation. + public static Task SendTaskAsync(this Ping ping, string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options) + { + return SendTaskAsyncCore(ping, hostNameOrAddress, tcs => ping.SendAsync(hostNameOrAddress, timeout, buffer, options, tcs)); + } + + /// The core implementation of SendTaskAsync. + /// The Ping. + /// A user-defined object stored in the resulting Task. + /// + /// A delegate that initiates the asynchronous send. + /// The provided TaskCompletionSource must be passed as the user-supplied state to the actual Ping.SendAsync method. + /// + /// + private static Task SendTaskAsyncCore(Ping ping, object userToken, Action> sendAsync) + { + // Validate arguments + if (ping == null) throw new ArgumentNullException("ping"); + + // Create a TaskCompletionSource to represent the operation + var tcs = new TaskCompletionSource(userToken); + + // Register a handler that will transfer completion results to the TCS Task + PingCompletedEventHandler handler = null; + handler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => e.Reply, () => ping.PingCompleted -= handler); + ping.PingCompleted += handler; + + // Start the async operation. + try { sendAsync(tcs); } + catch + { + ping.PingCompleted -= handler; + throw; + } + + // Return the task to represent the asynchronous operation + return tcs.Task; + } + + /// Sends an e-mail message asynchronously. + /// The client. + /// A String that contains the address information of the message sender. + /// A String that contains the address that the message is sent to. + /// A String that contains the subject line for the message. + /// A String that contains the message body. + /// A Task that represents the asynchronous send. + public static Task SendTaskAsync(this SmtpClient smtpClient, string from, string recipients, string subject, string body) + { + var message = new MailMessage(from, recipients, subject, body); + return SendTaskAsync(smtpClient, message); + } + + /// Sends an e-mail message asynchronously. + /// The client. + /// A MailMessage that contains the message to send. + /// A Task that represents the asynchronous send. + public static Task SendTaskAsync(this SmtpClient smtpClient, MailMessage message) + { + return SendTaskAsyncCore(smtpClient, message, tcs => smtpClient.SendAsync(message, tcs)); + } + + /// The core implementation of SendTaskAsync. + /// The client. + /// The user-supplied state. + /// + /// A delegate that initiates the asynchronous send. + /// The provided TaskCompletionSource must be passed as the user-supplied state to the actual SmtpClient.SendAsync method. + /// + /// + private static Task SendTaskAsyncCore(SmtpClient smtpClient, object userToken, Action> sendAsync) + { + // Validate arguments + if (smtpClient == null) throw new ArgumentNullException("smtpClient"); + + // Create a TaskCompletionSource to represent the operation + var tcs = new TaskCompletionSource(userToken); + + // Register a handler that will transfer completion results to the TCS Task + SendCompletedEventHandler handler = null; + handler = (sender, e) => TaskServices.HandleEapCompletion(tcs, true, e, () => null, () => smtpClient.SendCompleted -= handler); + smtpClient.SendCompleted += handler; + + // Start the async operation. + try { sendAsync(tcs); } + catch + { + smtpClient.SendCompleted -= handler; + throw; + } + + // Return the task to represent the asynchronous operation + return tcs.Task; + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Microsoft.Threading.Tasks.Extensions.Desktop.csproj b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Microsoft.Threading.Tasks.Extensions.Desktop.csproj new file mode 100644 index 000000000..80c6abae5 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Microsoft.Threading.Tasks.Extensions.Desktop.csproj @@ -0,0 +1,92 @@ + + + + + Debug + AnyCPU + {9D4342DE-EF5A-4ACF-8AFC-0C777D23577B} + Library + Properties + System + Microsoft.Threading.Tasks.Extensions.Desktop + v4.0 + 512 + SAK + SAK + SAK + SAK + ..\..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Microsoft.Threading.Tasks.Extensions.Desktop.xml + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Microsoft.Threading.Tasks.Extensions.Desktop.xml + + + true + true + ..\CodePlexKey.snk + + + + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\net40\System.Runtime.dll + + + + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\net40\System.Threading.Tasks.dll + + + + + + + + + + + Threading\Tasks\TaskServices.cs + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Microsoft.Threading.Tasks.Extensions.Desktop.csproj.vspscc b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Microsoft.Threading.Tasks.Extensions.Desktop.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Microsoft.Threading.Tasks.Extensions.Desktop.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Net/DnsEx.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Net/DnsEx.cs new file mode 100644 index 000000000..f963007bd --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Net/DnsEx.cs @@ -0,0 +1,33 @@ +using System; +using System.Threading.Tasks; + +namespace System.Net +{ + /// Provides asynchronous wrappers for the class. + public static class DnsEx + { + /// Asynchronously returns the Internet Protocol (IP) addresses for the specified host. + /// The host name or IP address to resolve. + /// An array of type System.Net.IPAddress that holds the IP addresses for the host specified. + public static Task GetHostAddressesAsync(string hostNameOrAddress) + { + return Task.Factory.FromAsync(Dns.BeginGetHostAddresses, Dns.EndGetHostAddresses, hostNameOrAddress, null); + } + + /// Asynchronously resolves an IP address to an System.Net.IPHostEntry instance. + /// The IP address to resolve. + /// An System.Net.IPHostEntry instance that contains address information about the host. + public static Task GetHostEntryAsync(IPAddress address) + { + return Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, address, null); + } + + /// Asynchronously resolves an IP address to an System.Net.IPHostEntry instance. + /// The host name or IP address to resolve. + /// An System.Net.IPHostEntry instance that contains address information about the host. + public static Task GetHostEntryAsync(string hostNameOrAddress) + { + return Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, hostNameOrAddress, null); + } + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Properties/AssemblyInfo.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..beda9c649 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.Threading.Tasks.Extensions.Desktop")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("Microsoft.Threading.Tasks.Extensions.Desktop")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/app.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/app.config new file mode 100644 index 000000000..a6a2b7fa9 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/app.config @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/packages.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/packages.config new file mode 100644 index 000000000..92ec9f85a --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Desktop/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Microsoft.Threading.Tasks.Extensions.Phone.csproj b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Microsoft.Threading.Tasks.Extensions.Phone.csproj new file mode 100644 index 000000000..72879d885 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Microsoft.Threading.Tasks.Extensions.Phone.csproj @@ -0,0 +1,101 @@ + + + + Debug + AnyCPU + 10.0.20506 + 2.0 + {AECCDA63-2C7E-4F94-B609-BA552C619EB3} + {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Microsoft.Threading.Tasks.Phone + Microsoft.Threading.Tasks.Extensions.Phone + v4.0 + $(TargetFrameworkVersion) + WindowsPhone71 + Silverlight + false + false + true + SAK + SAK + SAK + SAK + ..\..\ + true + true + + + true + full + false + Bin\Debug + TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + Bin\Debug\Microsoft.Threading.Tasks.Extensions.Phone.xml + + + pdbonly + true + Bin\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + Bin\Release\Microsoft.Threading.Tasks.Extensions.Phone.xml + + + true + true + ..\CodePlexKey.snk + + + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\sl4-windowsphone71\System.Runtime.dll + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\sl4-windowsphone71\System.Threading.Tasks.dll + + + + + + + AsyncPlatformExtensions.WebClient.cs + + + AsyncPlatformExtensions.Dispatcher.cs + + + Threading\Tasks\TaskServices.cs + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Microsoft.Threading.Tasks.Extensions.Phone.csproj.vspscc b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Microsoft.Threading.Tasks.Extensions.Phone.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Microsoft.Threading.Tasks.Extensions.Phone.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Properties/AssemblyInfo.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..2ead716a2 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.Threading.Tasks.Extensions.Phone")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("Microsoft.Threading.Tasks.Extensions.Phone")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/app.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/app.config new file mode 100644 index 000000000..a6a2b7fa9 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/app.config @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/packages.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/packages.config new file mode 100644 index 000000000..52dc8d017 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Phone/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/AsyncPlatformExtensions.Dispatcher.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/AsyncPlatformExtensions.Dispatcher.cs new file mode 100644 index 000000000..c7006ca23 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/AsyncPlatformExtensions.Dispatcher.cs @@ -0,0 +1,63 @@ +using System; +using System.Net; +using System.Threading.Tasks; +using System.Windows; + +/// +/// Provides asynchronous wrappers for .NET Framework operations. +/// +public static partial class AsyncPlatformExtensions +{ + /// Asynchronously invokes an Action on the Dispatcher. + /// The Dispatcher. + /// The action to invoke. + /// A Task that represents the execution of the action. + public static Task InvokeAsync(this System.Windows.Threading.Dispatcher dispatcher, Action action) + { + if (dispatcher == null) throw new ArgumentNullException("dispatcher"); + if (action == null) throw new ArgumentNullException("action"); + + var tcs = new TaskCompletionSource(); + dispatcher.BeginInvoke(new Action(() => + { + try + { + action(); + tcs.TrySetResult(default(VoidTaskResult)); + } + catch (Exception exc) + { + tcs.TrySetException(exc); + } + })); + return tcs.Task; + } + + /// Asynchronously invokes an Action on the Dispatcher. + /// The Dispatcher. + /// The function to invoke. + /// A Task that represents the execution of the function. + public static Task InvokeAsync(this System.Windows.Threading.Dispatcher dispatcher, Func function) + { + if (dispatcher == null) throw new ArgumentNullException("dispatcher"); + if (function == null) throw new ArgumentNullException("function"); + + var tcs = new TaskCompletionSource(); + dispatcher.BeginInvoke(new Action(() => + { + try + { + var result = function(); + tcs.TrySetResult(result); + } + catch (Exception exc) + { + tcs.TrySetException(exc); + } + })); + return tcs.Task; + } +} + +/// Used with Task(of void) +internal struct VoidTaskResult { } diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Microsoft.Threading.Tasks.Extensions.Silverlight.csproj b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Microsoft.Threading.Tasks.Extensions.Silverlight.csproj new file mode 100644 index 000000000..fd6ad617b --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Microsoft.Threading.Tasks.Extensions.Silverlight.csproj @@ -0,0 +1,108 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {E4616E51-1FE7-4007-B85E-B6108FD2F0D1} + {A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Microsoft + Microsoft.Threading.Tasks.Extensions.Silverlight + Silverlight + v4.0 + $(TargetFrameworkVersion) + false + true + true + SAK + SAK + SAK + SAK + + ..\..\ + true + + + + v3.5 + + + true + full + false + Bin\Debug + DEBUG;TRACE;SILVERLIGHT + true + true + prompt + 4 + Bin\Debug\Microsoft.Threading.Tasks.Extensions.Silverlight.xml + + + pdbonly + true + Bin\Release + TRACE;SILVERLIGHT + true + true + prompt + 4 + Bin\Release\Microsoft.Threading.Tasks.Extensions.Silverlight.xml + + + true + true + ..\CodePlexKey.snk + + + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\sl4\System.Runtime.dll + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\sl4\System.Threading.Tasks.dll + + + + + $(TargetFrameworkDirectory)System.Core.dll + + + + + + + + AsyncPlatformExtensions.WebClient.cs + + + Threading\Tasks\TaskServices.cs + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Microsoft.Threading.Tasks.Extensions.Silverlight.csproj.vspscc b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Microsoft.Threading.Tasks.Extensions.Silverlight.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Microsoft.Threading.Tasks.Extensions.Silverlight.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Properties/AssemblyInfo.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..283df850c --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.Threading.Tasks.Extensions.Silverlight")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("Microsoft.Threading.Tasks.Extensions.Silverlight")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/app.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/app.config new file mode 100644 index 000000000..a6a2b7fa9 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/app.config @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/packages.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/packages.config new file mode 100644 index 000000000..83ce40645 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions.Silverlight/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/AsyncExtensions.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/AsyncExtensions.cs new file mode 100644 index 000000000..6d840c9fe --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/AsyncExtensions.cs @@ -0,0 +1,363 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +/// +/// Provides asynchronous wrappers for .NET Framework operations. +/// +public static partial class AsyncExtensions +{ + /// + ///Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + ///A Task that represents the asynchronous read. + ///The source. + ///The buffer to read data into. + ///The byte offset in at which to begin reading. + ///The maximum number of bytes to read. + ///The array length minus is less than . + /// is null. + /// or is negative. + ///An asynchronous read was attempted past the end of the file. + public static Task ReadAsync(this System.IO.Stream source, byte[] buffer, int offset, int count) + { + return ReadAsync(source, buffer, offset, count, System.Threading.CancellationToken.None); + } + + /// + ///Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + ///A Task that represents the asynchronous read. + ///The source. + ///The buffer to read data into. + ///The byte offset in at which to begin reading. + ///The maximum number of bytes to read. + /// The cancellation token. + ///The array length minus is less than . + /// is null. + /// or is negative. + ///An asynchronous read was attempted past the end of the file. + public static Task ReadAsync(this System.IO.Stream source, byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + return TaskServices.FromCancellation(cancellationToken); + return Task.Factory.FromAsync(source.BeginRead, source.EndRead, buffer, offset, count, null); + } + + /// + ///Writes asynchronously a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + ///A Task that represents the asynchronous write. + ///The source. + ///The buffer containing data to write to the current stream. + ///The zero-based byte offset in at which to begin copying bytes to the current stream. + ///The maximum number of bytes to write. + /// length minus is less than . + /// is null. + /// or is negative. + ///The stream does not support writing. + ///The stream is closed. + ///An I/O error occurred. + public static Task WriteAsync(this System.IO.Stream source, byte[] buffer, int offset, int count) + { + return WriteAsync(source, buffer, offset, count, System.Threading.CancellationToken.None); + } + + /// + ///Writes asynchronously a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + ///A Task that represents the asynchronous write. + ///The source. + ///The buffer containing data to write to the current stream. + ///The zero-based byte offset in at which to begin copying bytes to the current stream. + ///The maximum number of bytes to write. + /// The cancellation token. + /// length minus is less than . + /// is null. + /// or is negative. + ///The stream does not support writing. + ///The stream is closed. + ///An I/O error occurred. + public static Task WriteAsync(this System.IO.Stream source, byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + return TaskServices.FromCancellation(cancellationToken); + return Task.Factory.FromAsync(source.BeginWrite, source.EndWrite, buffer, offset, count, null); + } + + /// + ///Flushes asynchronously the current stream. + /// + ///A Task that represents the asynchronous flush. + public static Task FlushAsync(this System.IO.Stream source) + { + return FlushAsync(source, System.Threading.CancellationToken.None); + } + + /// + ///Flushes asynchronously the current stream. + /// + ///A Task that represents the asynchronous flush. + public static Task FlushAsync(this System.IO.Stream source, System.Threading.CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + return TaskServices.FromCancellation(cancellationToken); + return Task.Factory.StartNew(s => ((System.IO.Stream)s).Flush(), source, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// + /// Reads all the bytes from the current stream and writes them to the destination stream. + /// + /// The source stream. + /// The stream that will contain the contents of the current stream. + /// A Task that represents the asynchronous operation. + public static Task CopyToAsync(this Stream source, Stream destination) + { + return CopyToAsync(source, destination, 0x1000); + } + + /// + /// Reads all the bytes from the current stream and writes them to the destination stream. + /// + /// The source stream. + /// The stream that will contain the contents of the current stream. + /// The size of the buffer. This value must be greater than zero. The default size is 4096. + /// A Task that represents the asynchronous operation. + public static Task CopyToAsync(this Stream source, Stream destination, int bufferSize) + { + return CopyToAsync(source, destination, bufferSize, CancellationToken.None); + } + + /// + /// Reads all the bytes from the current stream and writes them to the destination stream. + /// + /// The source stream. + /// The stream that will contain the contents of the current stream. + /// The size of the buffer. This value must be greater than zero. The default size is 4096. + /// The cancellation token to use to cancel the asynchronous operation. + /// A Task that represents the asynchronous operation. + public static Task CopyToAsync(this Stream source, Stream destination, int bufferSize, CancellationToken cancellationToken) + { + if (source == null) throw new ArgumentNullException("source"); + if (destination == null) throw new ArgumentNullException("destination"); + if (bufferSize <= 0) throw new ArgumentOutOfRangeException("bufferSize"); + if (!source.CanRead && !source.CanWrite) throw new ObjectDisposedException("source"); + if (!destination.CanRead && !destination.CanWrite) throw new ObjectDisposedException("destination"); + if (!source.CanRead) throw new NotSupportedException(); + if (!destination.CanWrite) throw new NotSupportedException(); + + return CopyToAsyncInternal(source, destination, bufferSize, cancellationToken); + } + + /// + /// Reads all the bytes from the current stream and writes them to the destination stream. + /// + /// The source stream. + /// The stream that will contain the contents of the current stream. + /// The size of the buffer. This value must be greater than zero. The default size is 4096. + /// The cancellation token to use to cancel the asynchronous operation. + /// A Task that represents the asynchronous operation. + private static async Task CopyToAsyncInternal(this Stream source, Stream destination, int bufferSize, CancellationToken cancellationToken) + { + byte[] buffer = new byte[bufferSize]; + int bytesRead; + while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0) + { + await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); + } + } + + /// + /// Reads a maximum of count characters from the reader asynchronously and writes + /// the data to buffer, beginning at index. + /// + /// + /// When the operation completes, contains the specified character array with the + /// values between index and (index + count - 1) replaced by the characters read + /// from the current source. + /// + /// + /// The maximum number of characters to read. If the end of the stream is reached + /// before count of characters is read into buffer, the current method returns. + /// + /// The place in buffer at which to begin writing. + /// the source reader. + /// A Task that represents the asynchronous operation. + public static Task ReadAsync(this TextReader source, char[] buffer, int index, int count) + { + if (source == null) throw new ArgumentNullException("source"); + return Task.Factory.StartNew(() => source.Read(buffer, index, count), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// + /// Reads asynchronously a maximum of count characters from the current stream, and writes the + /// data to buffer, beginning at index. + /// + /// The source reader. + /// + /// When this method returns, this parameter contains the specified character + /// array with the values between index and (index + count -1) replaced by the + /// characters read from the current source. + /// + /// The position in buffer at which to begin writing. + /// The maximum number of characters to read. + /// A Task that represents the asynchronous operation. + public static Task ReadBlockAsync(this TextReader source, char[] buffer, int index, int count) + { + if (source == null) throw new ArgumentNullException("source"); + return Task.Factory.StartNew(() => source.ReadBlock(buffer, index, count), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// + /// Reads a line of characters from the reader and returns the string asynchronously. + /// + /// the source reader. + /// A Task that represents the asynchronous operation. + public static Task ReadLineAsync(this TextReader source) + { + if (source == null) throw new ArgumentNullException("source"); + return Task.Factory.StartNew(() => source.ReadLine(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// + /// Reads all characters from the current position to the end of the TextReader + /// and returns them as one string asynchronously. + /// + /// the source reader. + /// A Task that represents the asynchronous operation. + public static Task ReadToEndAsync(this TextReader source) + { + if (source == null) throw new ArgumentNullException("source"); + return Task.Factory.StartNew(() => source.ReadToEnd(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Writes a string asynchronously to a text stream. + /// The writer. + /// The string to write. + /// A Task representing the asynchronous write. + public static Task WriteAsync(this TextWriter target, string value) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.Write(value), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Writes a char asynchronously to a text stream. + /// The writer. + /// The char to write. + /// A Task representing the asynchronous write. + public static Task WriteAsync(this TextWriter target, char value) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.Write(value), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Writes a char array asynchronously to a text stream. + /// The writer. + /// The buffer to write. + /// A Task representing the asynchronous write. + public static Task WriteAsync(this TextWriter target, char[] buffer) + { + return WriteAsync(target, buffer, 0, buffer.Length); + } + + /// Writes a subarray of characters asynchronously to a text stream. + /// The writer. + /// The buffer to write. + /// Starting index in the buffer. + /// The number of characters to write. + /// A Task representing the asynchronous write. + public static Task WriteAsync(this TextWriter target, char[] buffer, int index, int count) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.Write(buffer, index, count), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Writes a line terminator asynchronously to a text stream. + /// The writer. + /// A Task representing the asynchronous write. + public static Task WriteLineAsync(this TextWriter target) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.WriteLine(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Writes a string followed by a line terminator asynchronously to a text stream. + /// The writer. + /// The string to write. + /// A Task representing the asynchronous write. + public static Task WriteLineAsync(this TextWriter target, string value) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.WriteLine(value), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Writes a char followed by a line terminator asynchronously to a text stream. + /// The writer. + /// The char to write. + /// A Task representing the asynchronous write. + public static Task WriteLineAsync(this TextWriter target, char value) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.WriteLine(value), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Writes a char array followed by a line terminator asynchronously to a text stream. + /// The writer. + /// The buffer to write. + /// A Task representing the asynchronous write. + public static Task WriteLineAsync(this TextWriter target, char[] buffer) + { + return WriteLineAsync(target, buffer, 0, buffer.Length); + } + + /// Writes a subarray of characters followed by a line terminator asynchronously to a text stream. + /// The writer. + /// The buffer to write. + /// Starting index in the buffer. + /// The number of characters to write. + /// A Task representing the asynchronous write. + public static Task WriteLineAsync(this TextWriter target, char[] buffer, int index, int count) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.WriteLine(buffer, index, count), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// + /// Clears all buffers for the current writer and causes any buffered data to + /// be written to the underlying device. + /// + /// The writer. + /// A Task representing the asynchronous flush. + public static Task FlushAsync(this TextWriter target) + { + if (target == null) throw new ArgumentNullException("target"); + return Task.Factory.StartNew(() => target.Flush(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + ///Starts an asynchronous request for a web resource. + ///Task that represents the asynchronous request. + ///The stream is already in use by a previous call to . + /// + ///The source. + public static Task GetResponseAsync(this System.Net.WebRequest source) + { + return Task.Factory.StartNew(() => + Task.Factory.FromAsync(source.BeginGetResponse, source.EndGetResponse, null), + CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); + } + + ///Starts an asynchronous request for a object to use to write data. + ///Task that represents the asynchronous request. + ///The property is GET and the application writes to the stream. + ///The stream is being used by a previous call to . + ///No write stream is available. + /// + ///The source. + public static Task GetRequestStreamAsync(this System.Net.WebRequest source) + { + return Task.Factory.StartNew(() => + Task.Factory.FromAsync(source.BeginGetRequestStream, source.EndGetRequestStream, null), + CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Microsoft.Threading.Tasks.Extensions.csproj b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Microsoft.Threading.Tasks.Extensions.csproj new file mode 100644 index 000000000..2bbdb4bca --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Microsoft.Threading.Tasks.Extensions.csproj @@ -0,0 +1,89 @@ + + + + + 10.0 + Debug + AnyCPU + {D9B6763A-CDAA-47F0-A227-3CA12C3C7FA6} + Library + Properties + System + Microsoft.Threading.Tasks.Extensions + v4.0 + Profile88 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + ..\..\ + true + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NO_TIMER_ROOT + prompt + 4 + bin\Debug\Microsoft.Threading.Tasks.Extensions.xml + + + pdbonly + true + bin\Release\ + TRACE;NO_TIMER_ROOT + prompt + 4 + bin\Release\Microsoft.Threading.Tasks.Extensions.xml + + + true + true + ..\CodePlexKey.snk + + + + Threading\Tasks\TaskServices.cs + + + + + + + {b27b5e06-fd10-427a-96e3-770c6a1268d6} + Microsoft.Threading.Tasks + + + + + + + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\portable-net40+sl4+win8+wp71\System.Runtime.dll + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\portable-net40+sl4+win8+wp71\System.Threading.Tasks.dll + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Microsoft.Threading.Tasks.Extensions.csproj.vspscc b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Microsoft.Threading.Tasks.Extensions.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Microsoft.Threading.Tasks.Extensions.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Properties/AssemblyInfo.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..56e0e5757 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.Threading.Tasks.Extensions")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("Microsoft.Threading.Tasks.Extensions")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/app.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/app.config new file mode 100644 index 000000000..a6a2b7fa9 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/app.config @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/packages.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/packages.config new file mode 100644 index 000000000..2384716da --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks.Extensions/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/AwaitExtensions.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/AwaitExtensions.cs new file mode 100644 index 000000000..5876f47d0 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/AwaitExtensions.cs @@ -0,0 +1,89 @@ +using System; +using System.Diagnostics.Contracts; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.CompilerServices; +using Microsoft.Runtime.CompilerServices; + +/// +/// Provides extension methods for threading-related types. +/// +public static class AwaitExtensions +{ + /// Cancels the after the specified duration. + /// The CancellationTokenSource. + /// The due time in milliseconds for the source to be canceled. + public static void CancelAfter(this CancellationTokenSource source, int dueTime) + { + if (source == null) throw new NullReferenceException(); + if (dueTime < -1) throw new ArgumentOutOfRangeException("dueTime"); + Contract.EndContractBlock(); + + Timer timer = null; + timer = new Timer(state => + { + ((IDisposable)timer).Dispose(); + TimerManager.Remove(timer); + try { source.Cancel(); } + catch (ObjectDisposedException) { } + }, null, Timeout.Infinite, Timeout.Infinite); + + TimerManager.Add(timer); + timer.Change(dueTime, Timeout.Infinite); + } + + /// Cancels the after the specified duration. + /// The CancellationTokenSource. + /// The due time for the source to be canceled. + public static void CancelAfter(this CancellationTokenSource source, TimeSpan dueTime) + { + long milliseconds = (long)dueTime.TotalMilliseconds; + if (milliseconds < -1 || milliseconds > Int32.MaxValue) throw new ArgumentOutOfRangeException("dueTime"); + CancelAfter(source, (int)milliseconds); + } + + /// Gets an awaiter used to await this . + /// The task to await. + /// An awaiter instance. + public static TaskAwaiter GetAwaiter(this Task task) + { + if (task == null) throw new ArgumentNullException("task"); + return new TaskAwaiter(task); + } + + /// Gets an awaiter used to await this . + /// Specifies the type of data returned by the task. + /// The task to await. + /// An awaiter instance. + public static TaskAwaiter GetAwaiter(this Task task) + { + if (task == null) throw new ArgumentNullException("task"); + return new TaskAwaiter(task); + } + + /// Creates and configures an awaitable object for awaiting the specified task. + /// The task to be awaited. + /// + /// true to automatic marshag back to the original call site's current SynchronizationContext + /// or TaskScheduler; otherwise, false. + /// + /// The instance to be awaited. + public static ConfiguredTaskAwaitable ConfigureAwait(this Task task, bool continueOnCapturedContext) + { + if (task == null) throw new ArgumentNullException("task"); + return new ConfiguredTaskAwaitable(task, continueOnCapturedContext); + } + + /// Creates and configures an awaitable object for awaiting the specified task. + /// The task to be awaited. + /// + /// true to automatic marshag back to the original call site's current SynchronizationContext + /// or TaskScheduler; otherwise, false. + /// + /// The instance to be awaited. + public static ConfiguredTaskAwaitable ConfigureAwait(this Task task, bool continueOnCapturedContext) + { + if (task == null) throw new ArgumentNullException("task"); + return new ConfiguredTaskAwaitable(task, continueOnCapturedContext); + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Diagnostics/Contracts/Contract.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Diagnostics/Contracts/Contract.cs new file mode 100644 index 000000000..523d0f36d --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Diagnostics/Contracts/Contract.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace System.Diagnostics.Contracts +{ + internal class Contract + { + public static void Assert(bool condition, string message = null) + { + Debug.Assert(condition, message); + } + + public static void EndContractBlock() + { + } + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Microsoft.Threading.Tasks.csproj b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Microsoft.Threading.Tasks.csproj new file mode 100644 index 000000000..ba664dfb0 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Microsoft.Threading.Tasks.csproj @@ -0,0 +1,91 @@ + + + + + 10.0 + Debug + AnyCPU + {B27B5E06-FD10-427A-96E3-770C6A1268D6} + Library + Properties + System + Microsoft.Threading.Tasks + v4.0 + Profile88 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + ..\..\ + true + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NO_TIMER_ROOT + prompt + 4 + bin\Debug\Microsoft.Threading.Tasks.xml + + + pdbonly + true + bin\Release\ + TRACE;NO_TIMER_ROOT + prompt + 4 + bin\Release\Microsoft.Threading.Tasks.xml + + + true + true + ..\CodePlexKey.snk + + + + + + + + + + + + + + + + + + + + + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\portable-net40+sl4+win8+wp71\System.Runtime.dll + + + ..\..\packages\Microsoft.Bcl.1.0.19\lib\portable-net40+sl4+win8+wp71\System.Threading.Tasks.dll + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Microsoft.Threading.Tasks.csproj.vspscc b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Microsoft.Threading.Tasks.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Microsoft.Threading.Tasks.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Progress.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Progress.cs new file mode 100644 index 000000000..b00620568 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Progress.cs @@ -0,0 +1,108 @@ +// NOTE: Although this looks very similar to the Progress class available in the framework, the reason this is here is due to the lack of ability to make this +// compatible due to EventHandler difference. Note that in 4.0, EventHandler has a constraint on EventArgs, in 4.5 we removed it. +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; +using System.Threading; + +namespace Microsoft +{ + /// Event handler for progress reports. + /// Specifies the type of data for the progress report. + /// The sender of the report. + /// The reported value. + public delegate void ProgressEventHandler(object sender, T value); + + /// + /// Provides an IProgress{T} that invokes callbacks for each reported progress value. + /// + /// Specifies the type of the progress report value. + /// + /// Any handler provided to the constructor or event handlers registered with + /// the event are invoked through a + /// instance captured + /// when the instance is constructed. If there is no current SynchronizationContext + /// at the time of construction, the callbacks will be invoked on the ThreadPool. + /// + public class Progress : IProgress + { + /// The synchronization context captured upon construction. This will never be null. + private readonly SynchronizationContext m_synchronizationContext; + /// The handler specified to the constructor. This may be null. + private readonly Action m_handler; + /// A cached delegate used to post invocation to the synchronization context. + private readonly SendOrPostCallback m_invokeHandlers; + + /// Initializes the . + public Progress() + { + m_synchronizationContext = SynchronizationContext.Current ?? ProgressStatics.DefaultContext; + Contract.Assert(m_synchronizationContext != null); + m_invokeHandlers = new SendOrPostCallback(InvokeHandlers); + } + + /// Initializes the with the specified callback. + /// + /// A handler to invoke for each reported progress value. This handler will be invoked + /// in addition to any delegates registered with the event. + /// + /// The is null (Nothing in Visual Basic). + public Progress(Action handler) + : this() + { + if (handler == null) throw new ArgumentNullException("handler"); + m_handler = handler; + } + + /// Raised for each reported progress value. + /// + /// Handlers registered with this event will be invoked on the + /// captured when the instance was constructed. + /// + public event ProgressEventHandler ProgressChanged; + + /// Reports a progress change. + /// The value of the updated progress. + protected virtual void OnReport(T value) + { + // If there's no handler, don't bother going through the sync context. + // Inside the callback, we'll need to check again, in case + // an event handler is removed between now and then. + Action handler = m_handler; + ProgressEventHandler changedEvent = ProgressChanged; + if (handler != null || changedEvent != null) + { + // Post the processing to the sync context. + // (If T is a value type, it will get boxed here.) + m_synchronizationContext.Post(m_invokeHandlers, value); + } + } + + /// Reports a progress change. + /// The value of the updated progress. + void IProgress.Report(T value) { OnReport(value); } + + /// Invokes the action and event callbacks. + /// The progress value. + private void InvokeHandlers(object state) + { + T value = (T)state; + + Action handler = m_handler; + ProgressEventHandler changedEvent = ProgressChanged; + + if (handler != null) handler(value); + if (changedEvent != null) changedEvent(this, value); + } + } + + /// Holds static values for . + /// This avoids one static instance per type T. + internal static class ProgressStatics + { + /// A default synchronization context that targets the ThreadPool. + internal static readonly SynchronizationContext DefaultContext = new SynchronizationContext(); + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Properties/AssemblyInfo.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8c972199d --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.Threading.Tasks")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("Microsoft.Threading.Tasks")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/AsyncServices.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/AsyncServices.cs new file mode 100644 index 000000000..05651ad0f --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/AsyncServices.cs @@ -0,0 +1,71 @@ +// NOTE: If you change this copy, please also change the copy under the BCL partition +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace System.Runtime.CompilerServices +{ + internal static class AsyncServices + { + /// Throws the exception on the ThreadPool. + /// The exception to propagate. + /// The target context on which to propagate the exception. Null to use the ThreadPool. + internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext) + { + // If the user supplied a SynchronizationContext... + if (targetContext != null) + { + try + { + // Post the throwing of the exception to that context, and return. + targetContext.Post(state => { throw PrepareExceptionForRethrow((Exception)state); }, exception); + return; + } + catch (Exception postException) + { + // If something goes horribly wrong in the Post, we'll + // propagate both exceptions on the ThreadPool + exception = new AggregateException(exception, postException); + } + } + + // Propagate the exception(s) on the ThreadPool + ThreadPool.QueueUserWorkItem(state => { throw PrepareExceptionForRethrow((Exception)state); }, exception); + } + + /// Copies the exception's stack trace so its stack trace isn't overwritten. + /// The exception to prepare. + internal static Exception PrepareExceptionForRethrow(Exception exc) + { +#if EXCEPTION_STACK_PRESERVE + Contract.Assume(exc != null); + if (s_prepForRemoting != null) + { + try { s_prepForRemoting.Invoke(exc, s_emptyParams); } + catch { } + } +#endif + return exc; + } + +#if EXCEPTION_STACK_PRESERVE + /// A MethodInfo for the Exception.PrepForRemoting method. + private readonly static MethodInfo s_prepForRemoting = GetPrepForRemotingMethodInfo(); + /// An empty array to use with MethodInfo.Invoke. + private readonly static Object[] s_emptyParams = new object[0]; + + /// Gets the MethodInfo for the internal PrepForRemoting method on Exception. + /// The MethodInfo if it could be retrieved, or else null. + private static MethodInfo GetPrepForRemotingMethodInfo() + { + try + { + return typeof(Exception).GetMethod("PrepForRemoting", BindingFlags.NonPublic | BindingFlags.Instance); + } + catch { return null; } + } +#endif + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/ConfiguredTaskAwaitable.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/ConfiguredTaskAwaitable.cs new file mode 100644 index 000000000..1634eb9a9 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/ConfiguredTaskAwaitable.cs @@ -0,0 +1,104 @@ +// NOTE: The reason this type does exist in the BCL System.Threading.Tasks contract is because we need to be able to construct one of these in the AwaitExtensions +// class. The equivalent type in the current platform does not have an accessible constructor, hence the AwaitExtensions would fail when run on platforms +// where System.Threading.Tasks gets unified. + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Security; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Runtime.CompilerServices +{ + /// Provides an awaitable object that allows for configured awaits on . + /// This type is intended for compiler use only. + public struct ConfiguredTaskAwaitable + { + /// The task being awaited. + private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter m_configuredTaskAwaiter; + + /// Initializes the . + /// The awaitable . + /// + /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. + /// + internal ConfiguredTaskAwaitable(Task task, bool continueOnCapturedContext) + { + Contract.Assert(task != null); + m_configuredTaskAwaiter = new ConfiguredTaskAwaitable.ConfiguredTaskAwaiter(task, continueOnCapturedContext); + } + + /// Gets an awaiter for this awaitable. + /// The awaiter. + public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter() + { + return m_configuredTaskAwaiter; + } + + /// Provides an awaiter for a . + /// This type is intended for compiler use only. + public struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion + { + /// The task being awaited. + private readonly Task m_task; + /// Whether to attempt marshaling back to the original context. + private readonly bool m_continueOnCapturedContext; + + /// Initializes the . + /// The to await. + /// + /// true to attempt to marshal the continuation back to the original context captured + /// when BeginAwait is called; otherwise, false. + /// + internal ConfiguredTaskAwaiter(Task task, bool continueOnCapturedContext) + { + Contract.Assert(task != null); + m_task = task; + m_continueOnCapturedContext = continueOnCapturedContext; + } + + /// Gets whether the task being awaited is completed. + /// This property is intended for compiler user rather than use directly in code. + /// The awaiter was not properly initialized. + public bool IsCompleted { get { return m_task.IsCompleted; } } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. + public void OnCompleted(Action continuation) + { + TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext); + } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. +#if !SILVERLIGHT + // [SecurityCritical] +#endif + public void UnsafeOnCompleted(Action continuation) + { + TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext); + } + + /// Ends the await on the completed . + /// The result of the completed . + /// The awaiter was not properly initialized. + /// The task was not yet completed. + /// The task was canceled. + /// The task completed in a Faulted state. + public void GetResult() + { + TaskAwaiter.ValidateEnd(m_task); + } + } + } + +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/ConfiguredTaskAwaitableOfTResult.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/ConfiguredTaskAwaitableOfTResult.cs new file mode 100644 index 000000000..a894eba0e --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/ConfiguredTaskAwaitableOfTResult.cs @@ -0,0 +1,100 @@ +// NOTE: The reason this type does exist in the BCL System.Threading.Tasks contract is because we need to be able to construct one of these in the AwaitExtensions +// class. The equivalent type in the current platform does not have an accessible constructor, hence the AwaitExtensions would fail when run on platforms +// where System.Threading.Tasks gets unified. +using System; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading.Tasks; + +namespace Microsoft.Runtime.CompilerServices +{ + /// Provides an awaitable object that allows for configured awaits on . + /// This type is intended for compiler use only. + public struct ConfiguredTaskAwaitable + { + /// The underlying awaitable on whose logic this awaitable relies. + private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter m_configuredTaskAwaiter; + + /// Initializes the . + /// The awaitable . + /// + /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. + /// + internal ConfiguredTaskAwaitable(Task task, bool continueOnCapturedContext) + { + m_configuredTaskAwaiter = new ConfiguredTaskAwaitable.ConfiguredTaskAwaiter(task, continueOnCapturedContext); + } + + /// Gets an awaiter for this awaitable. + /// The awaiter. + public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter() + { + return m_configuredTaskAwaiter; + } + + /// Provides an awaiter for a . + /// This type is intended for compiler use only. + public struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion + { + /// The task being awaited. + private readonly Task m_task; + /// Whether to attempt marshaling back to the original context. + private readonly bool m_continueOnCapturedContext; + + /// Initializes the . + /// The awaitable . + /// + /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. + /// + internal ConfiguredTaskAwaiter(Task task, bool continueOnCapturedContext) + { + Contract.Assert(task != null); + m_task = task; + m_continueOnCapturedContext = continueOnCapturedContext; + } + + /// Gets whether the task being awaited is completed. + /// This property is intended for compiler user rather than use directly in code. + /// The awaiter was not properly initialized. + public bool IsCompleted { get { return m_task.IsCompleted; } } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. + public void OnCompleted(Action continuation) + { + TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext); + } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. +#if !SILVERLIGHT + // [SecurityCritical] +#endif + public void UnsafeOnCompleted(Action continuation) + { + TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext); + } + + /// Ends the await on the completed . + /// The result of the completed . + /// The awaiter was not properly initialized. + /// The task was not yet completed. + /// The task was canceled. + /// The task completed in a Faulted state. + public TResult GetResult() + { + TaskAwaiter.ValidateEnd(m_task); + return m_task.Result; + } + } + + } + +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/TaskAwaiter.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/TaskAwaiter.cs new file mode 100644 index 000000000..713d60b60 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/TaskAwaiter.cs @@ -0,0 +1,235 @@ +// NOTE: The reason this type does exist in the BCL System.Threading.Tasks contract is because we need to be able to construct one of these in the AwaitExtensions +// class. The equivalent type in the current platform does not have an accessible constructor, hence the AwaitExtensions would fail when run on platforms +// where System.Threading.Tasks gets unified. +using System; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Runtime.CompilerServices +{ + /// Provides an awaiter for awaiting a . + /// This type is intended for compiler use only. + public struct TaskAwaiter : ICriticalNotifyCompletion + { + /// The default value to use for continueOnCapturedContext. + internal const bool CONTINUE_ON_CAPTURED_CONTEXT_DEFAULT = true; // marshal by default + /// The task being awaited. + private readonly Task m_task; + + /// Initializes the . + /// The to be awaited. + internal TaskAwaiter(Task task) + { + Contract.Assert(task != null); + m_task = task; + } + + /// Gets whether the task being awaited is completed. + /// This property is intended for compiler user rather than use directly in code. + /// The awaiter was not properly initialized. + public bool IsCompleted { get { return m_task.IsCompleted; } } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. + public void OnCompleted(Action continuation) + { + OnCompletedInternal(m_task, continuation, CONTINUE_ON_CAPTURED_CONTEXT_DEFAULT); + } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. +#if !SILVERLIGHT + // [SecurityCritical] +#endif + public void UnsafeOnCompleted(Action continuation) + { + OnCompletedInternal(m_task, continuation, CONTINUE_ON_CAPTURED_CONTEXT_DEFAULT); + } + + /// Ends the await on the completed . + /// The awaiter was not properly initialized. + /// The task was not yet completed. + /// The task was canceled. + /// The task completed in a Faulted state. + public void GetResult() + { + ValidateEnd(m_task); + } + + /// + /// Fast checks for the end of an await operation to determine whether more needs to be done + /// prior to completing the await. + /// + /// The awaited task. + internal static void ValidateEnd(Task task) + { + if (task.Status != TaskStatus.RanToCompletion) + HandleNonSuccess(task); + } + + /// Handles validations on tasks that aren't successfully completed. + /// The awaited task. + private static void HandleNonSuccess(Task task) + { + if (!task.IsCompleted) + { + try { task.Wait(); } + catch { } + } + if (task.Status != TaskStatus.RanToCompletion) + { + ThrowForNonSuccess(task); + } + } + + /// Throws an exception to handle a task that completed in a state other than RanToCompletion. + private static void ThrowForNonSuccess(Task task) + { + Contract.Assert(task.Status != TaskStatus.RanToCompletion); + + // Handle whether the task has been canceled or faulted + switch (task.Status) + { + // If the task completed in a canceled state, throw an OperationCanceledException. + // TaskCanceledException derives from OCE, and by throwing it we automatically pick up the + // completed task's CancellationToken if it has one, including that CT in the OCE. + case TaskStatus.Canceled: + throw new TaskCanceledException(task); + + // If the task faulted, throw its first exception, + // even if it contained more than one. + case TaskStatus.Faulted: + throw PrepareExceptionForRethrow(task.Exception.InnerException); + + // This should not happen on valid usage. + default: + throw new InvalidOperationException(InvalidOperationException_TaskNotCompleted); + } + } + + /// Error message for GetAwaiter. + private const string InvalidOperationException_TaskNotCompleted = "The task has not yet completed."; + + /// Schedules the continuation onto the associated with this . + /// The awaited task. + /// The action to invoke when the await operation completes. + /// Whether to capture and marshal back to the current context. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. + internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext) + { + if (continuation == null) throw new ArgumentNullException("continuation"); + SynchronizationContext sc = continueOnCapturedContext ? SynchronizationContext.Current : null; + if (sc != null && sc.GetType() != typeof(SynchronizationContext)) + { + // When the task completes, post to the synchronization context, or run it inline if we're already in the right place + task.ContinueWith(delegate + { + try { sc.Post(state => ((Action)state)(), continuation); } + catch (Exception exc) { AsyncServices.ThrowAsync(exc, null); } + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + else + { + var scheduler = continueOnCapturedContext ? TaskScheduler.Current : TaskScheduler.Default; + if (task.IsCompleted) + { + Task.Factory.StartNew( + s => ((Action)s)(), continuation, CancellationToken.None, TaskCreationOptions.None, scheduler); + } + else + { + // NOTE: There is a known rare race here. For performance reasons, we want this continuation to + // execute synchronously when the task completes, but if the task is already completed by the time + // we call ContinueWith, we don't want it executing synchronously as part of the ContinueWith call. + // If the race occurs, and if the unbelievable happens and it occurs frequently enough to + // stack dive, ContinueWith's support for depth checking helps to mitigate this. + + if (scheduler != TaskScheduler.Default) + { + // When the task completes, run the continuation in a callback using the correct task scheduler. + task.ContinueWith(_ => RunNoException(continuation), + CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, scheduler); + } + else + { + // When the task completes, run the continuation in a callback using the correct task scheduler. + task.ContinueWith(delegate + { + if (IsValidLocationForInlining) + RunNoException(continuation); + else + Task.Factory.StartNew(s => RunNoException((Action)s), + continuation, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + } + } + } + + /// Invokes the delegate in a try/catch that will propagate the exception asynchronously on the ThreadPool. + /// + private static void RunNoException(Action continuation) + { + try { continuation(); } + catch (Exception exc) { AsyncServices.ThrowAsync(exc, null); } + } + + /// Whether the current thread is appropriate for inlining the await continuation. + private static bool IsValidLocationForInlining + { + get + { + var currentCtx = SynchronizationContext.Current; + if (currentCtx != null && currentCtx.GetType() != typeof(SynchronizationContext)) + return false; + else + return TaskScheduler.Current == TaskScheduler.Default; + } + } + + /// Copies the exception's stack trace so its stack trace isn't overwritten. + /// The exception to prepare. + internal static Exception PrepareExceptionForRethrow(Exception exc) + { +#if EXCEPTION_STACK_PRESERVE + Contract.Assume(exc != null); + if (s_prepForRemoting != null) + { + try { s_prepForRemoting.Invoke(exc, s_emptyParams); } + catch { } + } +#endif + return exc; + } + +#if EXCEPTION_STACK_PRESERVE + /// A MethodInfo for the Exception.PrepForRemoting method. + private readonly static MethodInfo s_prepForRemoting = GetPrepForRemotingMethodInfo(); + /// An empty array to use with MethodInfo.Invoke. + private readonly static Object[] s_emptyParams = new object[0]; + + /// Gets the MethodInfo for the internal PrepForRemoting method on Exception. + /// The MethodInfo if it could be retrieved, or else null. + private static MethodInfo GetPrepForRemotingMethodInfo() + { + try + { + return typeof(Exception).GetMethod("PrepForRemoting", BindingFlags.NonPublic | BindingFlags.Instance); + } + catch { return null; } + } +#endif + } + +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/TaskAwaiterOfTResult.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/TaskAwaiterOfTResult.cs new file mode 100644 index 000000000..752a7c4d5 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/TaskAwaiterOfTResult.cs @@ -0,0 +1,68 @@ +// NOTE: The reason this type does exist in the BCL System.Threading.Tasks contract is because we need to be able to construct one of these in the AwaitExtensions +// class. The equivalent type in the current platform does not have an accessible constructor, hence the AwaitExtensions would fail when run on platforms +// where System.Threading.Tasks gets unified. +using System; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading.Tasks; + +namespace Microsoft.Runtime.CompilerServices +{ + /// Provides an awaiter for awaiting a . + /// This type is intended for compiler use only. + public struct TaskAwaiter : ICriticalNotifyCompletion + { + /// The task being awaited. + private readonly Task m_task; + + /// Initializes the . + /// The to be awaited. + internal TaskAwaiter(Task task) + { + Contract.Assert(task != null); + m_task = task; + } + + /// Gets whether the task being awaited is completed. + /// This property is intended for compiler user rather than use directly in code. + /// The awaiter was not properly initialized. + public bool IsCompleted { get { return m_task.IsCompleted; } } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. + public void OnCompleted(Action continuation) + { + TaskAwaiter.OnCompletedInternal(m_task, continuation, TaskAwaiter.CONTINUE_ON_CAPTURED_CONTEXT_DEFAULT); + } + + /// Schedules the continuation onto the associated with this . + /// The action to invoke when the await operation completes. + /// The argument is null (Nothing in Visual Basic). + /// The awaiter was not properly initialized. + /// This method is intended for compiler user rather than use directly in code. +#if !SILVERLIGHT + //[SecurityCritical] +#endif + public void UnsafeOnCompleted(Action continuation) + { + TaskAwaiter.OnCompletedInternal(m_task, continuation, TaskAwaiter.CONTINUE_ON_CAPTURED_CONTEXT_DEFAULT); + } + + /// Ends the await on the completed . + /// The result of the completed . + /// The awaiter was not properly initialized. + /// The task was not yet completed. + /// The task was canceled. + /// The task completed in a Faulted state. + public TResult GetResult() + { + TaskAwaiter.ValidateEnd(m_task); + return m_task.Result; + } + } + +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/YieldAwaitable.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/YieldAwaitable.cs new file mode 100644 index 000000000..4f0a0dbc3 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Runtime/CompilerServices/YieldAwaitable.cs @@ -0,0 +1,46 @@ +// NOTE: The reason this type does exist in the BCL System.Threading.Tasks contract is because we need to be able to construct one of these in the AwaitExtensions +// class. The equivalent type in the current platform does not have an accessible constructor, hence the AwaitExtensions would fail when run on platforms +// where System.Threading.Tasks gets unified. +using System; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading.Tasks; + +namespace Microsoft.Runtime.CompilerServices +{ + /// Provides an awaitable context for switching into a target environment. + /// This type is intended for compiler use only. + public struct YieldAwaitable + { + /// Gets an awaiter for this . + /// An awaiter for this awaitable. + /// This method is intended for compiler user rather than use directly in code. + public YieldAwaiter GetAwaiter() { return new YieldAwaiter(); } // if not initialized properly, m_target will just be null + + /// Provides an awaiter that switches into a target environment. + /// This type is intended for compiler use only. + public struct YieldAwaiter : ICriticalNotifyCompletion + { + /// A completed task. + private readonly static Task s_completed = TaskEx.FromResult(0); + + /// Gets whether a yield is not required. + /// This property is intended for compiler user rather than use directly in code. + public bool IsCompleted { get { return false; } } // yielding is always required for YieldAwaiter, hence false + + /// Posts the back to the current context. + /// The action to invoke asynchronously. + /// The awaiter was not properly initialized. + public void OnCompleted(Action continuation) { s_completed.GetAwaiter().OnCompleted(continuation); } + + /// Posts the back to the current context. + /// The action to invoke asynchronously. + /// The awaiter was not properly initialized. + //[SecurityCritical] + public void UnsafeOnCompleted(Action continuation) { s_completed.GetAwaiter().UnsafeOnCompleted(continuation); } + + /// Ends the await operation. + public void GetResult() { } // Nop. It exists purely because the compiler pattern demands it. + } + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/Tasks/TaskEx.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/Tasks/TaskEx.cs new file mode 100644 index 000000000..3061f44c4 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/Tasks/TaskEx.cs @@ -0,0 +1,434 @@ +using Microsoft.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; + +namespace System.Threading.Tasks +{ + /// Provides methods for creating and manipulating tasks. + public static class TaskEx + { + #region Run + /// Creates a task that runs the specified action. + /// The action to execute asynchronously. + /// A task that represents the completion of the action. + /// The argument is null. + public static Task Run(Action action) + { + return Run(action, CancellationToken.None); + } + + /// Creates a task that runs the specified action. + /// The action to execute. + /// The CancellationToken to use to request cancellation of this task. + /// A task that represents the completion of the action. + /// The argument is null. + public static Task Run(Action action, CancellationToken cancellationToken) + { + return Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Creates a task that runs the specified function. + /// The function to execute asynchronously. + /// A task that represents the completion of the action. + /// The argument is null. + public static Task Run(Func function) + { + return Run(function, CancellationToken.None); + } + + /// Creates a task that runs the specified function. + /// The action to execute. + /// The CancellationToken to use to cancel the task. + /// A task that represents the completion of the action. + /// The argument is null. + public static Task Run(Func function, CancellationToken cancellationToken) + { + return Task.Factory.StartNew(function, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + } + + /// Creates a task that runs the specified function. + /// The action to execute asynchronously. + /// A task that represents the completion of the action. + /// The argument is null. + public static Task Run(Func function) + { + return Run(function, CancellationToken.None); + } + + /// Creates a task that runs the specified function. + /// The function to execute. + /// The CancellationToken to use to request cancellation of this task. + /// A task that represents the completion of the function. + /// The argument is null. + public static Task Run(Func function, CancellationToken cancellationToken) + { + return Run(function, cancellationToken).Unwrap(); + } + + /// Creates a task that runs the specified function. + /// The function to execute asynchronously. + /// A task that represents the completion of the action. + /// The argument is null. + public static Task Run(Func> function) + { + return Run(function, CancellationToken.None); + } + + /// Creates a task that runs the specified function. + /// The action to execute. + /// The CancellationToken to use to cancel the task. + /// A task that represents the completion of the action. + /// The argument is null. + public static Task Run(Func> function, CancellationToken cancellationToken) + { + return Run>(function, cancellationToken).Unwrap(); + } + #endregion + + #region Delay + /// Starts a Task that will complete after the specified due time. + /// The delay in milliseconds before the returned task completes. + /// The timed Task. + /// + /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. + /// + public static Task Delay(int dueTime) + { + return Delay(dueTime, CancellationToken.None); + } + + /// Starts a Task that will complete after the specified due time. + /// The delay before the returned task completes. + /// The timed Task. + /// + /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. + /// + public static Task Delay(TimeSpan dueTime) + { + return Delay(dueTime, CancellationToken.None); + } + + /// Starts a Task that will complete after the specified due time. + /// The delay before the returned task completes. + /// A CancellationToken that may be used to cancel the task before the due time occurs. + /// The timed Task. + /// + /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. + /// + public static Task Delay(TimeSpan dueTime, CancellationToken cancellationToken) + { + long totalMilliseconds = (long)dueTime.TotalMilliseconds; + if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) throw new ArgumentOutOfRangeException("dueTime", ArgumentOutOfRange_TimeoutNonNegativeOrMinusOne); + Contract.EndContractBlock(); + return Delay((int)totalMilliseconds, cancellationToken); + } + + + + /// Starts a Task that will complete after the specified due time. + /// The delay in milliseconds before the returned task completes. + /// A CancellationToken that may be used to cancel the task before the due time occurs. + /// The timed Task. + /// + /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. + /// + public static Task Delay(int dueTime, CancellationToken cancellationToken) + { + // Validate arguments + if (dueTime < -1) throw new ArgumentOutOfRangeException("dueTime", ArgumentOutOfRange_TimeoutNonNegativeOrMinusOne); + Contract.EndContractBlock(); + + // Fast-paths if the timeout has expired or the token has had cancellation requested + if (cancellationToken.IsCancellationRequested) return new Task(() => { }, cancellationToken); + if (dueTime == 0) return s_preCompletedTask; + + // Create the timed task + var tcs = new TaskCompletionSource(); + var ctr = default(CancellationTokenRegistration); + + Timer timer = null; + // Create the timer but don't start it yet. If we start it now, + // it might fire before ctr has been set to the right registration. + timer = new Timer(state => + { + // Clean up both the cancellation token and the timer, and try to transition to completed + ctr.Dispose(); + timer.Dispose(); + tcs.TrySetResult(true); + + TimerManager.Remove(timer); + + }, null, Timeout.Infinite, Timeout.Infinite); + + // Make sure the timer stays rooted. The full Framework + // does this automatically when constructing a timer with the simple + // overload that doesn't take state, in which case the timer itself + // is the state. But Compact Framework doesn't root, so we need to. + TimerManager.Add(timer); + + // Register with the cancellation token if a cancelable one was provided. This must be + // done after initializing timer, as we call timer.Dispose from within the callback + // and that callback will fire synchronously if the token has already been canceled + // by the time we call Register. + if (cancellationToken.CanBeCanceled) + { + // When cancellation occurs, cancel the timer and try to transition to canceled. + // There could be a race, but it's benign. + ctr = cancellationToken.Register(() => + { + timer.Dispose(); + tcs.TrySetCanceled(); + TimerManager.Remove(timer); + }); + } + + // Start the timer and hand back the task... + timer.Change(dueTime, Timeout.Infinite); + return tcs.Task; + } + + private const string ArgumentOutOfRange_TimeoutNonNegativeOrMinusOne = "The timeout must be non-negative or -1, and it must be less than or equal to Int32.MaxValue."; + + /// An already completed task. + private static Task s_preCompletedTask = TaskEx.FromResult(false); + #endregion + + #region WhenAll + /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. + /// The Tasks to monitor for completion. + /// A Task that represents the completion of all of the provided tasks. + /// + /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information + /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned + /// Task will also be canceled. + /// + /// The argument is null. + /// The argument contains a null reference. + public static Task WhenAll(params Task[] tasks) + { + return WhenAll((IEnumerable)tasks); + } + + /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. + /// The Tasks to monitor for completion. + /// A Task that represents the completion of all of the provided tasks. + /// + /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information + /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned + /// Task will also be canceled. + /// + /// The argument is null. + /// The argument contains a null reference. + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static Task WhenAll(params Task[] tasks) + { + return WhenAll((IEnumerable>)tasks); + } + + /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. + /// The Tasks to monitor for completion. + /// A Task that represents the completion of all of the provided tasks. + /// + /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information + /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned + /// Task will also be canceled. + /// + /// The argument is null. + /// The argument contains a null reference. + public static Task WhenAll(IEnumerable tasks) + { + return WhenAllCore(tasks, (completedTasks, tcs) => + tcs.TrySetResult(null)); + } + + /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. + /// The Tasks to monitor for completion. + /// A Task that represents the completion of all of the provided tasks. + /// + /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information + /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned + /// Task will also be canceled. + /// + /// The argument is null. + /// The argument contains a null reference. + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static Task WhenAll(IEnumerable> tasks) + { + return WhenAllCore(tasks.Cast(), (completedTasks, tcs) => + tcs.TrySetResult(completedTasks.Select(t => ((Task)t).Result).ToArray())); + } + + /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. + /// The Tasks to monitor for completion. + /// + /// A callback invoked when all of the tasks complete successfully in the RanToCompletion state. + /// This callback is responsible for storing the results into the TaskCompletionSource. + /// + /// A Task that represents the completion of all of the provided tasks. + /// The argument is null. + /// The argument contains a null reference. + private static Task WhenAllCore( + IEnumerable tasks, + Action> setResultAction) + { + // Validate arguments + if (tasks == null) throw new ArgumentNullException("tasks"); + Contract.EndContractBlock(); + Contract.Assert(setResultAction != null); + + // Create a TCS to represent the completion of all of the tasks. This TCS's Task is + // completed by a ContinueWhenAll continuation + var tcs = new TaskCompletionSource(); + var taskArr = tasks as Task[] ?? tasks.ToArray(); + if (taskArr.Length == 0) + { + setResultAction(taskArr, tcs); + } + else + { + Task.Factory.ContinueWhenAll(taskArr, completedTasks => + { + // Get exceptions for any faulted or canceled tasks + List exceptions = null; + bool canceled = false; + foreach (var task in completedTasks) + { + if (task.IsFaulted) AddPotentiallyUnwrappedExceptions(ref exceptions, task.Exception); + else if (task.IsCanceled) canceled = true; + } + + // Set up the resulting task. + if (exceptions != null && exceptions.Count > 0) tcs.TrySetException(exceptions); + else if (canceled) tcs.TrySetCanceled(); + else setResultAction(completedTasks, tcs); + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + + // Return the resulting task + return tcs.Task; + } + #endregion + + #region WhenAny + /// Creates a Task that will complete when any of the tasks in the provided collection completes. + /// The Tasks to be monitored. + /// + /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. + /// + /// Any Tasks that fault will need to have their exceptions observed elsewhere. + /// The argument is null. + /// The argument contains a null reference. + public static Task WhenAny(params Task[] tasks) + { + return WhenAny((IEnumerable)tasks); + } + + /// Creates a Task that will complete when any of the tasks in the provided collection completes. + /// The Tasks to be monitored. + /// + /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. + /// + /// Any Tasks that fault will need to have their exceptions observed elsewhere. + /// The argument is null. + /// The argument contains a null reference. + public static Task WhenAny(IEnumerable tasks) + { + // Validate arguments + if (tasks == null) throw new ArgumentNullException("tasks"); + Contract.EndContractBlock(); + + // Create a task that will complete with + var tcs = new TaskCompletionSource(); + Task.Factory.ContinueWhenAny(tasks as Task[] ?? tasks.ToArray(), + completed => tcs.TrySetResult(completed), + CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + return tcs.Task; + } + + /// Creates a Task that will complete when any of the tasks in the provided collection completes. + /// The Tasks to be monitored. + /// + /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. + /// + /// Any Tasks that fault will need to have their exceptions observed elsewhere. + /// The argument is null. + /// The argument contains a null reference. + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static Task> WhenAny(params Task[] tasks) + { + return WhenAny((IEnumerable>)tasks); + } + + /// Creates a Task that will complete when any of the tasks in the provided collection completes. + /// The Tasks to be monitored. + /// + /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. + /// + /// Any Tasks that fault will need to have their exceptions observed elsewhere. + /// The argument is null. + /// The argument contains a null reference. + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static Task> WhenAny(IEnumerable> tasks) + { + // Validate arguments + if (tasks == null) throw new ArgumentNullException("tasks"); + Contract.EndContractBlock(); + + // Create a task that will complete with + var tcs = new TaskCompletionSource>(); + Task.Factory.ContinueWhenAny(tasks as Task[] ?? tasks.ToArray(), + completed => tcs.TrySetResult(completed), + CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + return tcs.Task; + } + #endregion + + #region FromResult + /// Creates an already completed from the specified result. + /// The result from which to create the completed task. + /// The completed task. + public static Task FromResult(TResult result) + { + var tcs = new TaskCompletionSource(result); + tcs.TrySetResult(result); + return tcs.Task; + } + #endregion + + #region Yield + /// Creates an awaitable that asynchronously yields back to the current context when awaited. + /// + /// A context that, when awaited, will asynchronously transition back into the current context. + /// If SynchronizationContext.Current is non-null, that is treated as the current context. + /// Otherwise, TaskScheduler.Current is treated as the current context. + /// + public static YieldAwaitable Yield() { return new YieldAwaitable(); } + #endregion + + #region Private Helpers + /// Adds the target exception to the list, initializing the list if it's null. + /// The list to which to add the exception and initialize if the list is null. + /// The exception to add, and unwrap if it's an aggregate. + private static void AddPotentiallyUnwrappedExceptions(ref List targetList, Exception exception) + { + var ae = exception as AggregateException; + + Contract.Assert(exception != null); + Contract.Assert(ae == null || ae.InnerExceptions.Count > 0); + + // Initialize the list if necessary + if (targetList == null) targetList = new List(); + + // If the exception is an aggregate and it contains only one exception, add just its inner exception + if (ae != null) + { + targetList.Add(ae.InnerExceptions.Count == 1 ? exception.InnerException : exception); + } + // Otherwise, add the exception + else targetList.Add(exception); + } + #endregion + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/Tasks/TaskServices.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/Tasks/TaskServices.cs new file mode 100644 index 000000000..1020bb2e2 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/Tasks/TaskServices.cs @@ -0,0 +1,54 @@ +using System.ComponentModel; + +namespace System.Threading.Tasks +{ + internal class TaskServices + { + /// Returns a canceled task. + /// The cancellation token. + /// The canceled task. + public static Task FromCancellation(System.Threading.CancellationToken cancellationToken) + { + if (!cancellationToken.IsCancellationRequested) throw new System.ArgumentOutOfRangeException("cancellationToken"); + return new Task(() => { }, cancellationToken); + } + + /// Returns a canceled task. + /// Specifies the type of the result. + /// The cancellation token. + /// The canceled task. + public static Task FromCancellation(System.Threading.CancellationToken cancellationToken) + { + if (!cancellationToken.IsCancellationRequested) throw new System.ArgumentOutOfRangeException("cancellationToken"); + return new Task(() => default(TResult), cancellationToken); + } + + /// + /// Completes the Task if the user state matches the TaskCompletionSource. + /// + /// Specifies the type of data returned by the Task. + /// The TaskCompletionSource. + /// The completion event arguments. + /// Whether we require the tcs to match the e.UserState. + /// A function that gets the result with which to complete the task. + /// An action used to unregister work when the operaiton completes. + public static void HandleEapCompletion( + TaskCompletionSource tcs, bool requireMatch, AsyncCompletedEventArgs e, Func getResult, Action unregisterHandler) + { + // Transfers the results from the AsyncCompletedEventArgs and getResult() to the + // TaskCompletionSource, but only AsyncCompletedEventArg's UserState matches the TCS + // (this check is important if the same WebClient is used for multiple, asynchronous + // operations concurrently). Also unregisters the handler to avoid a leak. + if (!requireMatch || e.UserState == tcs) + { + try { unregisterHandler(); } + finally + { + if (e.Cancelled) tcs.TrySetCanceled(); + else if (e.Error != null) tcs.TrySetException(e.Error); + else tcs.TrySetResult(getResult()); + } + } + } + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/TimerManager.cs b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/TimerManager.cs new file mode 100644 index 000000000..eef2acd94 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/Threading/TimerManager.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Threading +{ + + // Workaround for the lack of rooting of timers on Compat Framework/Windows Phone + internal static class TimerManager + { +#if NO_TIMER_ROOT + private static Dictionary s_rootedTimers = new Dictionary(); +#endif + public static void Add(Timer timer) + { +#if NO_TIMER_ROOT + lock (s_rootedTimers) + { + s_rootedTimers.Add(timer, null); + } +#endif + } + + public static void Remove(Timer timer) + { +#if NO_TIMER_ROOT + lock (s_rootedTimers) + { + s_rootedTimers.Remove(timer); + } +#endif + } + } +} diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/app.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/app.config new file mode 100644 index 000000000..a6a2b7fa9 --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/app.config @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/packages.config b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/packages.config new file mode 100644 index 000000000..2384716da --- /dev/null +++ b/Microsoft.Bcl.Async/Microsoft.Threading.Tasks/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl/CodePlexKey.snk b/Microsoft.Bcl/CodePlexKey.snk new file mode 100644 index 000000000..5d44ffe87 Binary files /dev/null and b/Microsoft.Bcl/CodePlexKey.snk differ diff --git a/Microsoft.Bcl/System.IO.v1.5/Properties/AssemblyInfo.cs b/Microsoft.Bcl/System.IO.v1.5/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..eac78e0bd --- /dev/null +++ b/Microsoft.Bcl/System.IO.v1.5/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("System.IO")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("System.IO")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/Microsoft.Bcl/System.IO.v1.5/Strings.Designer.cs b/Microsoft.Bcl/System.IO.v1.5/Strings.Designer.cs new file mode 100644 index 000000000..426216571 --- /dev/null +++ b/Microsoft.Bcl/System.IO.v1.5/Strings.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18046 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace System { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Found invalid data while decoding.. + /// + internal static string GenericInvalidData { + get { + return ResourceManager.GetString("GenericInvalidData", resourceCulture); + } + } + } +} diff --git a/Microsoft.Bcl/System.IO.v1.5/Strings.resx b/Microsoft.Bcl/System.IO.v1.5/Strings.resx new file mode 100644 index 000000000..36dc2620b --- /dev/null +++ b/Microsoft.Bcl/System.IO.v1.5/Strings.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Found invalid data while decoding. + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.IO.v1.5/System.IO.v1.5.csproj b/Microsoft.Bcl/System.IO.v1.5/System.IO.v1.5.csproj new file mode 100644 index 000000000..c0c4ef1d5 --- /dev/null +++ b/Microsoft.Bcl/System.IO.v1.5/System.IO.v1.5.csproj @@ -0,0 +1,71 @@ + + + + + 10.0 + Debug + AnyCPU + {E18239EC-7C12-4704-A089-8B619C44F4C6} + Library + Properties + System + System.IO + v4.0 + Profile88 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + bin\Debug\System.IO.xml + SecurityRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\System.IO.xml + + + true + true + ..\CodePlexKey.snk + + + + + True + True + Strings.resx + + + + + + ResXFileCodeGenerator + Strings.Designer.cs + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.IO.v1.5/System/IO/InvalidDataException.cs b/Microsoft.Bcl/System.IO.v1.5/System/IO/InvalidDataException.cs new file mode 100644 index 000000000..776201ed7 --- /dev/null +++ b/Microsoft.Bcl/System.IO.v1.5/System/IO/InvalidDataException.cs @@ -0,0 +1,34 @@ +namespace System.IO { + + using System; + + /// + /// The exception that is thrown when a data stream is in an invalid format. + /// + public sealed class InvalidDataException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public InvalidDataException () + : base(Strings.GenericInvalidData) { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The error message that explains the reason for the exception. + public InvalidDataException (String message) + : base(message) { + } + + /// + /// Initializes a new instance of the class with a reference to the inner exception that is the cause of this exception. + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not null, the current exception is raised in a catch block that handles the inner exception. + public InvalidDataException (String message, Exception innerException) + : base(message, innerException) { + } + + } +} diff --git a/Microsoft.Bcl/System.IO.v2.5/Properties/AssemblyInfo.cs b/Microsoft.Bcl/System.IO.v2.5/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f9834b34b --- /dev/null +++ b/Microsoft.Bcl/System.IO.v2.5/Properties/AssemblyInfo.cs @@ -0,0 +1,24 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; +using System.Runtime.CompilerServices; +using System.IO; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("System.IO")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("System.IO")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +[assembly: TypeForwardedTo(typeof(InvalidDataException))] \ No newline at end of file diff --git a/Microsoft.Bcl/System.IO.v2.5/System.IO.v2.5.csproj b/Microsoft.Bcl/System.IO.v2.5/System.IO.v2.5.csproj new file mode 100644 index 000000000..f426f1bb9 --- /dev/null +++ b/Microsoft.Bcl/System.IO.v2.5/System.IO.v2.5.csproj @@ -0,0 +1,59 @@ + + + + + 10.0 + Debug + AnyCPU + {BD52BEC2-B8A9-4C12-968B-87E9D77776DA} + Library + Properties + System + System.IO + v4.0 + Profile5 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + bin\Debug\System.IO.xml + SecurityRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\System.IO.xml + + + true + true + ..\CodePlexKey.snk + + + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v1.5/Properties/AssemblyInfo.cs b/Microsoft.Bcl/System.Runtime.v1.5/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a2253d6b0 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("System.Runtime")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("System.Runtime")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v1.5/Strings.Designer.cs b/Microsoft.Bcl/System.Runtime.v1.5/Strings.Designer.cs new file mode 100644 index 000000000..4ef234b98 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/Strings.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.17929 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace System { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Argument must be of type {0}.. + /// + internal static string ArgumentException_TupleIncorrectType { + get { + return ResourceManager.GetString("ArgumentException_TupleIncorrectType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The last element of an eight element tuple must be a Tuple.. + /// + internal static string ArgumentException_TupleLastArgumentNotATuple { + get { + return ResourceManager.GetString("ArgumentException_TupleLastArgumentNotATuple", resourceCulture); + } + } + } +} diff --git a/Microsoft.Bcl/System.Runtime.v1.5/Strings.resx b/Microsoft.Bcl/System.Runtime.v1.5/Strings.resx new file mode 100644 index 000000000..4c671ff08 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/Strings.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Argument must be of type {0}. + + + The last element of an eight element tuple must be a Tuple. + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System.Runtime.v1.5.csproj b/Microsoft.Bcl/System.Runtime.v1.5/System.Runtime.v1.5.csproj new file mode 100644 index 000000000..70e845671 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System.Runtime.v1.5.csproj @@ -0,0 +1,79 @@ + + + + + 10.0 + Debug + AnyCPU + {42DB1993-8EBB-4827-BC05-F3906EA8CFBC} + Library + Properties + System + System.Runtime + v4.0 + Profile88 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + bin\Debug\System.Runtime.xml + SecurityRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\System.Runtime.xml + + + true + true + ..\CodePlexKey.snk + + + + + True + True + Strings.resx + + + + + + + + + + + + + + ResXFileCodeGenerator + Strings.Designer.cs + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System.Runtime.v1.5.csproj.vspscc b/Microsoft.Bcl/System.Runtime.v1.5/System.Runtime.v1.5.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System.Runtime.v1.5.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Collections/IStructuralComparable.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Collections/IStructuralComparable.cs new file mode 100644 index 000000000..6c6275e7f --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Collections/IStructuralComparable.cs @@ -0,0 +1,29 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +namespace System.Collections +{ + /// + /// Supports the structural comparison of collection objects. + /// + public interface IStructuralComparable + { + /// + /// Determines whether the current collection object precedes, occurs in the same position as, or follows another object in the sort order. + /// + /// The object to compare with the current instance. + /// An object that compares members of the current collection object with the corresponding members of other. + /// An integer that indicates the relationship of the current collection object to other. + /// + /// This instance and other are not the same type. + /// + int CompareTo(object other, IComparer comparer); + } +} \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Collections/IStructuralEquatable.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Collections/IStructuralEquatable.cs new file mode 100644 index 000000000..eeb8667ea --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Collections/IStructuralEquatable.cs @@ -0,0 +1,33 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +namespace System.Collections +{ + /// + /// Defines methods to support the comparison of objects for structural equality. + /// + public interface IStructuralEquatable + { + /// + /// Determines whether an object is structurally equal to the current instance. + /// + /// The object to compare with the current instance. + /// An object that determines whether the current instance and other are equal. + /// true if the two objects are equal; otherwise, false. + bool Equals(object other, IEqualityComparer comparer); + + /// + /// Returns a hash code for the current instance. + /// + /// An object that computes the hash code of the current object. + /// The hash code for the current instance. + int GetHashCode(IEqualityComparer comparer); + } +} \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Func.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Func.cs new file mode 100644 index 000000000..84f21da7b --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Func.cs @@ -0,0 +1,30 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System +{ + /// + /// Encapsulates a method that has five parameters and returns a value of the type specified by the TResult parameter. + /// + /// The type of the first parameter of the method that this delegate encapsulates. + /// The type of the second parameter of the method that this delegate encapsulates. + /// The type of the third parameter of the method that this delegate encapsulates. + /// The type of the fourth parameter of the method that this delegate encapsulates. + /// The type of the fifth parameter of the method that this delegate encapsulates. + /// The type of the return value of the method that this delegate encapsulates. + /// The first parameter of the method that this delegate encapsulates. + /// The second parameter of the method that this delegate encapsulates. + /// The third parameter of the method that this delegate encapsulates. + /// The fourth parameter of the method that this delegate encapsulates. + /// The fifth parameter of the method that this delegate encapsulates. + /// The return value of the method that this delegate encapsulates. + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); +} diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Progress.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Progress.cs new file mode 100644 index 000000000..2bc82e9a7 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Progress.cs @@ -0,0 +1,28 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading; + +namespace System +{ + /// Defines a provider for progress updates. + /// The type of progress update value. +#if VARIANCE + public interface IProgress +#else + public interface IProgress +#endif + { + /// Reports a progress update. + /// The value of the updated progress. + void Report(T value); + } +} \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs new file mode 100644 index 000000000..506804810 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs @@ -0,0 +1,21 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + /// Identities the async state machine type for this method. + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + public sealed class AsyncStateMachineAttribute : StateMachineAttribute + { + /// Initializes the attribute. + /// The type that implements the state machine. + public AsyncStateMachineAttribute(Type stateMachineType) : base(stateMachineType) { } + } +} diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/CallerInfoAttributes.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/CallerInfoAttributes.cs new file mode 100644 index 000000000..b5c7f8dfb --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/CallerInfoAttributes.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + /// + /// Allows you to obtain the method or property name of the caller to the method. + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + public sealed class CallerMemberNameAttribute : Attribute { } + + /// + /// Allows you to obtain the line number in the source file at which the method is called. + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + public sealed class CallerLineNumberAttribute : Attribute { } + + /// + /// Allows you to obtain the full path of the source file that contains the caller. + /// This is the file path at the time of compile. + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + public sealed class CallerFilePathAttribute : Attribute { } +} diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs new file mode 100644 index 000000000..92ad87638 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs @@ -0,0 +1,22 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + /// Identities the iterator state machine type for this method. + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + public sealed class IteratorStateMachineAttribute : StateMachineAttribute + { + /// Initializes the attribute. + /// The type that implements the state machine. + public IteratorStateMachineAttribute(Type stateMachineType) : base(stateMachineType) { } + } +} diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/StateMachineAttribute.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/StateMachineAttribute.cs new file mode 100644 index 000000000..6c4e5954a --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Runtime/CompilerServices/StateMachineAttribute.cs @@ -0,0 +1,28 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + /// Identities the state machine type for this method. + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + public class StateMachineAttribute : Attribute + { + /// Initializes the attribute. + /// The type that implements the state machine. + public StateMachineAttribute(Type stateMachineType) + { + this.StateMachineType = stateMachineType; + } + + /// Gets the type that implements the state machine. + public Type StateMachineType { get; private set; } + } +} diff --git a/Microsoft.Bcl/System.Runtime.v1.5/System/Tuple.cs b/Microsoft.Bcl/System.Runtime.v1.5/System/Tuple.cs new file mode 100644 index 000000000..78243bd82 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v1.5/System/Tuple.cs @@ -0,0 +1,1677 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; + +namespace System +{ + /// + /// Helper so we can call some tuple methods recursively without knowing the underlying types. + /// + internal interface ITuple + { + string ToString(StringBuilder sb); + int GetHashCode(IEqualityComparer comparer); + int Size { get; } + } + + /// + /// Provides static methods for creating tuple objects. + /// + public static class Tuple + { + /// + /// Creates a new 1-tuple, or singleton. + /// + /// The type of the only component of the tuple. + /// The value of the only component of the tuple. + /// A tuple whose value is (item1). + public static Tuple Create(T1 item1) + { + return new Tuple(item1); + } + + /// + /// Creates a new 3-tuple, or pair. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// An 2-tuple (pair) whose value is (item1, item2). + public static Tuple Create(T1 item1, T2 item2) + { + return new Tuple(item1, item2); + } + + /// + /// Creates a new 3-tuple, or triple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// An 3-tuple (triple) whose value is (item1, item2, item3). + public static Tuple Create(T1 item1, T2 item2, T3 item3) + { + return new Tuple(item1, item2, item3); + } + + /// + /// Creates a new 4-tuple, or quadruple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// An 4-tuple (quadruple) whose value is (item1, item2, item3, item4). + public static Tuple Create(T1 item1, T2 item2, T3 item3, T4 item4) + { + return new Tuple(item1, item2, item3, item4); + } + + /// + /// Creates a new 5-tuple, or quintuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// An 5-tuple (quintuple) whose value is (item1, item2, item3, item4, item5). + public static Tuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) + { + return new Tuple(item1, item2, item3, item4, item5); + } + + /// + /// Creates a new 6-tuple, or sextuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// An 6-tuple (sextuple) whose value is (item1, item2, item3, item4, item5, item6). + public static Tuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) + { + return new Tuple(item1, item2, item3, item4, item5, item6); + } + + /// + /// Creates a new 7-tuple, or septuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The type of the seventh component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// The value of the seventh component of the tuple. + /// An 7-tuple (septuple) whose value is (item1, item2, item3, item4, item5, item6, item7). + public static Tuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) + { + return new Tuple(item1, item2, item3, item4, item5, item6, item7); + } + + /// + /// Creates a new 8-tuple, or octuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The type of the seventh component of the tuple. + /// The type of the eighth component of the tuple. + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// The value of the seventh component of the tuple. + /// The value of the eighth component of the tuple. + /// An 8-tuple (octuple) whose value is (item1, item2, item3, item4, item5, item6, item7, item8). + public static Tuple> Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) + { + return new Tuple>(item1, item2, item3, item4, item5, item6, item7, new Tuple(item8)); + } + + // From System.Web.Util.HashCodeCombiner + internal static int CombineHashCodes(int h1, int h2) + { + return (((h1 << 5) + h1) ^ h2); + } + + internal static int CombineHashCodes(int h1, int h2, int h3) + { + return CombineHashCodes(CombineHashCodes(h1, h2), h3); + } + + internal static int CombineHashCodes(int h1, int h2, int h3, int h4) + { + return CombineHashCodes(CombineHashCodes(h1, h2), CombineHashCodes(h3, h4)); + } + + internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5) + { + return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), h5); + } + + internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6) + { + return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6)); + } + + internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7) + { + return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7)); + } + + internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8) + { + return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7, h8)); + } + } + + /// + /// Represents a 1-tuple, or singleton. + /// + /// The type of the tuple's only component. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + private readonly T1 m_Item1; + + /// + /// Gets the value of the tuple object's single component. + /// + /// + /// The value of the current tuple object's single component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the current tuple object's single component. + public Tuple(T1 item1) + { + m_Item1 = item1; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + return comparer.Compare(m_Item1, objTuple.m_Item1); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return comparer.GetHashCode(m_Item1); + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(")"); + return sb.ToString(); + } + + int ITuple.Size + { + get + { + return 1; + } + } + } + + /// + /// Represents an 2-tuple, or pair. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + + private readonly T1 m_Item1; + private readonly T2 m_Item2; + + /// + /// Gets the value of the current tuple object's first component. + /// + /// + /// The value of the current tuple object's first component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Gets the value of the current tuple object's second component. + /// + /// + /// The value of the current tuple object's second component. + /// + public T2 Item2 { get { return m_Item2; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + public Tuple(T1 item1, T2 item2) + { + m_Item1 = item1; + m_Item2 = item2; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + int c = 0; + + c = comparer.Compare(m_Item1, objTuple.m_Item1); + + if (c != 0) return c; + + return comparer.Compare(m_Item2, objTuple.m_Item2); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2)); + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(", "); + sb.Append(m_Item2); + sb.Append(")"); + return sb.ToString(); + } + + int ITuple.Size + { + get + { + return 2; + } + } + } + + /// + /// Represents an 3-tuple, or triple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + + private readonly T1 m_Item1; + private readonly T2 m_Item2; + private readonly T3 m_Item3; + + /// + /// Gets the value of the current tuple object's first component. + /// + /// + /// The value of the current tuple object's first component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Gets the value of the current tuple object's second component. + /// + /// + /// The value of the current tuple object's second component. + /// + public T2 Item2 { get { return m_Item2; } } + + /// + /// Gets the value of the current tuple object's third component. + /// + /// + /// The value of the current tuple object's third component. + /// + public T3 Item3 { get { return m_Item3; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + public Tuple(T1 item1, T2 item2, T3 item3) + { + m_Item1 = item1; + m_Item2 = item2; + m_Item3 = item3; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + int c = 0; + + c = comparer.Compare(m_Item1, objTuple.m_Item1); + + if (c != 0) return c; + + c = comparer.Compare(m_Item2, objTuple.m_Item2); + + if (c != 0) return c; + + return comparer.Compare(m_Item3, objTuple.m_Item3); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3)); + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(", "); + sb.Append(m_Item2); + sb.Append(", "); + sb.Append(m_Item3); + sb.Append(")"); + return sb.ToString(); + } + + int ITuple.Size + { + get + { + return 3; + } + } + } + + /// + /// Represents an 4-tuple, or quadruple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + + private readonly T1 m_Item1; + private readonly T2 m_Item2; + private readonly T3 m_Item3; + private readonly T4 m_Item4; + + /// + /// Gets the value of the current tuple object's first component. + /// + /// + /// The value of the current tuple object's first component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Gets the value of the current tuple object's second component. + /// + /// + /// The value of the current tuple object's second component. + /// + public T2 Item2 { get { return m_Item2; } } + + /// + /// Gets the value of the current tuple object's third component. + /// + /// + /// The value of the current tuple object's third component. + /// + public T3 Item3 { get { return m_Item3; } } + + /// + /// Gets the value of the current tuple object's fourth component. + /// + /// + /// The value of the current tuple object's fourth component. + /// + public T4 Item4 { get { return m_Item4; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4) + { + m_Item1 = item1; + m_Item2 = item2; + m_Item3 = item3; + m_Item4 = item4; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + int c = 0; + + c = comparer.Compare(m_Item1, objTuple.m_Item1); + + if (c != 0) return c; + + c = comparer.Compare(m_Item2, objTuple.m_Item2); + + if (c != 0) return c; + + c = comparer.Compare(m_Item3, objTuple.m_Item3); + + if (c != 0) return c; + + return comparer.Compare(m_Item4, objTuple.m_Item4); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4)); + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(", "); + sb.Append(m_Item2); + sb.Append(", "); + sb.Append(m_Item3); + sb.Append(", "); + sb.Append(m_Item4); + sb.Append(")"); + return sb.ToString(); + } + + int ITuple.Size + { + get + { + return 4; + } + } + } + + /// + /// Represents an 5-tuple, or quintuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + + private readonly T1 m_Item1; + private readonly T2 m_Item2; + private readonly T3 m_Item3; + private readonly T4 m_Item4; + private readonly T5 m_Item5; + + /// + /// Gets the value of the current tuple object's first component. + /// + /// + /// The value of the current tuple object's first component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Gets the value of the current tuple object's second component. + /// + /// + /// The value of the current tuple object's second component. + /// + public T2 Item2 { get { return m_Item2; } } + + /// + /// Gets the value of the current tuple object's third component. + /// + /// + /// The value of the current tuple object's third component. + /// + public T3 Item3 { get { return m_Item3; } } + + /// + /// Gets the value of the current tuple object's fourth component. + /// + /// + /// The value of the current tuple object's fourth component. + /// + public T4 Item4 { get { return m_Item4; } } + + /// + /// Gets the value of the current tuple object's fifth component. + /// + /// + /// The value of the current tuple object's fifth component. + /// + public T5 Item5 { get { return m_Item5; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) + { + m_Item1 = item1; + m_Item2 = item2; + m_Item3 = item3; + m_Item4 = item4; + m_Item5 = item5; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + int c = 0; + + c = comparer.Compare(m_Item1, objTuple.m_Item1); + + if (c != 0) return c; + + c = comparer.Compare(m_Item2, objTuple.m_Item2); + + if (c != 0) return c; + + c = comparer.Compare(m_Item3, objTuple.m_Item3); + + if (c != 0) return c; + + c = comparer.Compare(m_Item4, objTuple.m_Item4); + + if (c != 0) return c; + + return comparer.Compare(m_Item5, objTuple.m_Item5); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5)); + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(", "); + sb.Append(m_Item2); + sb.Append(", "); + sb.Append(m_Item3); + sb.Append(", "); + sb.Append(m_Item4); + sb.Append(", "); + sb.Append(m_Item5); + sb.Append(")"); + return sb.ToString(); + } + + int ITuple.Size + { + get + { + return 5; + } + } + } + + /// + /// Represents an 6-tuple, or sextuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + + private readonly T1 m_Item1; + private readonly T2 m_Item2; + private readonly T3 m_Item3; + private readonly T4 m_Item4; + private readonly T5 m_Item5; + private readonly T6 m_Item6; + + /// + /// Gets the value of the current tuple object's first component. + /// + /// + /// The value of the current tuple object's first component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Gets the value of the current tuple object's second component. + /// + /// + /// The value of the current tuple object's second component. + /// + public T2 Item2 { get { return m_Item2; } } + + /// + /// Gets the value of the current tuple object's third component. + /// + /// + /// The value of the current tuple object's third component. + /// + public T3 Item3 { get { return m_Item3; } } + + /// + /// Gets the value of the current tuple object's fourth component. + /// + /// + /// The value of the current tuple object's fourth component. + /// + public T4 Item4 { get { return m_Item4; } } + + /// + /// Gets the value of the current tuple object's fifth component. + /// + /// + /// The value of the current tuple object's fifth component. + /// + public T5 Item5 { get { return m_Item5; } } + + /// + /// Gets the value of the current tuple object's sixth component. + /// + /// + /// The value of the current tuple object's sixth component. + /// + public T6 Item6 { get { return m_Item6; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) + { + m_Item1 = item1; + m_Item2 = item2; + m_Item3 = item3; + m_Item4 = item4; + m_Item5 = item5; + m_Item6 = item6; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5) && comparer.Equals(m_Item6, objTuple.m_Item6); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + int c = 0; + + c = comparer.Compare(m_Item1, objTuple.m_Item1); + + if (c != 0) return c; + + c = comparer.Compare(m_Item2, objTuple.m_Item2); + + if (c != 0) return c; + + c = comparer.Compare(m_Item3, objTuple.m_Item3); + + if (c != 0) return c; + + c = comparer.Compare(m_Item4, objTuple.m_Item4); + + if (c != 0) return c; + + c = comparer.Compare(m_Item5, objTuple.m_Item5); + + if (c != 0) return c; + + return comparer.Compare(m_Item6, objTuple.m_Item6); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6)); + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(", "); + sb.Append(m_Item2); + sb.Append(", "); + sb.Append(m_Item3); + sb.Append(", "); + sb.Append(m_Item4); + sb.Append(", "); + sb.Append(m_Item5); + sb.Append(", "); + sb.Append(m_Item6); + sb.Append(")"); + return sb.ToString(); + } + + int ITuple.Size + { + get + { + return 6; + } + } + } + + /// + /// Represents an 7-tuple, or septuple. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The type of the seventh component of the tuple. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + + private readonly T1 m_Item1; + private readonly T2 m_Item2; + private readonly T3 m_Item3; + private readonly T4 m_Item4; + private readonly T5 m_Item5; + private readonly T6 m_Item6; + private readonly T7 m_Item7; + + /// + /// Gets the value of the current tuple object's first component. + /// + /// + /// The value of the current tuple object's first component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Gets the value of the current tuple object's second component. + /// + /// + /// The value of the current tuple object's second component. + /// + public T2 Item2 { get { return m_Item2; } } + + /// + /// Gets the value of the current tuple object's third component. + /// + /// + /// The value of the current tuple object's third component. + /// + public T3 Item3 { get { return m_Item3; } } + + /// + /// Gets the value of the current tuple object's fourth component. + /// + /// + /// The value of the current tuple object's fourth component. + /// + public T4 Item4 { get { return m_Item4; } } + + /// + /// Gets the value of the current tuple object's fifth component. + /// + /// + /// The value of the current tuple object's fifth component. + /// + public T5 Item5 { get { return m_Item5; } } + + /// + /// Gets the value of the current tuple object's sixth component. + /// + /// + /// The value of the current tuple object's sixth component. + /// + public T6 Item6 { get { return m_Item6; } } + + /// + /// Gets the value of the current tuple object's seventh component. + /// + /// + /// The value of the current tuple object's seventh component. + /// + public T7 Item7 { get { return m_Item7; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// The value of the seventh component of the tuple. + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) + { + m_Item1 = item1; + m_Item2 = item2; + m_Item3 = item3; + m_Item4 = item4; + m_Item5 = item5; + m_Item6 = item6; + m_Item7 = item7; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5) && comparer.Equals(m_Item6, objTuple.m_Item6) && comparer.Equals(m_Item7, objTuple.m_Item7); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + int c = 0; + + c = comparer.Compare(m_Item1, objTuple.m_Item1); + + if (c != 0) return c; + + c = comparer.Compare(m_Item2, objTuple.m_Item2); + + if (c != 0) return c; + + c = comparer.Compare(m_Item3, objTuple.m_Item3); + + if (c != 0) return c; + + c = comparer.Compare(m_Item4, objTuple.m_Item4); + + if (c != 0) return c; + + c = comparer.Compare(m_Item5, objTuple.m_Item5); + + if (c != 0) return c; + + c = comparer.Compare(m_Item6, objTuple.m_Item6); + + if (c != 0) return c; + + return comparer.Compare(m_Item7, objTuple.m_Item7); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7)); + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(", "); + sb.Append(m_Item2); + sb.Append(", "); + sb.Append(m_Item3); + sb.Append(", "); + sb.Append(m_Item4); + sb.Append(", "); + sb.Append(m_Item5); + sb.Append(", "); + sb.Append(m_Item6); + sb.Append(", "); + sb.Append(m_Item7); + sb.Append(")"); + return sb.ToString(); + } + + int ITuple.Size + { + get + { + return 7; + } + } + } + + /// + /// Represents an n-tuple, where n is 8 or greater. + /// + /// The type of the first component of the tuple. + /// The type of the second component of the tuple. + /// The type of the third component of the tuple. + /// The type of the fourth component of the tuple. + /// The type of the fifth component of the tuple. + /// The type of the sixth component of the tuple. + /// The type of the seventh component of the tuple. + /// Any generic Tuple object that defines the types of the tuple's remaining components. + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple + { + + private readonly T1 m_Item1; + private readonly T2 m_Item2; + private readonly T3 m_Item3; + private readonly T4 m_Item4; + private readonly T5 m_Item5; + private readonly T6 m_Item6; + private readonly T7 m_Item7; + private readonly TRest m_Rest; + + /// + /// Gets the value of the current tuple object's first component. + /// + /// + /// The value of the current tuple object's first component. + /// + public T1 Item1 { get { return m_Item1; } } + + /// + /// Gets the value of the current tuple object's second component. + /// + /// + /// The value of the current tuple object's second component. + /// + public T2 Item2 { get { return m_Item2; } } + + /// + /// Gets the value of the current tuple object's third component. + /// + /// + /// The value of the current tuple object's third component. + /// + public T3 Item3 { get { return m_Item3; } } + + /// + /// Gets the value of the current tuple object's fourth component. + /// + /// + /// The value of the current tuple object's fourth component. + /// + public T4 Item4 { get { return m_Item4; } } + + /// + /// Gets the value of the current tuple object's fifth component. + /// + /// + /// The value of the current tuple object's fifth component. + /// + public T5 Item5 { get { return m_Item5; } } + + /// + /// Gets the value of the current tuple object's sixth component. + /// + /// + /// The value of the current tuple object's sixth component. + /// + public T6 Item6 { get { return m_Item6; } } + + /// + /// Gets the value of the current tuple object's seventh component. + /// + /// + /// The value of the current tuple object's seventh component. + /// + public T7 Item7 { get { return m_Item7; } } + + /// + /// Gets the current tuple object's remaining components. + /// + /// + /// The value of the current tuple object's remaining components. + /// + public TRest Rest { get { return m_Rest; } } + + /// + /// Initializes a new instance of the class. + /// + /// The value of the first component of the tuple. + /// The value of the second component of the tuple. + /// The value of the third component of the tuple. + /// The value of the fourth component of the tuple. + /// The value of the fifth component of the tuple. + /// The value of the sixth component of the tuple. + /// The value of the seventh component of the tuple. + /// Any generic Tuple object that contains the values of the tuple's remaining components. + /// + /// rest is not a generic Tuple object. + /// + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) + { + if (!(rest is ITuple)) + { + throw new ArgumentException(Strings.ArgumentException_TupleLastArgumentNotATuple); + } + + m_Item1 = item1; + m_Item2 = item2; + m_Item3 = item3; + m_Item4 = item4; + m_Item5 = item5; + m_Item6 = item6; + m_Item7 = item7; + m_Rest = rest; + } + + /// + /// Returns a value that indicates whether the current tuple object is equal to a specified object. + /// + /// The object to compare with this instance. + /// true if the current instance is equal to the specified object; otherwise, false. + public override Boolean Equals(Object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); ; + } + + Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) + { + if (other == null) return false; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + return false; + } + + return comparer.Equals(m_Item1, objTuple.m_Item1) && comparer.Equals(m_Item2, objTuple.m_Item2) && comparer.Equals(m_Item3, objTuple.m_Item3) && comparer.Equals(m_Item4, objTuple.m_Item4) && comparer.Equals(m_Item5, objTuple.m_Item5) && comparer.Equals(m_Item6, objTuple.m_Item6) && comparer.Equals(m_Item7, objTuple.m_Item7) && comparer.Equals(m_Rest, objTuple.m_Rest); + } + + Int32 IComparable.CompareTo(Object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) + { + if (other == null) return 1; + + Tuple objTuple = other as Tuple; + + if (objTuple == null) + { + throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, Strings.ArgumentException_TupleIncorrectType, GetType().ToString()), "other"); + } + + int c = 0; + + c = comparer.Compare(m_Item1, objTuple.m_Item1); + + if (c != 0) return c; + + c = comparer.Compare(m_Item2, objTuple.m_Item2); + + if (c != 0) return c; + + c = comparer.Compare(m_Item3, objTuple.m_Item3); + + if (c != 0) return c; + + c = comparer.Compare(m_Item4, objTuple.m_Item4); + + if (c != 0) return c; + + c = comparer.Compare(m_Item5, objTuple.m_Item5); + + if (c != 0) return c; + + c = comparer.Compare(m_Item6, objTuple.m_Item6); + + if (c != 0) return c; + + c = comparer.Compare(m_Item7, objTuple.m_Item7); + + if (c != 0) return c; + + return comparer.Compare(m_Rest, objTuple.m_Rest); + } + + /// + /// Calculates the hash code for the current tuple object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return ((IStructuralEquatable)this).GetHashCode(EqualityComparer.Default); + } + + Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple + ITuple t = (ITuple)m_Rest; + if (t.Size >= 8) { return t.GetHashCode(comparer); } + + // In this case, the rest memeber has less than 8 elements so we need to combine some our elements with the elements in rest + int k = 8 - t.Size; + switch (k) + { + case 1: + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); + case 2: + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); + case 3: + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); + case 4: + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); + case 5: + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); + case 6: + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); + case 7: + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); + } + //Contract.Assert(false, "Missed all cases for computing Tuple hash code"); + return -1; + } + + Int32 ITuple.GetHashCode(IEqualityComparer comparer) + { + return ((IStructuralEquatable)this).GetHashCode(comparer); + } + + /// + /// Returns a string that represents the value of this tuple instance. + /// + /// The string representation of this tuple object. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + return ((ITuple)this).ToString(sb); + } + + string ITuple.ToString(StringBuilder sb) + { + sb.Append(m_Item1); + sb.Append(", "); + sb.Append(m_Item2); + sb.Append(", "); + sb.Append(m_Item3); + sb.Append(", "); + sb.Append(m_Item4); + sb.Append(", "); + sb.Append(m_Item5); + sb.Append(", "); + sb.Append(m_Item6); + sb.Append(", "); + sb.Append(m_Item7); + sb.Append(", "); + return ((ITuple)m_Rest).ToString(sb); + } + + int ITuple.Size + { + get + { + return 7 + ((ITuple)m_Rest).Size; + } + } + } +} + diff --git a/Microsoft.Bcl/System.Runtime.v2.5/Properties/AssemblyInfo.cs b/Microsoft.Bcl/System.Runtime.v2.5/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..1966be555 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v2.5/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("System.Runtime")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("System.Runtime")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +[assembly: TypeForwardedTo(typeof(Func<,,,,,>))] +[assembly: TypeForwardedTo(typeof(Tuple))] +[assembly: TypeForwardedTo(typeof(Tuple<>))] +[assembly: TypeForwardedTo(typeof(Tuple<,>))] +[assembly: TypeForwardedTo(typeof(Tuple<,,>))] +[assembly: TypeForwardedTo(typeof(Tuple<,,,>))] +[assembly: TypeForwardedTo(typeof(Tuple<,,,,>))] +[assembly: TypeForwardedTo(typeof(Tuple<,,,,,>))] +[assembly: TypeForwardedTo(typeof(Tuple<,,,,,,>))] +[assembly: TypeForwardedTo(typeof(Tuple<,,,,,,,>))] +[assembly: TypeForwardedTo(typeof(IStructuralComparable))] +[assembly: TypeForwardedTo(typeof(IStructuralEquatable))] diff --git a/Microsoft.Bcl/System.Runtime.v2.5/System.Runtime.v2.5.csproj b/Microsoft.Bcl/System.Runtime.v2.5/System.Runtime.v2.5.csproj new file mode 100644 index 000000000..dcda83652 --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v2.5/System.Runtime.v2.5.csproj @@ -0,0 +1,77 @@ + + + + + 10.0 + Debug + AnyCPU + {64A2361B-9B62-4D21-8012-E3317696327E} + Library + Properties + System + System.Runtime + v4.0 + Profile36 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;VARIANCE + prompt + 4 + bin\Debug\System.Runtime.xml + SecurityRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE;VARIANCE + prompt + 4 + bin\Release\System.Runtime.xml + + + true + true + ..\CodePlexKey.snk + + + + + + + System\Progress.cs + + + System\Runtime\CompilerServices\AsyncStateMachineAttribute.cs + + + System\Runtime\CompilerServices\CallerInfoAttributes.cs + + + System\Runtime\CompilerServices\IteratorStateMachineAttribute.cs + + + System\Runtime\CompilerServices\StateMachineAttribute.cs + + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.Runtime.v2.5/System.Runtime.v2.5.csproj.vspscc b/Microsoft.Bcl/System.Runtime.v2.5/System.Runtime.v2.5.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl/System.Runtime.v2.5/System.Runtime.v2.5.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/Properties/AssemblyInfo.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..41721dd1c --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System.Resources; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("System.Threading.Tasks")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("System.Threading.Tasks")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/Strings.Designer.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/Strings.Designer.cs new file mode 100644 index 000000000..6613ac9cc --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/Strings.Designer.cs @@ -0,0 +1,639 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.17929 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace System { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to One or more errors occurred.. + /// + internal static string AggregateException_ctor_DefaultMessage { + get { + return ResourceManager.GetString("AggregateException_ctor_DefaultMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An element of innerExceptions was null.. + /// + internal static string AggregateException_ctor_InnerExceptionNull { + get { + return ResourceManager.GetString("AggregateException_ctor_InnerExceptionNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}{1}---> (Inner Exception #{2}) {3}{4}{5}. + /// + internal static string AggregateException_ToString { + get { + return ResourceManager.GetString("AggregateException_ToString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No tokens were supplied.. + /// + internal static string CancellationToken_CreateLinkedToken_TokensIsEmpty { + get { + return ResourceManager.GetString("CancellationToken_CreateLinkedToken_TokensIsEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The CancellationTokenSource associated with this CancellationToken has been disposed.. + /// + internal static string CancellationToken_SourceDisposed { + get { + return ResourceManager.GetString("CancellationToken_SourceDisposed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The CancellationTokenSource has been disposed.. + /// + internal static string CancellationTokenSource_Disposed { + get { + return ResourceManager.GetString("CancellationTokenSource_Disposed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The SyncRoot property may not be used for the synchronization of concurrent collections.. + /// + internal static string ConcurrentCollection_SyncRoot_NotSupported { + get { + return ResourceManager.GetString("ConcurrentCollection_SyncRoot_NotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The array is multidimensional, or the type parameter for the set cannot be cast automatically to the type of the destination array.. + /// + internal static string ConcurrentDictionary_ArrayIncorrectType { + get { + return ResourceManager.GetString("ConcurrentDictionary_ArrayIncorrectType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The index is equal to or greater than the length of the array, or the number of elements in the dictionary is greater than the available space from index to the end of the destination array.. + /// + internal static string ConcurrentDictionary_ArrayNotLargeEnough { + get { + return ResourceManager.GetString("ConcurrentDictionary_ArrayNotLargeEnough", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The capacity argument must be greater than or equal to zero.. + /// + internal static string ConcurrentDictionary_CapacityMustNotBeNegative { + get { + return ResourceManager.GetString("ConcurrentDictionary_CapacityMustNotBeNegative", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The concurrencyLevel argument must be positive.. + /// + internal static string ConcurrentDictionary_ConcurrencyLevelMustBePositive { + get { + return ResourceManager.GetString("ConcurrentDictionary_ConcurrencyLevelMustBePositive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The index argument is less than zero.. + /// + internal static string ConcurrentDictionary_IndexIsNegative { + get { + return ResourceManager.GetString("ConcurrentDictionary_IndexIsNegative", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TKey is a reference type and item.Key is null.. + /// + internal static string ConcurrentDictionary_ItemKeyIsNull { + get { + return ResourceManager.GetString("ConcurrentDictionary_ItemKeyIsNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The key already existed in the dictionary.. + /// + internal static string ConcurrentDictionary_KeyAlreadyExisted { + get { + return ResourceManager.GetString("ConcurrentDictionary_KeyAlreadyExisted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The source argument contains duplicate keys.. + /// + internal static string ConcurrentDictionary_SourceContainsDuplicateKeys { + get { + return ResourceManager.GetString("ConcurrentDictionary_SourceContainsDuplicateKeys", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The key was of an incorrect type for this dictionary.. + /// + internal static string ConcurrentDictionary_TypeOfKeyIncorrect { + get { + return ResourceManager.GetString("ConcurrentDictionary_TypeOfKeyIncorrect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value was of an incorrect type for this dictionary.. + /// + internal static string ConcurrentDictionary_TypeOfValueIncorrect { + get { + return ResourceManager.GetString("ConcurrentDictionary_TypeOfValueIncorrect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The lazily-initialized type does not have a public, parameterless constructor.. + /// + internal static string Lazy_CreateValue_NoParameterlessCtorForT { + get { + return ResourceManager.GetString("Lazy_CreateValue_NoParameterlessCtorForT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ValueFactory returned null.. + /// + internal static string Lazy_StaticInit_InvalidOperation { + get { + return ResourceManager.GetString("Lazy_StaticInit_InvalidOperation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The spinCount argument must be in the range 0 to {0}, inclusive.. + /// + internal static string ManualResetEventSlim_ctor_SpinCountOutOfRange { + get { + return ResourceManager.GetString("ManualResetEventSlim_ctor_SpinCountOutOfRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are too many threads currently waiting on the event. A maximum of {0} waiting threads are supported.. + /// + internal static string ManualResetEventSlim_ctor_TooManyWaiters { + get { + return ResourceManager.GetString("ManualResetEventSlim_ctor_TooManyWaiters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The event has been disposed.. + /// + internal static string ManualResetEventSlim_Disposed { + get { + return ResourceManager.GetString("ManualResetEventSlim_Disposed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The operation was canceled.. + /// + internal static string OperationCanceled { + get { + return ResourceManager.GetString("OperationCanceled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The condition argument is null.. + /// + internal static string SpinWait_SpinUntil_ArgumentNull { + get { + return ResourceManager.GetString("SpinWait_SpinUntil_ArgumentNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The timeout must represent a value between -1 and Int32.MaxValue, inclusive.. + /// + internal static string SpinWait_SpinUntil_TimeoutWrong { + get { + return ResourceManager.GetString("SpinWait_SpinUntil_TimeoutWrong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified TaskContinuationOptions combined LongRunning and ExecuteSynchronously. Synchronous continuations should not be long running.. + /// + internal static string Task_ContinueWith_ESandLR { + get { + return ResourceManager.GetString("Task_ContinueWith_ESandLR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified TaskContinuationOptions excluded all continuation kinds.. + /// + internal static string Task_ContinueWith_NotOnAnything { + get { + return ResourceManager.GetString("Task_ContinueWith_NotOnAnything", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (Internal)An attempt was made to create a LongRunning SelfReplicating task.. + /// + internal static string Task_ctor_LRandSR { + get { + return ResourceManager.GetString("Task_ctor_LRandSR", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue.. + /// + internal static string Task_Delay_InvalidDelay { + get { + return ResourceManager.GetString("Task_Delay_InvalidDelay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value needs to be either -1 (signifying an infinite timeout), 0 or a positive integer.. + /// + internal static string Task_Delay_InvalidMillisecondsDelay { + get { + return ResourceManager.GetString("Task_Delay_InvalidMillisecondsDelay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled).. + /// + internal static string Task_Dispose_NotCompleted { + get { + return ResourceManager.GetString("Task_Dispose_NotCompleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is invalid to specify TaskCreationOptions.LongRunning in calls to FromAsync.. + /// + internal static string Task_FromAsync_LongRunning { + get { + return ResourceManager.GetString("Task_FromAsync_LongRunning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is invalid to specify TaskCreationOptions.PreferFairness in calls to FromAsync.. + /// + internal static string Task_FromAsync_PreferFairness { + get { + return ResourceManager.GetString("Task_FromAsync_PreferFairness", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is invalid to specify TaskCreationOptions.SelfReplicating in calls to FromAsync.. + /// + internal static string Task_FromAsync_SelfReplicating { + get { + return ResourceManager.GetString("Task_FromAsync_SelfReplicating", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to FromAsync was called with a TaskManager that had already shut down.. + /// + internal static string Task_FromAsync_TaskManagerShutDown { + get { + return ResourceManager.GetString("Task_FromAsync_TaskManagerShutDown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tasks argument contains no tasks.. + /// + internal static string Task_MultiTaskContinuation_EmptyTaskList { + get { + return ResourceManager.GetString("Task_MultiTaskContinuation_EmptyTaskList", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is invalid to exclude specific continuation kinds for continuations off of multiple tasks.. + /// + internal static string Task_MultiTaskContinuation_FireOptions { + get { + return ResourceManager.GetString("Task_MultiTaskContinuation_FireOptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tasks argument included a null value.. + /// + internal static string Task_MultiTaskContinuation_NullTask { + get { + return ResourceManager.GetString("Task_MultiTaskContinuation_NullTask", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RunSynchronously may not be called on a task that was already started.. + /// + internal static string Task_RunSynchronously_AlreadyStarted { + get { + return ResourceManager.GetString("Task_RunSynchronously_AlreadyStarted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RunSynchronously may not be called on a continuation task.. + /// + internal static string Task_RunSynchronously_Continuation { + get { + return ResourceManager.GetString("Task_RunSynchronously_Continuation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.. + /// + internal static string Task_RunSynchronously_Promise { + get { + return ResourceManager.GetString("Task_RunSynchronously_Promise", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RunSynchronously may not be called on a task that has already completed.. + /// + internal static string Task_RunSynchronously_TaskCompleted { + get { + return ResourceManager.GetString("Task_RunSynchronously_TaskCompleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start may not be called on a task that was already started.. + /// + internal static string Task_Start_AlreadyStarted { + get { + return ResourceManager.GetString("Task_Start_AlreadyStarted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start may not be called on a continuation task.. + /// + internal static string Task_Start_ContinuationTask { + get { + return ResourceManager.GetString("Task_Start_ContinuationTask", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start may not be called on a task with null action.. + /// + internal static string Task_Start_NullAction { + get { + return ResourceManager.GetString("Task_Start_NullAction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start may not be called on a promise-style task.. + /// + internal static string Task_Start_Promise { + get { + return ResourceManager.GetString("Task_Start_Promise", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start may not be called on a task that has completed.. + /// + internal static string Task_Start_TaskCompleted { + get { + return ResourceManager.GetString("Task_Start_TaskCompleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The task has been disposed.. + /// + internal static string Task_ThrowIfDisposed { + get { + return ResourceManager.GetString("Task_ThrowIfDisposed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The tasks array included at least one null element.. + /// + internal static string Task_WaitMulti_NullTask { + get { + return ResourceManager.GetString("Task_WaitMulti_NullTask", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The awaited task has not yet completed.. + /// + internal static string TaskAwaiter_TaskNotCompleted { + get { + return ResourceManager.GetString("TaskAwaiter_TaskNotCompleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A task was canceled.. + /// + internal static string TaskCanceledException_ctor_DefaultMessage { + get { + return ResourceManager.GetString("TaskCanceledException_ctor_DefaultMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The exceptions collection was empty.. + /// + internal static string TaskCompletionSourceT_TrySetException_NoExceptions { + get { + return ResourceManager.GetString("TaskCompletionSourceT_TrySetException_NoExceptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The exceptions collection included at least one null element.. + /// + internal static string TaskCompletionSourceT_TrySetException_NullException { + get { + return ResourceManager.GetString("TaskCompletionSourceT_TrySetException_NullException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.. + /// + internal static string TaskExceptionHolder_UnhandledException { + get { + return ResourceManager.GetString("TaskExceptionHolder_UnhandledException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (Internal)Expected an Exception or an IEnumerable<Exception>. + /// + internal static string TaskExceptionHolder_UnknownExceptionType { + get { + return ResourceManager.GetString("TaskExceptionHolder_UnknownExceptionType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ExecuteTask may not be called for a task which was already executed.. + /// + internal static string TaskScheduler_ExecuteTask_TaskAlreadyExecuted { + get { + return ResourceManager.GetString("TaskScheduler_ExecuteTask_TaskAlreadyExecuted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ExecuteTask may not be called for a task which was previously queued to a different TaskScheduler.. + /// + internal static string TaskScheduler_ExecuteTask_WrongTaskScheduler { + get { + return ResourceManager.GetString("TaskScheduler_ExecuteTask_WrongTaskScheduler", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The current SynchronizationContext may not be used as a TaskScheduler.. + /// + internal static string TaskScheduler_FromCurrentSynchronizationContext_NoCurrent { + get { + return ResourceManager.GetString("TaskScheduler_FromCurrentSynchronizationContext_NoCurrent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The TryExecuteTaskInline call to the underlying scheduler succeeded, but the task body was not invoked.. + /// + internal static string TaskScheduler_InconsistentStateAfterTryExecuteTaskInline { + get { + return ResourceManager.GetString("TaskScheduler_InconsistentStateAfterTryExecuteTaskInline", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An exception was thrown by a TaskScheduler.. + /// + internal static string TaskSchedulerException_ctor_DefaultMessage { + get { + return ResourceManager.GetString("TaskSchedulerException_ctor_DefaultMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is invalid to specify TaskCreationOptions.SelfReplicating for a Task<TResult>.. + /// + internal static string TaskT_ctor_SelfReplicating { + get { + return ResourceManager.GetString("TaskT_ctor_SelfReplicating", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {Not yet computed}. + /// + internal static string TaskT_DebuggerNoResult { + get { + return ResourceManager.GetString("TaskT_DebuggerNoResult", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A task's Exception may only be set directly if the task was created without a function.. + /// + internal static string TaskT_SetException_HasAnInitializer { + get { + return ResourceManager.GetString("TaskT_SetException_HasAnInitializer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An attempt was made to transition a task to a final state when it had already completed.. + /// + internal static string TaskT_TransitionToFinal_AlreadyCompleted { + get { + return ResourceManager.GetString("TaskT_TransitionToFinal_AlreadyCompleted", resourceCulture); + } + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/Strings.resx b/Microsoft.Bcl/System.Threading.Tasks.v1.5/Strings.resx new file mode 100644 index 000000000..dc14022d0 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/Strings.resx @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + One or more errors occurred. + + + An element of innerExceptions was null. + + + {0}{1}---> (Inner Exception #{2}) {3}{4}{5} + + + The CancellationTokenSource has been disposed. + + + No tokens were supplied. + + + The CancellationTokenSource associated with this CancellationToken has been disposed. + + + The SyncRoot property may not be used for the synchronization of concurrent collections. + + + The array is multidimensional, or the type parameter for the set cannot be cast automatically to the type of the destination array. + + + The index is equal to or greater than the length of the array, or the number of elements in the dictionary is greater than the available space from index to the end of the destination array. + + + The capacity argument must be greater than or equal to zero. + + + The concurrencyLevel argument must be positive. + + + The index argument is less than zero. + + + TKey is a reference type and item.Key is null. + + + The key already existed in the dictionary. + + + The source argument contains duplicate keys. + + + The key was of an incorrect type for this dictionary. + + + The value was of an incorrect type for this dictionary. + + + The operation was canceled. + + + The awaited task has not yet completed. + + + A task was canceled. + + + The exceptions collection was empty. + + + The exceptions collection included at least one null element. + + + A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. + + + (Internal)Expected an Exception or an IEnumerable<Exception> + + + An exception was thrown by a TaskScheduler. + + + ExecuteTask may not be called for a task which was already executed. + + + ExecuteTask may not be called for a task which was previously queued to a different TaskScheduler. + + + The current SynchronizationContext may not be used as a TaskScheduler. + + + The TryExecuteTaskInline call to the underlying scheduler succeeded, but the task body was not invoked. + + + It is invalid to specify TaskCreationOptions.SelfReplicating for a Task<TResult>. + + + {Not yet computed} + + + A task's Exception may only be set directly if the task was created without a function. + + + An attempt was made to transition a task to a final state when it had already completed. + + + The specified TaskContinuationOptions combined LongRunning and ExecuteSynchronously. Synchronous continuations should not be long running. + + + The specified TaskContinuationOptions excluded all continuation kinds. + + + (Internal)An attempt was made to create a LongRunning SelfReplicating task. + + + The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue. + + + The value needs to be either -1 (signifying an infinite timeout), 0 or a positive integer. + + + A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled). + + + It is invalid to specify TaskCreationOptions.LongRunning in calls to FromAsync. + + + It is invalid to specify TaskCreationOptions.PreferFairness in calls to FromAsync. + + + It is invalid to specify TaskCreationOptions.SelfReplicating in calls to FromAsync. + + + FromAsync was called with a TaskManager that had already shut down. + + + The tasks argument contains no tasks. + + + It is invalid to exclude specific continuation kinds for continuations off of multiple tasks. + + + The tasks argument included a null value. + + + RunSynchronously may not be called on a task that was already started. + + + RunSynchronously may not be called on a continuation task. + + + RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method. + + + RunSynchronously may not be called on a task that has already completed. + + + Start may not be called on a task that was already started. + + + Start may not be called on a continuation task. + + + Start may not be called on a promise-style task. + + + Start may not be called on a task that has completed. + + + The task has been disposed. + + + The tasks array included at least one null element. + + + The lazily-initialized type does not have a public, parameterless constructor. + + + ValueFactory returned null. + + + The spinCount argument must be in the range 0 to {0}, inclusive. + + + There are too many threads currently waiting on the event. A maximum of {0} waiting threads are supported. + + + The event has been disposed. + + + The condition argument is null. + + + The timeout must represent a value between -1 and Int32.MaxValue, inclusive. + + + Start may not be called on a task with null action. + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System.Threading.Tasks.v1.5.csproj b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System.Threading.Tasks.v1.5.csproj new file mode 100644 index 000000000..9cdbada8f --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System.Threading.Tasks.v1.5.csproj @@ -0,0 +1,120 @@ + + + + + 10.0 + Debug + AnyCPU + {816208A5-320B-4998-9B34-0895630A9A8F} + Library + Properties + System + System.Threading.Tasks + v4.0 + Profile88 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + bin\Debug\System.Threading.Tasks.xml + SecurityRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\System.Threading.Tasks.xml + + + true + true + ..\CodePlexKey.snk + + + + + {42db1993-8ebb-4827-bc05-f3906ea8cfbc} + System.Runtime.v1.5 + + + + + + + Strings.resx + True + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ResXFileCodeGenerator + Strings.Designer.cs + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System.Threading.Tasks.v1.5.csproj.vspscc b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System.Threading.Tasks.v1.5.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System.Threading.Tasks.v1.5.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/AggregateException.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/AggregateException.cs new file mode 100644 index 000000000..e70a829f5 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/AggregateException.cs @@ -0,0 +1,314 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.Serialization; +using System.Security; +using System.Threading; + +namespace System +{ + + /// Represents one or more errors that occur during application execution. + /// + /// is used to consolidate multiple failures into a single, throwable + /// exception object. + /// + [DebuggerDisplay("Count = {InnerExceptions.Count}")] + public class AggregateException : Exception + { + + private ReadOnlyCollection m_innerExceptions; // Complete set of exceptions. + + /// + /// Initializes a new instance of the class. + /// + public AggregateException() + : base(Strings.AggregateException_ctor_DefaultMessage) + { + m_innerExceptions = new ReadOnlyCollection(new Exception[0]); + } + + /// + /// Initializes a new instance of the class with + /// a specified error message. + /// + /// The error message that explains the reason for the exception. + public AggregateException(string message) + : base(message) + { + m_innerExceptions = new ReadOnlyCollection(new Exception[0]); + } + + /// + /// Initializes a new instance of the class with a specified error + /// message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. + /// The argument + /// is null. + public AggregateException(string message, Exception innerException) + : base(message, innerException) + { + if (innerException == null) + { + throw new ArgumentNullException("innerException"); + } + + m_innerExceptions = new ReadOnlyCollection(new Exception[] { innerException }); + } + + /// + /// Initializes a new instance of the class with + /// references to the inner exceptions that are the cause of this exception. + /// + /// The exceptions that are the cause of the current exception. + /// The argument + /// is null. + /// An element of is + /// null. + public AggregateException(IEnumerable innerExceptions) : + this(Strings.AggregateException_ctor_DefaultMessage, innerExceptions) + { + } + + /// + /// Initializes a new instance of the class with + /// references to the inner exceptions that are the cause of this exception. + /// + /// The exceptions that are the cause of the current exception. + /// The argument + /// is null. + /// An element of is + /// null. + public AggregateException(params Exception[] innerExceptions) : + this(Strings.AggregateException_ctor_DefaultMessage, innerExceptions) + { + } + + /// + /// Initializes a new instance of the class with a specified error + /// message and references to the inner exceptions that are the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exceptions that are the cause of the current exception. + /// The argument + /// is null. + /// An element of is + /// null. + public AggregateException(string message, IEnumerable innerExceptions) + : this(message, innerExceptions == null ? (List)null : new List(innerExceptions)) + { + } + + /// + /// Initializes a new instance of the class with a specified error + /// message and references to the inner exceptions that are the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exceptions that are the cause of the current exception. + /// The argument + /// is null. + /// An element of is + /// null. + public AggregateException(string message, params Exception[] innerExceptions) : + this(message, (IList)innerExceptions) + { + } + + /// + /// Allocates a new aggregate exception with the specified message and list of inner exceptions. + /// + /// The error message that explains the reason for the exception. + /// The exceptions that are the cause of the current exception. + /// The argument + /// is null. + /// An element of is + /// null. + private AggregateException(string message, IList innerExceptions) + : base(message, innerExceptions != null && innerExceptions.Count > 0 ? innerExceptions[0] : null) + { + if (innerExceptions == null) + { + throw new ArgumentNullException("innerExceptions"); + } + + // Copy exceptions to our internal array and validate them. We must copy them, + // because we're going to put them into a ReadOnlyCollection which simply reuses + // the list passed in to it. We don't want callers subsequently mutating. + Exception[] exceptionsCopy = new Exception[innerExceptions.Count]; + + for (int i = 0; i < exceptionsCopy.Length; i++) + { + exceptionsCopy[i] = innerExceptions[i]; + + if (exceptionsCopy[i] == null) + { + throw new ArgumentException(Strings.AggregateException_ctor_InnerExceptionNull); + } + } + + m_innerExceptions = new ReadOnlyCollection(exceptionsCopy); + } + + /// + /// Returns the that is the root cause of this exception. + /// + public override Exception GetBaseException() + { + // Returns the first inner AggregateException that contains more or less than one inner exception + + // Recursively traverse the inner exceptions as long as the inner exception of type AggregateException and has only one inner exception + Exception back = this; + AggregateException backAsAggregate = this; + while (backAsAggregate != null && backAsAggregate.InnerExceptions.Count == 1) + { + back = back.InnerException; + backAsAggregate = back as AggregateException; + } + return back; + } + + /// + /// Gets a read-only collection of the instances that caused the + /// current exception. + /// + public ReadOnlyCollection InnerExceptions + { + get { return m_innerExceptions; } + } + + /// + /// Invokes a handler on each contained by this . + /// + /// The predicate to execute for each exception. The predicate accepts as an + /// argument the to be processed and returns a Boolean to indicate + /// whether the exception was handled. + /// + /// Each invocation of the returns true or false to indicate whether the + /// was handled. After all invocations, if any exceptions went + /// unhandled, all unhandled exceptions will be put into a new + /// which will be thrown. Otherwise, the method simply returns. If any + /// invocations of the throws an exception, it will halt the processing + /// of any more exceptions and immediately propagate the thrown exception as-is. + /// + /// An exception contained by this was not handled. + /// The argument is + /// null. + public void Handle(Func predicate) + { + if (predicate == null) + { + throw new ArgumentNullException("predicate"); + } + + List unhandledExceptions = null; + for (int i = 0; i < m_innerExceptions.Count; i++) + { + // If the exception was not handled, lazily allocate a list of unhandled + // exceptions (to be rethrown later) and add it. + if (!predicate(m_innerExceptions[i])) + { + if (unhandledExceptions == null) + { + unhandledExceptions = new List(); + } + + unhandledExceptions.Add(m_innerExceptions[i]); + } + } + + // If there are unhandled exceptions remaining, throw them. + if (unhandledExceptions != null) + { + throw new AggregateException(Message, unhandledExceptions); + } + } + + /// + /// Flattens an instances into a single, new instance. + /// + /// A new, flattened . + /// + /// If any inner exceptions are themselves instances of + /// , this method will recursively flatten all of them. The + /// inner exceptions returned in the new + /// will be the union of all of the the inner exceptions from exception tree rooted at the provided + /// instance. + /// + public AggregateException Flatten() + { + // Initialize a collection to contain the flattened exceptions. + List flattenedExceptions = new List(); + + // Create a list to remember all aggregates to be flattened, this will be accessed like a FIFO queue + List exceptionsToFlatten = new List(); + exceptionsToFlatten.Add(this); + int nDequeueIndex = 0; + + // Continue removing and recursively flattening exceptions, until there are no more. + while (exceptionsToFlatten.Count > nDequeueIndex) + { + // dequeue one from exceptionsToFlatten + IList currentInnerExceptions = exceptionsToFlatten[nDequeueIndex++].InnerExceptions; + + for (int i = 0; i < currentInnerExceptions.Count; i++) + { + Exception currentInnerException = currentInnerExceptions[i]; + + if (currentInnerException == null) + { + continue; + } + + AggregateException currentInnerAsAggregate = currentInnerException as AggregateException; + + // If this exception is an aggregate, keep it around for later. Otherwise, + // simply add it to the list of flattened exceptions to be returned. + if (currentInnerAsAggregate != null) + { + exceptionsToFlatten.Add(currentInnerAsAggregate); + } + else + { + flattenedExceptions.Add(currentInnerException); + } + } + } + + + return new AggregateException(Message, flattenedExceptions); + } + + /// + /// Creates and returns a string representation of the current . + /// + /// A string representation of the current exception. + public override string ToString() + { + string text = base.ToString(); + + for (int i = 0; i < m_innerExceptions.Count; i++) + { + text = String.Format( + CultureInfo.InvariantCulture, + Strings.AggregateException_ToString, + text, Environment.NewLine, i, m_innerExceptions[i].ToString(), "<---", Environment.NewLine); + } + + return text; + } + + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Collections/Concurrent/ConcurrentDictionary.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Collections/Concurrent/ConcurrentDictionary.cs new file mode 100644 index 000000000..ba40f0f6f --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -0,0 +1,1805 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// +// igoro +/*============================================================ +** +** Class: ConcurrentDictionary +** +** +** Purpose: A scalable dictionary for concurrent access +** +** +===========================================================*/ + +// If CDS_COMPILE_JUST_THIS symbol is defined, the ConcurrentDictionary.cs file compiles separately, +// with no dependencies other than .NET Framework 3.5. + +//#define CDS_COMPILE_JUST_THIS + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Collections; +using System.Runtime.Serialization; +using System.Security; +using System.Collections.ObjectModel; + +#if !CDS_COMPILE_JUST_THIS +using System.Diagnostics.Contracts; +#endif + +namespace System.Collections.Concurrent +{ + + /// + /// Represents a thread-safe collection of keys and values. + /// + /// The type of the keys in the dictionary. + /// The type of the values in the dictionary. + /// + /// All public and protected members of are thread-safe and may be used + /// concurrently from multiple threads. + /// + + //[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))] + [DebuggerDisplay("Count = {Count}")] + internal class ConcurrentDictionary : IDictionary, IDictionary + { + + private volatile Node[] m_buckets; // A singly-linked list for each bucket. + + private object[] m_locks; // A set of locks, each guarding a section of the table. + + private volatile int[] m_countPerLock; // The number of elements guarded by each lock. + private IEqualityComparer m_comparer; // Key equality comparer + + private KeyValuePair[] m_serializationArray; // Used for custom serialization + + private int m_serializationConcurrencyLevel; // used to save the concurrency level in serialization + + private int m_serializationCapacity; // used to save the capacity in serialization + + // The default concurrency level is DEFAULT_CONCURRENCY_MULTIPLIER * #CPUs. The higher the + // DEFAULT_CONCURRENCY_MULTIPLIER, the more concurrent writes can take place without interference + // and blocking, but also the more expensive operations that require all locks become (e.g. table + // resizing, ToArray, Count, etc). According to brief benchmarks that we ran, 4 seems like a good + // compromise. + private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4; + + // The default capacity, i.e. the initial # of buckets. When choosing this value, we are making + // a trade-off between the size of a very small dictionary, and the number of resizes when + // constructing a large dictionary. Also, the capacity should not be divisible by a small prime. + private const int DEFAULT_CAPACITY = 31; + + /// + /// Initializes a new instance of the + /// class that is empty, has the default concurrency level, has the default initial capacity, and + /// uses the default comparer for the key type. + /// + public ConcurrentDictionary() : this(DefaultConcurrencyLevel, DEFAULT_CAPACITY) { } + + /// + /// Initializes a new instance of the + /// class that is empty, has the specified concurrency level and capacity, and uses the default + /// comparer for the key type. + /// + /// The estimated number of threads that will update the + /// concurrently. + /// The initial number of elements that the + /// can contain. + /// is + /// less than 1. + /// is less than + /// 0. + public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(concurrencyLevel, capacity, EqualityComparer.Default) { } + + /// + /// Initializes a new instance of the + /// class that contains elements copied from the specified , has the default concurrency + /// level, has the default initial capacity, and uses the default comparer for the key type. + /// + /// The whose elements are copied to + /// the new + /// . + /// is a null reference + /// (Nothing in Visual Basic). + /// contains one or more + /// duplicate keys. + public ConcurrentDictionary(IEnumerable> collection) : this(collection, EqualityComparer.Default) { } + + /// + /// Initializes a new instance of the + /// class that is empty, has the specified concurrency level and capacity, and uses the specified + /// . + /// + /// The + /// implementation to use when comparing keys. + /// is a null reference + /// (Nothing in Visual Basic). + public ConcurrentDictionary(IEqualityComparer comparer) : this(DefaultConcurrencyLevel, DEFAULT_CAPACITY, comparer) { } + + /// + /// Initializes a new instance of the + /// class that contains elements copied from the specified , has the default concurrency level, has the default + /// initial capacity, and uses the specified + /// . + /// + /// The whose elements are copied to + /// the new + /// . + /// The + /// implementation to use when comparing keys. + /// is a null reference + /// (Nothing in Visual Basic). -or- + /// is a null reference (Nothing in Visual Basic). + /// + public ConcurrentDictionary(IEnumerable> collection, IEqualityComparer comparer) + : this(DefaultConcurrencyLevel, collection, comparer) { } + + /// + /// Initializes a new instance of the + /// class that contains elements copied from the specified , + /// has the specified concurrency level, has the specified initial capacity, and uses the specified + /// . + /// + /// The estimated number of threads that will update the + /// concurrently. + /// The whose elements are copied to the new + /// . + /// The implementation to use + /// when comparing keys. + /// + /// is a null reference (Nothing in Visual Basic). + /// -or- + /// is a null reference (Nothing in Visual Basic). + /// + /// + /// is less than 1. + /// + /// contains one or more duplicate keys. + public ConcurrentDictionary( + int concurrencyLevel, IEnumerable> collection, IEqualityComparer comparer) + : this(concurrencyLevel, DEFAULT_CAPACITY, comparer) + { + if (collection == null) throw new ArgumentNullException("collection"); + if (comparer == null) throw new ArgumentNullException("comparer"); + + InitializeFromCollection(collection); + } + + private void InitializeFromCollection(IEnumerable> collection) + { + TValue dummy; + foreach (KeyValuePair pair in collection) + { + if (pair.Key == null) throw new ArgumentNullException("key"); + + if (!TryAddInternal(pair.Key, pair.Value, false, false, out dummy)) + { + throw new ArgumentException(Strings.ConcurrentDictionary_SourceContainsDuplicateKeys, "collection"); + } + } + } + + /// + /// Initializes a new instance of the + /// class that is empty, has the specified concurrency level, has the specified initial capacity, and + /// uses the specified . + /// + /// The estimated number of threads that will update the + /// concurrently. + /// The initial number of elements that the + /// can contain. + /// The + /// implementation to use when comparing keys. + /// + /// is less than 1. -or- + /// is less than 0. + /// + /// is a null reference + /// (Nothing in Visual Basic). + public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer comparer) + { + if (concurrencyLevel < 1) + { + throw new ArgumentOutOfRangeException("concurrencyLevel", Strings.ConcurrentDictionary_ConcurrencyLevelMustBePositive); + } + if (capacity < 0) + { + throw new ArgumentOutOfRangeException("capacity", Strings.ConcurrentDictionary_CapacityMustNotBeNegative); + } + if (comparer == null) throw new ArgumentNullException("comparer"); + + // The capacity should be at least as large as the concurrency level. Otherwise, we would have locks that don't guard + // any buckets. + if (capacity < concurrencyLevel) + { + capacity = concurrencyLevel; + } + + m_locks = new object[concurrencyLevel]; + for (int i = 0; i < m_locks.Length; i++) + { + m_locks[i] = new object(); + } + + m_countPerLock = new int[m_locks.Length]; + m_buckets = new Node[capacity]; + m_comparer = comparer; + } + + + /// + /// Attempts to add the specified key and value to the . + /// + /// The key of the element to add. + /// The value of the element to add. The value can be a null reference (Nothing + /// in Visual Basic) for reference types. + /// true if the key/value pair was added to the + /// successfully; otherwise, false. + /// is null reference + /// (Nothing in Visual Basic). + /// The + /// contains too many elements. + public bool TryAdd(TKey key, TValue value) + { + if (key == null) throw new ArgumentNullException("key"); + TValue dummy; + return TryAddInternal(key, value, false, true, out dummy); + } + + /// + /// Determines whether the contains the specified + /// key. + /// + /// The key to locate in the . + /// true if the contains an element with + /// the specified key; otherwise, false. + /// is a null reference + /// (Nothing in Visual Basic). + public bool ContainsKey(TKey key) + { + if (key == null) throw new ArgumentNullException("key"); + + TValue throwAwayValue; + return TryGetValue(key, out throwAwayValue); + } + + /// + /// Attempts to remove and return the the value with the specified key from the + /// . + /// + /// The key of the element to remove and return. + /// When this method returns, contains the object removed from the + /// or the default value of + /// if the operation failed. + /// true if an object was removed successfully; otherwise, false. + /// is a null reference + /// (Nothing in Visual Basic). + public bool TryRemove(TKey key, out TValue value) + { + if (key == null) throw new ArgumentNullException("key"); + + return TryRemoveInternal(key, out value, false, default(TValue)); + } + + /// + /// Removes the specified key from the dictionary if it exists and returns its associated value. + /// If matchValue flag is set, the key will be removed only if is associated with a particular + /// value. + /// + /// The key to search for and remove if it exists. + /// The variable into which the removed value, if found, is stored. + /// Whether removal of the key is conditional on its value. + /// The conditional value to compare against if is true + /// + private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue) + { + while (true) + { + Node[] buckets = m_buckets; + + int bucketNo, lockNo; + GetBucketAndLockNo(m_comparer.GetHashCode(key), out bucketNo, out lockNo, buckets.Length); + + lock (m_locks[lockNo]) + { + // If the table just got resized, we may not be holding the right lock, and must retry. + // This should be a rare occurence. + if (buckets != m_buckets) + { + continue; + } + + Node prev = null; + for (Node curr = m_buckets[bucketNo]; curr != null; curr = curr.m_next) + { + Assert((prev == null && curr == m_buckets[bucketNo]) || prev.m_next == curr); + + if (m_comparer.Equals(curr.m_key, key)) + { + if (matchValue) + { + bool valuesMatch = EqualityComparer.Default.Equals(oldValue, curr.m_value); + if (!valuesMatch) + { + value = default(TValue); + return false; + } + } + + if (prev == null) + { + m_buckets[bucketNo] = curr.m_next; + } + else + { + prev.m_next = curr.m_next; + } + + value = curr.m_value; + m_countPerLock[lockNo]--; + return true; + } + prev = curr; + } + } + + value = default(TValue); + return false; + } + } + + /// + /// Attempts to get the value associated with the specified key from the . + /// + /// The key of the value to get. + /// When this method returns, contains the object from + /// the + /// with the spedified key or the default value of + /// , if the operation failed. + /// true if the key was found in the ; + /// otherwise, false. + /// is a null reference + /// (Nothing in Visual Basic). + public bool TryGetValue(TKey key, out TValue value) + { + if (key == null) throw new ArgumentNullException("key"); + + int bucketNo, lockNoUnused; + + // We must capture the m_buckets field in a local variable. It is set to a new table on each table resize. + Node[] buckets = m_buckets; + GetBucketAndLockNo(m_comparer.GetHashCode(key), out bucketNo, out lockNoUnused, buckets.Length); + + // We can get away w/out a lock here. + Node n = buckets[bucketNo]; + + // The memory barrier ensures that the load of the fields of 'n' doesn’t move before the load from buckets[i]. + Thread.MemoryBarrier(); + while (n != null) + { + if (m_comparer.Equals(n.m_key, key)) + { + value = n.m_value; + return true; + } + n = n.m_next; + } + + value = default(TValue); + return false; + } + + /// + /// Compares the existing value for the specified key with a specified value, and if they’re equal, + /// updates the key with a third value. + /// + /// The key whose value is compared with and + /// possibly replaced. + /// The value that replaces the value of the element with if the comparison results in equality. + /// The value that is compared to the value of the element with + /// . + /// true if the value with was equal to and replaced with ; otherwise, + /// false. + /// is a null + /// reference. + public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) + { + if (key == null) throw new ArgumentNullException("key"); + + int hashcode = m_comparer.GetHashCode(key); + IEqualityComparer valueComparer = EqualityComparer.Default; + + while (true) + { + int bucketNo; + int lockNo; + + Node[] buckets = m_buckets; + GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, buckets.Length); + + lock (m_locks[lockNo]) + { + // If the table just got resized, we may not be holding the right lock, and must retry. + // This should be a rare occurence. + if (buckets != m_buckets) + { + continue; + } + + // Try to find this key in the bucket + Node prev = null; + for (Node node = buckets[bucketNo]; node != null; node = node.m_next) + { + Assert((prev == null && node == m_buckets[bucketNo]) || prev.m_next == node); + if (m_comparer.Equals(node.m_key, key)) + { + if (valueComparer.Equals(node.m_value, comparisonValue)) + { + // Replace the old node with a new node. Unfortunately, we cannot simply + // change node.m_value in place. We don't know the size of TValue, so + // its writes may not be atomic. + Node newNode = new Node(node.m_key, newValue, hashcode, node.m_next); + + if (prev == null) + { + buckets[bucketNo] = newNode; + } + else + { + prev.m_next = newNode; + } + + return true; + } + + return false; + } + + prev = node; + } + + //didn't find the key + return false; + } + } + } + + /// + /// Removes all keys and values from the . + /// + public void Clear() + { + int locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + + m_buckets = new Node[DEFAULT_CAPACITY]; + Array.Clear(m_countPerLock, 0, m_countPerLock.Length); + } + finally + { + ReleaseLocks(0, locksAcquired); + } + } + + /// + /// Copies the elements of the to an array of + /// type , starting at the + /// specified array index. + /// + /// The one-dimensional array of type + /// that is the destination of the elements copied from the . The array must have zero-based indexing. + /// The zero-based index in at which copying + /// begins. + /// is a null reference + /// (Nothing in Visual Basic). + /// is less than + /// 0. + /// is equal to or greater than + /// the length of the . -or- The number of elements in the source + /// is greater than the available space from to the end of the destination + /// . + void ICollection>.CopyTo(KeyValuePair[] array, int index) + { + if (array == null) throw new ArgumentNullException("array"); + if (index < 0) throw new ArgumentOutOfRangeException("index", Strings.ConcurrentDictionary_IndexIsNegative); + + int locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + + int count = 0; + + for (int i = 0; i < m_locks.Length; i++) + { + count += m_countPerLock[i]; + } + + if (array.Length - count < index || count < 0) //"count" itself or "count + index" can overflow + { + throw new ArgumentException(Strings.ConcurrentDictionary_ArrayNotLargeEnough, "array"); + } + + CopyToPairs(array, index); + } + finally + { + ReleaseLocks(0, locksAcquired); + } + } + + /// + /// Copies the key and value pairs stored in the to a + /// new array. + /// + /// A new array containing a snapshot of key and value pairs copied from the . + public KeyValuePair[] ToArray() + { + int locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + int count = 0; + checked + { + for (int i = 0; i < m_locks.Length; i++) + { + count += m_countPerLock[i]; + } + } + + KeyValuePair[] array = new KeyValuePair[count]; + + CopyToPairs(array, 0); + return array; + } + finally + { + ReleaseLocks(0, locksAcquired); + } + } + + /// + /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo. + /// + /// Important: the caller must hold all locks in m_locks before calling CopyToPairs. + /// + private void CopyToPairs(KeyValuePair[] array, int index) + { + Node[] buckets = m_buckets; + for (int i = 0; i < buckets.Length; i++) + { + for (Node current = buckets[i]; current != null; current = current.m_next) + { + array[index] = new KeyValuePair(current.m_key, current.m_value); + index++; //this should never flow, CopyToPairs is only called when there's no overflow risk + } + } + } + + /// + /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo. + /// + /// Important: the caller must hold all locks in m_locks before calling CopyToEntries. + /// + private void CopyToEntries(DictionaryEntry[] array, int index) + { + Node[] buckets = m_buckets; + for (int i = 0; i < buckets.Length; i++) + { + for (Node current = buckets[i]; current != null; current = current.m_next) + { + array[index] = new DictionaryEntry(current.m_key, current.m_value); + index++; //this should never flow, CopyToEntries is only called when there's no overflow risk + } + } + } + + /// + /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo. + /// + /// Important: the caller must hold all locks in m_locks before calling CopyToObjects. + /// + private void CopyToObjects(object[] array, int index) + { + Node[] buckets = m_buckets; + for (int i = 0; i < buckets.Length; i++) + { + for (Node current = buckets[i]; current != null; current = current.m_next) + { + array[index] = new KeyValuePair(current.m_key, current.m_value); + index++; //this should never flow, CopyToObjects is only called when there's no overflow risk + } + } + } + + /// Returns an enumerator that iterates through the . + /// An enumerator for the . + /// + /// The enumerator returned from the dictionary is safe to use concurrently with + /// reads and writes to the dictionary, however it does not represent a moment-in-time snapshot + /// of the dictionary. The contents exposed through the enumerator may contain modifications + /// made to the dictionary after was called. + /// + public IEnumerator> GetEnumerator() + { + Node[] buckets = m_buckets; + + for (int i = 0; i < buckets.Length; i++) + { + Node current = buckets[i]; + + // The memory barrier ensures that the load of the fields of 'current' doesn’t move before the load from buckets[i]. + Thread.MemoryBarrier(); + while (current != null) + { + yield return new KeyValuePair(current.m_key, current.m_value); + current = current.m_next; + } + } + } + + /// + /// Shared internal implementation for inserts and updates. + /// If key exists, we always return false; and if updateIfExists == true we force update with value; + /// If key doesn't exist, we always add value and return true; + /// + private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue) + { + int hashcode = m_comparer.GetHashCode(key); + + while (true) + { + int bucketNo, lockNo; + + Node[] buckets = m_buckets; + GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, buckets.Length); + + bool resizeDesired = false; + bool lockTaken = false; + try + { + if (acquireLock) + Monitor.Enter(m_locks[lockNo], ref lockTaken); + + // If the table just got resized, we may not be holding the right lock, and must retry. + // This should be a rare occurence. + if (buckets != m_buckets) + { + continue; + } + + // Try to find this key in the bucket + Node prev = null; + for (Node node = buckets[bucketNo]; node != null; node = node.m_next) + { + Assert((prev == null && node == m_buckets[bucketNo]) || prev.m_next == node); + if (m_comparer.Equals(node.m_key, key)) + { + // The key was found in the dictionary. If updates are allowed, update the value for that key. + // We need to create a new node for the update, in order to support TValue types that cannot + // be written atomically, since lock-free reads may be happening concurrently. + if (updateIfExists) + { + Node newNode = new Node(node.m_key, value, hashcode, node.m_next); + if (prev == null) + { + buckets[bucketNo] = newNode; + } + else + { + prev.m_next = newNode; + } + resultingValue = value; + } + else + { + resultingValue = node.m_value; + } + return false; + } + prev = node; + } + + // The key was not found in the bucket. Insert the key-value pair. + buckets[bucketNo] = new Node(key, value, hashcode, buckets[bucketNo]); + checked + { + m_countPerLock[lockNo]++; + } + + // + // If this lock has element / bucket ratio greater than 1, resize the entire table. + // Note: the formula is chosen to avoid overflow, but has a small inaccuracy due to + // rounding. + // + if (m_countPerLock[lockNo] > buckets.Length / m_locks.Length) + { + resizeDesired = true; + } + } + finally + { + if (lockTaken) + Monitor.Exit(m_locks[lockNo]); + } + + // + // The fact that we got here means that we just performed an insertion. If necessary, we will grow the table. + // + // Concurrency notes: + // - Notice that we are not holding any locks at when calling GrowTable. This is necessary to prevent deadlocks. + // - As a result, it is possible that GrowTable will be called unnecessarily. But, GrowTable will obtain lock 0 + // and then verify that the table we passed to it as the argument is still the current table. + // + if (resizeDesired) + { + GrowTable(buckets); + } + + resultingValue = value; + return true; + } + } + + /// + /// Gets or sets the value associated with the specified key. + /// + /// The key of the value to get or set. + /// The value associated with the specified key. If the specified key is not found, a get + /// operation throws a + /// , and a set operation creates a new + /// element with the specified key. + /// is a null reference + /// (Nothing in Visual Basic). + /// The property is retrieved and + /// + /// does not exist in the collection. + public TValue this[TKey key] + { + get + { + TValue value; + if (!TryGetValue(key, out value)) + { + throw new KeyNotFoundException(); + } + return value; + } + set + { + if (key == null) throw new ArgumentNullException("key"); + TValue dummy; + TryAddInternal(key, value, true, true, out dummy); + } + } + + /// + /// Gets the number of key/value pairs contained in the . + /// + /// The dictionary contains too many + /// elements. + /// The number of key/value paris contained in the . + /// Count has snapshot semantics and represents the number of items in the + /// at the moment when Count was accessed. + public int Count + { + get + { + int count = 0; + + int acquiredLocks = 0; + try + { + // Acquire all locks + AcquireAllLocks(ref acquiredLocks); + + // Compute the count, we allow overflow + for (int i = 0; i < m_countPerLock.Length; i++) + { + count += m_countPerLock[i]; + } + + } + finally + { + // Release locks that have been acquired earlier + ReleaseLocks(0, acquiredLocks); + } + + return count; + } + } + + /// + /// Adds a key/value pair to the + /// if the key does not already exist. + /// + /// The key of the element to add. + /// The function used to generate a value for the key + /// is a null reference + /// (Nothing in Visual Basic). + /// is a null reference + /// (Nothing in Visual Basic). + /// The dictionary contains too many + /// elements. + /// The value for the key. This will be either the existing value for the key if the + /// key is already in the dictionary, or the new value for the key as returned by valueFactory + /// if the key was not in the dictionary. + public TValue GetOrAdd(TKey key, Func valueFactory) + { + if (key == null) throw new ArgumentNullException("key"); + if (valueFactory == null) throw new ArgumentNullException("valueFactory"); + + TValue resultingValue; + if (TryGetValue(key, out resultingValue)) + { + return resultingValue; + } + TryAddInternal(key, valueFactory(key), false, true, out resultingValue); + return resultingValue; + } + + /// + /// Adds a key/value pair to the + /// if the key does not already exist. + /// + /// The key of the element to add. + /// the value to be added, if the key does not already exist + /// is a null reference + /// (Nothing in Visual Basic). + /// The dictionary contains too many + /// elements. + /// The value for the key. This will be either the existing value for the key if the + /// key is already in the dictionary, or the new value if the key was not in the dictionary. + public TValue GetOrAdd(TKey key, TValue value) + { + if (key == null) throw new ArgumentNullException("key"); + + TValue resultingValue; + TryAddInternal(key, value, false, true, out resultingValue); + return resultingValue; + } + + /// + /// Adds a key/value pair to the if the key does not already + /// exist, or updates a key/value pair in the if the key + /// already exists. + /// + /// The key to be added or whose value should be updated + /// The function used to generate a value for an absent key + /// The function used to generate a new value for an existing key + /// based on the key's existing value + /// is a null reference + /// (Nothing in Visual Basic). + /// is a null reference + /// (Nothing in Visual Basic). + /// is a null reference + /// (Nothing in Visual Basic). + /// The dictionary contains too many + /// elements. + /// The new value for the key. This will be either be the result of addValueFactory (if the key was + /// absent) or the result of updateValueFactory (if the key was present). + public TValue AddOrUpdate(TKey key, Func addValueFactory, Func updateValueFactory) + { + if (key == null) throw new ArgumentNullException("key"); + if (addValueFactory == null) throw new ArgumentNullException("addValueFactory"); + if (updateValueFactory == null) throw new ArgumentNullException("updateValueFactory"); + + TValue newValue, resultingValue; + while (true) + { + TValue oldValue; + if (TryGetValue(key, out oldValue)) + //key exists, try to update + { + newValue = updateValueFactory(key, oldValue); + if (TryUpdate(key, newValue, oldValue)) + { + return newValue; + } + } + else //try add + { + newValue = addValueFactory(key); + if (TryAddInternal(key, newValue, false, true, out resultingValue)) + { + return resultingValue; + } + } + } + } + + /// + /// Adds a key/value pair to the if the key does not already + /// exist, or updates a key/value pair in the if the key + /// already exists. + /// + /// The key to be added or whose value should be updated + /// The value to be added for an absent key + /// The function used to generate a new value for an existing key based on + /// the key's existing value + /// is a null reference + /// (Nothing in Visual Basic). + /// is a null reference + /// (Nothing in Visual Basic). + /// The dictionary contains too many + /// elements. + /// The new value for the key. This will be either be the result of addValueFactory (if the key was + /// absent) or the result of updateValueFactory (if the key was present). + public TValue AddOrUpdate(TKey key, TValue addValue, Func updateValueFactory) + { + if (key == null) throw new ArgumentNullException("key"); + if (updateValueFactory == null) throw new ArgumentNullException("updateValueFactory"); + TValue newValue, resultingValue; + while (true) + { + TValue oldValue; + if (TryGetValue(key, out oldValue)) + //key exists, try to update + { + newValue = updateValueFactory(key, oldValue); + if (TryUpdate(key, newValue, oldValue)) + { + return newValue; + } + } + else //try add + { + if (TryAddInternal(key, addValue, false, true, out resultingValue)) + { + return resultingValue; + } + } + } + } + + + + /// + /// Gets a value that indicates whether the is empty. + /// + /// true if the is empty; otherwise, + /// false. + public bool IsEmpty + { + get + { + int acquiredLocks = 0; + try + { + // Acquire all locks + AcquireAllLocks(ref acquiredLocks); + + for (int i = 0; i < m_countPerLock.Length; i++) + { + if (m_countPerLock[i] != 0) + { + return false; + } + } + } + finally + { + // Release locks that have been acquired earlier + ReleaseLocks(0, acquiredLocks); + } + + return true; + } + } + + #region IDictionary members + + /// + /// Adds the specified key and value to the . + /// + /// The object to use as the key of the element to add. + /// The object to use as the value of the element to add. + /// is a null reference + /// (Nothing in Visual Basic). + /// The dictionary contains too many + /// elements. + /// + /// An element with the same key already exists in the . + void IDictionary.Add(TKey key, TValue value) + { + if (!TryAdd(key, value)) + { + throw new ArgumentException(Strings.ConcurrentDictionary_KeyAlreadyExisted, "key"); + } + } + + /// + /// Removes the element with the specified key from the . + /// + /// The key of the element to remove. + /// true if the element is successfully remove; otherwise false. This method also returns + /// false if + /// was not found in the original . + /// + /// is a null reference + /// (Nothing in Visual Basic). + bool IDictionary.Remove(TKey key) + { + TValue throwAwayValue; + return TryRemove(key, out throwAwayValue); + } + + /// + /// Gets a collection containing the keys in the . + /// + /// An containing the keys in the + /// . + public ICollection Keys + { + get { return GetKeys(); } + } + + /// + /// Gets a collection containing the values in the . + /// + /// An containing the values in + /// the + /// . + public ICollection Values + { + get { return GetValues(); } + } + #endregion + + #region ICollection> Members + + /// + /// Adds the specified value to the + /// with the specified key. + /// + /// The + /// structure representing the key and value to add to the . + /// The of is null. + /// The + /// contains too many elements. + /// An element with the same key already exists in the + /// + void ICollection>.Add(KeyValuePair keyValuePair) + { + ((IDictionary)this).Add(keyValuePair.Key, keyValuePair.Value); + } + + /// + /// Determines whether the + /// contains a specific key and value. + /// + /// The + /// structure to locate in the . + /// true if the is found in the ; otherwise, false. + bool ICollection>.Contains(KeyValuePair keyValuePair) + { + TValue value; + if (!TryGetValue(keyValuePair.Key, out value)) + { + return false; + } + return EqualityComparer.Default.Equals(value, keyValuePair.Value); + } + + /// + /// Gets a value indicating whether the dictionary is read-only. + /// + /// true if the is + /// read-only; otherwise, false. For , this property always returns + /// false. + bool ICollection>.IsReadOnly + { + get { return false; } + } + + /// + /// Removes a key and value from the dictionary. + /// + /// The + /// structure representing the key and value to remove from the . + /// true if the key and value represented by is successfully + /// found and removed; otherwise, false. + /// The Key property of is a null reference (Nothing in Visual Basic). + bool ICollection>.Remove(KeyValuePair keyValuePair) + { + if (keyValuePair.Key == null) throw new ArgumentNullException(Strings.ConcurrentDictionary_ItemKeyIsNull, "keyValuePair"); + + TValue throwAwayValue; + return TryRemoveInternal(keyValuePair.Key, out throwAwayValue, true, keyValuePair.Value); + } + + #endregion + + #region IEnumerable Members + + /// Returns an enumerator that iterates through the . + /// An enumerator for the . + /// + /// The enumerator returned from the dictionary is safe to use concurrently with + /// reads and writes to the dictionary, however it does not represent a moment-in-time snapshot + /// of the dictionary. The contents exposed through the enumerator may contain modifications + /// made to the dictionary after was called. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((ConcurrentDictionary)this).GetEnumerator(); + } + + #endregion + + #region IDictionary Members + + /// + /// Adds the specified key and value to the dictionary. + /// + /// The object to use as the key. + /// The object to use as the value. + /// is a null reference + /// (Nothing in Visual Basic). + /// The dictionary contains too many + /// elements. + /// + /// is of a type that is not assignable to the key type of the . -or- + /// is of a type that is not assignable to , + /// the type of values in the . + /// -or- A value with the same key already exists in the . + /// + void IDictionary.Add(object key, object value) + { + if (key == null) throw new ArgumentNullException("key"); + if (!(key is TKey)) throw new ArgumentException(Strings.ConcurrentDictionary_TypeOfKeyIncorrect, "key"); + + TValue typedValue; + try + { + typedValue = (TValue)value; + } + catch (InvalidCastException) + { + throw new ArgumentException(Strings.ConcurrentDictionary_TypeOfValueIncorrect, "value"); + } + + ((IDictionary)this).Add((TKey)key, typedValue); + } + + /// + /// Gets whether the contains an + /// element with the specified key. + /// + /// The key to locate in the . + /// true if the contains + /// an element with the specified key; otherwise, false. + /// is a null reference + /// (Nothing in Visual Basic). + bool IDictionary.Contains(object key) + { + if (key == null) throw new ArgumentNullException("key"); + + return (key is TKey) && ((ConcurrentDictionary)this).ContainsKey((TKey)key); + } + + /// Provides an for the + /// . + /// An for the . + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return new DictionaryEnumerator(this); + } + + /// + /// Gets a value indicating whether the has a fixed size. + /// + /// true if the has a + /// fixed size; otherwise, false. For , this property always + /// returns false. + bool IDictionary.IsFixedSize + { + get { return false; } + } + + /// + /// Gets a value indicating whether the is read-only. + /// + /// true if the is + /// read-only; otherwise, false. For , this property always + /// returns false. + bool IDictionary.IsReadOnly + { + get { return false; } + } + + /// + /// Gets an containing the keys of the . + /// + /// An containing the keys of the . + ICollection IDictionary.Keys + { + get { return GetKeys(); } + } + + /// + /// Removes the element with the specified key from the . + /// + /// The key of the element to remove. + /// is a null reference + /// (Nothing in Visual Basic). + void IDictionary.Remove(object key) + { + if (key == null) throw new ArgumentNullException("key"); + + TValue throwAwayValue; + if (key is TKey) + { + this.TryRemove((TKey)key, out throwAwayValue); + } + } + + /// + /// Gets an containing the values in the . + /// + /// An containing the values in the . + ICollection IDictionary.Values + { + get { return GetValues(); } + } + + /// + /// Gets or sets the value associated with the specified key. + /// + /// The key of the value to get or set. + /// The value associated with the specified key, or a null reference (Nothing in Visual Basic) + /// if is not in the dictionary or is of a type that is + /// not assignable to the key type of the . + /// is a null reference + /// (Nothing in Visual Basic). + /// + /// A value is being assigned, and is of a type that is not assignable to the + /// key type of the . -or- A value is being + /// assigned, and is of a type that is not assignable to the value type + /// of the + /// + object IDictionary.this[object key] + { + get + { + if (key == null) throw new ArgumentNullException("key"); + + TValue value; + if (key is TKey && this.TryGetValue((TKey)key, out value)) + { + return value; + } + + return null; + } + set + { + if (key == null) throw new ArgumentNullException("key"); + + if (!(key is TKey)) throw new ArgumentException(Strings.ConcurrentDictionary_TypeOfKeyIncorrect, "key"); + if (!(value is TValue)) throw new ArgumentException(Strings.ConcurrentDictionary_TypeOfValueIncorrect, "value"); + + ((ConcurrentDictionary)this)[(TKey)key] = (TValue)value; + } + } + + #endregion + + #region ICollection Members + + /// + /// Copies the elements of the to an array, starting + /// at the specified array index. + /// + /// The one-dimensional array that is the destination of the elements copied from + /// the . The array must have zero-based + /// indexing. + /// The zero-based index in at which copying + /// begins. + /// is a null reference + /// (Nothing in Visual Basic). + /// is less than + /// 0. + /// is equal to or greater than + /// the length of the . -or- The number of elements in the source + /// is greater than the available space from to the end of the destination + /// . + void ICollection.CopyTo(Array array, int index) + { + if (array == null) throw new ArgumentNullException("array"); + if (index < 0) throw new ArgumentOutOfRangeException("index", Strings.ConcurrentDictionary_IndexIsNegative); + + int locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + + int count = 0; + + for (int i = 0; i < m_locks.Length; i++) + { + count += m_countPerLock[i]; + } + + if (array.Length - count < index || count < 0) //"count" itself or "count + index" can overflow + { + throw new ArgumentException(Strings.ConcurrentDictionary_ArrayNotLargeEnough, "array"); + } + + // To be consistent with the behavior of ICollection.CopyTo() in Dictionary, + // we recognize three types of target arrays: + // - an array of KeyValuePair structs + // - an array of DictionaryEntry structs + // - an array of objects + + KeyValuePair[] pairs = array as KeyValuePair[]; + if (pairs != null) + { + CopyToPairs(pairs, index); + return; + } + + DictionaryEntry[] entries = array as DictionaryEntry[]; + if (entries != null) + { + CopyToEntries(entries, index); + return; + } + + object[] objects = array as object[]; + if (objects != null) + { + CopyToObjects(objects, index); + return; + } + + throw new ArgumentException(Strings.ConcurrentDictionary_ArrayIncorrectType, "array"); + } + finally + { + ReleaseLocks(0, locksAcquired); + } + } + + /// + /// Gets a value indicating whether access to the is + /// synchronized with the SyncRoot. + /// + /// true if access to the is synchronized + /// (thread safe); otherwise, false. For , this property always + /// returns false. + bool ICollection.IsSynchronized + { + get { return false; } + } + + /// + /// Gets an object that can be used to synchronize access to the . This property is not supported. + /// + /// The SyncRoot property is not supported. + object ICollection.SyncRoot + { + get + { + throw new NotSupportedException(Strings.ConcurrentCollection_SyncRoot_NotSupported); + } + } + + #endregion + + /// + /// Replaces the internal table with a larger one. To prevent multiple threads from resizing the + /// table as a result of races, the table of buckets that was deemed too small is passed in as + /// an argument to GrowTable(). GrowTable() obtains a lock, and then checks whether the bucket + /// table has been replaced in the meantime or not. + /// + /// Reference to the bucket table that was deemed too small. + private void GrowTable(Node[] buckets) + { + int locksAcquired = 0; + try + { + // The thread that first obtains m_locks[0] will be the one doing the resize operation + AcquireLocks(0, 1, ref locksAcquired); + + // Make sure nobody resized the table while we were waiting for lock 0: + if (buckets != m_buckets) + { + // We assume that since the table reference is different, it was already resized. If we ever + // decide to do table shrinking, or replace the table for other reasons, we will have to revisit + // this logic. + return; + } + + // Compute the new table size. We find the smallest integer larger than twice the previous table size, and not divisible by + // 2,3,5 or 7. We can consider a different table-sizing policy in the future. + int newLength; + try + { + checked + { + // Double the size of the buckets table and add one, so that we have an odd integer. + newLength = buckets.Length * 2 + 1; + + // Now, we only need to check odd integers, and find the first that is not divisible + // by 3, 5 or 7. + while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0) + { + newLength += 2; + } + + Assert(newLength % 2 != 0); + } + } + catch (OverflowException) + { + // If we were to resize the table, its new size will not fit into a 32-bit signed int. Just return. + return; + } + + Node[] newBuckets = new Node[newLength]; + int[] newCountPerLock = new int[m_locks.Length]; + + // Now acquire all other locks for the table + AcquireLocks(1, m_locks.Length, ref locksAcquired); + + // Copy all data into a new table, creating new nodes for all elements + for (int i = 0; i < buckets.Length; i++) + { + Node current = buckets[i]; + while (current != null) + { + Node next = current.m_next; + int newBucketNo, newLockNo; + GetBucketAndLockNo(current.m_hashcode, out newBucketNo, out newLockNo, newBuckets.Length); + + newBuckets[newBucketNo] = new Node(current.m_key, current.m_value, current.m_hashcode, newBuckets[newBucketNo]); + + checked + { + newCountPerLock[newLockNo]++; + } + + current = next; + } + } + + // And finally adjust m_buckets and m_countPerLock to point to data for the new table + m_buckets = newBuckets; + m_countPerLock = newCountPerLock; + + } + finally + { + // Release all locks that we took earlier + ReleaseLocks(0, locksAcquired); + } + } + + /// + /// Computes the bucket and lock number for a particular key. + /// + private void GetBucketAndLockNo( + int hashcode, out int bucketNo, out int lockNo, int bucketCount) + { + bucketNo = (hashcode & 0x7fffffff) % bucketCount; + lockNo = bucketNo % m_locks.Length; + + Assert(bucketNo >= 0 && bucketNo < bucketCount); + Assert(lockNo >= 0 && lockNo < m_locks.Length); + } + + /// + /// The number of concurrent writes for which to optimize by default. + /// + private static int DefaultConcurrencyLevel + { + get { return DEFAULT_CONCURRENCY_MULTIPLIER * PlatformHelper.ProcessorCount; } + } + + /// + /// Acquires all locks for this hash table, and increments locksAcquired by the number + /// of locks that were successfully acquired. The locks are acquired in an increasing + /// order. + /// + private void AcquireAllLocks(ref int locksAcquired) + { +#if ETW_EVENTING + if (CDSCollectionETWBCLProvider.Log.IsEnabled()) + { + CDSCollectionETWBCLProvider.Log.ConcurrentDictionary_AcquiringAllLocks(m_buckets.Length); + } +#endif + + AcquireLocks(0, m_locks.Length, ref locksAcquired); + Assert(locksAcquired == m_locks.Length); + } + + /// + /// Acquires a contiguous range of locks for this hash table, and increments locksAcquired + /// by the number of locks that were successfully acquired. The locks are acquired in an + /// increasing order. + /// + private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired) + { + Assert(fromInclusive <= toExclusive); + + for (int i = fromInclusive; i < toExclusive; i++) + { + bool lockTaken = false; + try + { +#if CDS_COMPILE_JUST_THIS + Monitor.Enter(m_locks[i]); + lockTaken = true; +#else + Monitor.Enter(m_locks[i], ref lockTaken); +#endif + } + finally + { + if (lockTaken) + { + locksAcquired++; + } + } + } + } + + /// + /// Releases a contiguous range of locks. + /// + private void ReleaseLocks(int fromInclusive, int toExclusive) + { + Assert(fromInclusive <= toExclusive); + + for (int i = fromInclusive; i < toExclusive; i++) + { + Monitor.Exit(m_locks[i]); + } + } + + /// + /// Gets a collection containing the keys in the dictionary. + /// + private ReadOnlyCollection GetKeys() + { + int locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + List keys = new List(); + + for (int i = 0; i < m_buckets.Length; i++) + { + Node current = m_buckets[i]; + while (current != null) + { + keys.Add(current.m_key); + current = current.m_next; + } + } + + return new ReadOnlyCollection(keys); + } + finally + { + ReleaseLocks(0, locksAcquired); + } + } + + /// + /// Gets a collection containing the values in the dictionary. + /// + private ReadOnlyCollection GetValues() + { + int locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + List values = new List(); + + for (int i = 0; i < m_buckets.Length; i++) + { + Node current = m_buckets[i]; + while (current != null) + { + values.Add(current.m_value); + current = current.m_next; + } + } + + return new ReadOnlyCollection(values); + } + finally + { + ReleaseLocks(0, locksAcquired); + } + } + + /// + /// A helper method for asserts. + /// + [Conditional("DEBUG")] + private void Assert(bool condition) + { +#if CDS_COMPILE_JUST_THIS + if (!condition) + { + throw new Exception("Assertion failed."); + } +#else + Contract.Assert(condition); +#endif + } + + /// + /// A node in a singly-linked list representing a particular hash table bucket. + /// + private class Node + { + internal TKey m_key; + internal TValue m_value; + internal volatile Node m_next; + internal int m_hashcode; + + internal Node(TKey key, TValue value, int hashcode, Node next) + { + m_key = key; + m_value = value; + m_next = next; + m_hashcode = hashcode; + } + } + + /// + /// A private class to represent enumeration over the dictionary that implements the + /// IDictionaryEnumerator interface. + /// + private class DictionaryEnumerator : IDictionaryEnumerator + { + IEnumerator> m_enumerator; // Enumerator over the dictionary. + + internal DictionaryEnumerator(ConcurrentDictionary dictionary) + { + m_enumerator = dictionary.GetEnumerator(); + } + + public DictionaryEntry Entry + { + get { return new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value); } + } + + public object Key + { + get { return m_enumerator.Current.Key; } + } + + public object Value + { + get { return m_enumerator.Current.Value; } + } + + public object Current + { + get { return this.Entry; } + } + + public bool MoveNext() + { + return m_enumerator.MoveNext(); + } + + public void Reset() + { + m_enumerator.Reset(); + } + } + + /// + /// Get the data array to be serialized + /// + [OnSerializing] + private void OnSerializing(StreamingContext context) + { + // save the data into the serialization array to be saved + m_serializationArray = ToArray(); + m_serializationConcurrencyLevel = m_locks.Length; + m_serializationCapacity = m_buckets.Length; + } + + /// + /// Construct the dictionary from a previously seiralized one + /// + [OnDeserialized] + private void OnDeserialized(StreamingContext context) + { + KeyValuePair[] array = m_serializationArray; + + m_buckets = new Node[m_serializationCapacity]; + m_countPerLock = new int[m_serializationConcurrencyLevel]; + + m_locks = new object[m_serializationConcurrencyLevel]; + for (int i = 0; i < m_locks.Length; i++) + { + m_locks[i] = new object(); + } + + InitializeFromCollection(array); + m_serializationArray = null; + + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Diagnostics/Contracts/Contract.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Diagnostics/Contracts/Contract.cs new file mode 100644 index 000000000..7b9148fd0 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Diagnostics/Contracts/Contract.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace System.Diagnostics.Contracts +{ + internal class Contract + { + public static void Assert(bool condition, string message = null) + { + Debug.Assert(condition, message); + } + + public static void Requires(bool condition, string message = null) + { + } + + public static void Ensures(bool condition) + { + } + + public static void EndContractBlock() + { + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/EnvironmentLightup.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/EnvironmentLightup.cs new file mode 100644 index 000000000..9a37732d4 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/EnvironmentLightup.cs @@ -0,0 +1,77 @@ +using System; + +namespace System +{ + internal class EnvironmentLightup : Lightup + { + public static readonly EnvironmentLightup Instance = new EnvironmentLightup(); + private volatile bool _failedToGetProcessorCount = false; + private volatile PlatformID _platform = PlatformID.Unknown; + private Delegate _getProcessorCount; + private Delegate _getOSVersion; + + public EnvironmentLightup() + : base(typeof(Environment)) + { + } + + protected override object GetInstance() + { + return null; + } + + public int ProcessorCount + { + get + { + if (!_failedToGetProcessorCount) + { + // We don't cache it + int count; + if (TryGetProcessorCount(out count)) + return count; + + _failedToGetProcessorCount = true; + } + + // We can't retrieve processor count, assume 1 + return 1; + } + } + + private PlatformID Platform + { + get + { + if (_platform == PlatformID.Unknown) + { + object operatingSystem = Get(ref _getOSVersion, "OSVersion"); + + var lightup = new OperatingSystemLightup(operatingSystem); + + _platform = lightup.Platform; + } + + return _platform; + } + } + + private bool TryGetProcessorCount(out int count) + { + // ProcessorCount on Windows Phone 7.x is critical, which prevents us from retrieving it. + // Therefore to avoid the first-chance exception showing to the user (as Phone 7.x does + // not have "Just My Code"), we assume that if running under CE, we're not going to be + // able to retrieve the processor count. + // NOTE: WinCE will still be returned to a Phone 7.x under Phone 8, even though it's running + // on a WinNT kernal, which is fine, we don't want to the application see a behavior change in + // this case. + if (Platform == PlatformID.WinCE) + { + count = 0; + return false; + } + + return TryGet(ref _getProcessorCount, "ProcessorCount", out count); + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/ExecutionContextLightup.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/ExecutionContextLightup.cs new file mode 100644 index 000000000..64d657f03 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/ExecutionContextLightup.cs @@ -0,0 +1,63 @@ +using System; +using System.Reflection; + +namespace System +{ + internal class ExecutionContextLightup : Lightup + { + public static readonly ExecutionContextLightup Instance = new ExecutionContextLightup(null); + private Delegate _dispose; + private Delegate _capture; + private Delegate _run; + private Delegate _createCopy; + private readonly object _executionContext; + + private ExecutionContextLightup(object executionContext) + : base(LightupType.ExecutionContext) + { + _executionContext = executionContext; + } + + protected override object GetInstance() + { + return _executionContext; + } + + public ExecutionContextLightup Capture() + { + object executionContext; + if (TryCall(ref _capture, "Capture", out executionContext) && executionContext != null) + { + return new ExecutionContextLightup(executionContext); + } + + return null; + } + + public ExecutionContextLightup CreateCopy() + { + object copy = Call(ref _createCopy, "CreateCopy"); + + return new ExecutionContextLightup(copy); + } + + public void Run(ExecutionContextLightup executionContext, Action callback, object state) + { + if (LightupType.ExecutionContext == null || LightupType.ContextCallback == null) + throw new PlatformNotSupportedException(); + + // Replace the Action with a ContextCallback + Delegate contextCallback = LightupServices.ReplaceWith(callback, LightupType.ContextCallback); + + Type actionRepresentingSignature = typeof(Action<,,>).MakeGenericType(LightupType.ExecutionContext, LightupType.ContextCallback, typeof(object)); + + Delegate d = GetMethodAccessor(ref _run, actionRepresentingSignature, "Run"); + d.DynamicInvoke(executionContext._executionContext, contextCallback, state); + } + + public void Dispose() + { + Call(ref _dispose, "Dispose"); + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/Lightup.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/Lightup.cs new file mode 100644 index 000000000..308cd54fc --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/Lightup.cs @@ -0,0 +1,220 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Threading; + +namespace System +{ + internal abstract class Lightup + { + private readonly static Type[] EmptyTypes = new Type[0]; + private readonly Type _type; + + protected Lightup(Type type) + { + _type = type; + } + + protected bool TryGet(ref Delegate storage, string propertyName, out T value) + { + return TryCall(ref storage, "get_" + propertyName, out value); + } + + protected T Get(ref Delegate storage, string propertyName) + { + return Call(ref storage, "get_" + propertyName); + } + + protected void Set(ref Delegate storage, string propertyName, T value) + { + Call(ref storage, "set_" + propertyName, value); + } + + protected void Set(ref Delegate storage, TI instance, string propertyName, TV value) + { + Call(ref storage, instance, "set_" + propertyName, value); + } + + protected bool TrySet(ref Delegate storage, TI instance, string propertyName, TV value) + { + return TryCall(ref storage, instance, "set_" + propertyName, value); + } + + protected bool TryCall(ref Delegate storage, string methodName, out T returnValue) + { + Func method = GetMethodAccessor>(ref storage, methodName); + if (method == null) + { + returnValue = default(T); + return false; + } + + returnValue = method(); + return true; + } + + protected T Call(ref Delegate storage, string methodName) + { + Func method = GetMethodAccessor>(ref storage, methodName); + if (method == null) + throw new InvalidOperationException(); + + return method(); + } + + protected void Call(ref Delegate storage, string methodName) + { + Action method = GetMethodAccessor(ref storage, methodName); + if (method == null) + throw new InvalidOperationException(); + + method(); + } + + protected bool TryCall(ref Delegate storage, TI instance, string methodName, TV parameter) + { + Action method = GetMethodAccessor>(ref storage, methodName, bindInstance:false); + if (method == null) + return false; + + method(instance, parameter); + return true; + } + + protected bool TryCall(ref Delegate storage, TI instance, string methodName, TV1 parameter1, TV2 parameter2) + { + Action method = GetMethodAccessor>(ref storage, methodName, bindInstance: false); + if (method == null) + return false; + + method(instance, parameter1, parameter2); + return true; + } + + protected void Call(ref Delegate storage, TI instance, string methodName, TV parameter) + { + Action method = GetMethodAccessor>(ref storage, methodName, bindInstance:false); + if (method == null) + throw new InvalidOperationException(); + + method(instance, parameter); + } + + protected void Call(ref Delegate storage, string methodName, T parameter) + { + Action method = GetMethodAccessor>(ref storage, methodName); + if (method == null) + throw new InvalidOperationException(); + + method(parameter); + } + + protected static T Create(params object[] parameters) + { + Type[] argumentTypes = parameters.Select(p => p.GetType()) + .ToArray(); + + Func activator = CreateActivator(argumentTypes); + + return activator(parameters); + } + + protected abstract object GetInstance(); + + private static Func CreateActivator(Type[] argumentTypes) + { + ConstructorInfo info = typeof(T).GetConstructor(argumentTypes); + if (info == null) + return null; + + Func activator = (arguments) => (T)Activator.CreateInstance(typeof(T), arguments); + + return activator; + } + + private Delegate CreateMethodAccessor(Type type, string name, bool bindInstance = true) + { + if (_type == null) + return null; + + Type[] argumentTypes = LightupServices.GetMethodArgumentTypes(type, bindInstance); + + MethodInfo method = _type.GetMethod(name, argumentTypes); + if (method == null) + return null; + + return LightupServices.CreateDelegate(type, bindInstance ? GetInstance() : null, method); + } + + protected T GetMethodAccessor(ref Delegate storage, string name, bool bindInstance = true) + { + return (T)(object)GetMethodAccessor(ref storage, typeof(T), name, bindInstance); + } + + protected Delegate GetMethodAccessor(ref Delegate storage, Type type, string name, bool bindInstance = true) + { + if (storage == null) + { + Delegate accessor = CreateMethodAccessor(type, name, bindInstance); + + Interlocked.CompareExchange(ref storage, accessor, null); + } + + return storage == LightupServices.NotFound ? null : storage; + } + } + + internal static class LightupServices + { + public static Delegate NotFound = new Action(() => { }); + + public static Delegate ReplaceWith(Delegate d, Type delegateType) + { + return Delegate.CreateDelegate(delegateType, d.Target, d.Method); + } + + public static Type[] GetMethodArgumentTypes(Type actionOrFuncType, bool bindInstance = true) + { + Type[] arguments = actionOrFuncType.GetGenericArguments(); + + if (!bindInstance) + { + // We aren't binding the instance, remove "this" argument + arguments = arguments.Skip(1).ToArray(); + } + + if (IsActionType(actionOrFuncType)) + return arguments; + + // We have a Func, remove it's trailing return type + return arguments.Take(arguments.Length -1).ToArray(); + } + + public static bool IsActionType(Type type) + { + if (type.IsGenericType) + type = type.GetGenericTypeDefinition(); + + return type == typeof(Action) || type == typeof(Action<>) || type == typeof(Action<,>) || type == typeof(Action<,,>) || type == typeof(Action<,,,>); + } + + public static Delegate CreateDelegate(Type type, object instance, MethodInfo method) + { + if (method.IsStatic) + instance = null; + + try + { + return Delegate.CreateDelegate(type, instance, method); + } + catch (InvalidOperationException) + { // Exists, but not callable + } + catch (MemberAccessException) + { // Exists, but don't have required access + } + + return NotFound; + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/LightupType.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/LightupType.cs new file mode 100644 index 000000000..f6141105e --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/LightupType.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System +{ + internal static class LightupType + { + public static readonly Type ParameterizedThreadStart = GetExternallyVisibleType("System.Threading.ParameterizedThreadStart, mscorlib"); + public static readonly Type ExecutionContext = GetExternallyVisibleType("System.Threading.ExecutionContext, mscorlib"); + public static readonly Type ContextCallback = GetExternallyVisibleType("System.Threading.ContextCallback, mscorlib"); + public static readonly Type OperatingSystem = GetExternallyVisibleType("System.OperatingSystem, mscorlib"); + + private static Type GetExternallyVisibleType(string typeName) + { + // Types such as ExecutionContext exist on Phone, but are not visible + Type type = Type.GetType(typeName); + if (type != null && type.IsVisible) + return type; + + return null; + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/OperatingSystemLightup.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/OperatingSystemLightup.cs new file mode 100644 index 000000000..85d57c8fd --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/OperatingSystemLightup.cs @@ -0,0 +1,38 @@ +using System; + +namespace System +{ + internal class OperatingSystemLightup : Lightup + { + private Delegate _platform; + private readonly object _getOperatingSystem; + + internal OperatingSystemLightup(object operatingSystem) + : base(LightupType.OperatingSystem) + { + _getOperatingSystem = operatingSystem; + } + + protected override object GetInstance() + { + return _getOperatingSystem; + } + + public PlatformID Platform + { + get { return (PlatformID)Get(ref _platform, "Platform"); } + } + } + + internal enum PlatformID + { + Unknown = -1, + Win32S = 0, + Win32Windows = 1, + Win32NT = 2, + WinCE = 3, + Unix = 4, + Xbox = 5, + MacOSX = 6, + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/ThreadLightup.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/ThreadLightup.cs new file mode 100644 index 000000000..a66d95ff0 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Lightup/ThreadLightup.cs @@ -0,0 +1,106 @@ +using System; +using System.Reflection; +using System.Threading; + +namespace System +{ + internal class ThreadLightup : Lightup + { + public static readonly ThreadLightup Current = new ThreadLightup(); + private readonly Func _thread; + private Delegate _start; + private Delegate _threadState; + private Delegate _yield; + private Delegate _sleep; + private Delegate _spinWait; + private Delegate _isAlive; + private Delegate _isBackground; + + public ThreadLightup() + : this(() => Thread.CurrentThread) + { + } + + public ThreadLightup(Thread thread) + : this(() => thread) + { + } + + private ThreadLightup(Func getThread) + : base(typeof(Thread)) + { + _thread = getThread; + } + + protected override object GetInstance() + { + return _thread(); + } + + public static ThreadLightup Create(Action start) + { + Type delegateType = LightupType.ParameterizedThreadStart; + if (delegateType == null) + throw new InvalidOperationException(); + + // Replace the Action with a ParameterizedThreadStart + Delegate parameterizedThreadStart = LightupServices.ReplaceWith(start, delegateType); + + Thread thread = Create(parameterizedThreadStart); + + return new ThreadLightup(thread); + } + + public void Start(object parameter) + { + Call(ref _start, "Start", parameter); + } + + public ThreadState ThreadState + { + get { return (ThreadState)Get(ref _threadState, "ThreadState"); } + } + + public void Yield() + { + // No-op if it doesn't exist or is not callable + bool ignored; + TryCall(ref _yield, "Yield", out ignored); + } + + public void Sleep(int millisecondsTimeout) + { + Call(ref _sleep, "Sleep", millisecondsTimeout); + } + + public void SpinWait(int iterations) + { + Call(ref _spinWait, "SpinWait", iterations); + } + + public bool IsBackground + { + set { Set(ref _isBackground, "IsBackground", value); } + } + + public bool IsAlive + { + get { return Get(ref _isAlive, "IsAlive"); } + } + } + + [Flags] + internal enum ThreadState + { + Running = 0, + StopRequested = 1, + SuspendRequested = 2, + Background = 4, + Unstarted = 8, + Stopped = 16, + WaitSleepJoin = 32, + Suspended = 64, + AbortRequested = 128, + Aborted = 256, + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/OperationCanceledException.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/OperationCanceledException.cs new file mode 100644 index 000000000..b7a2941bb --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/OperationCanceledException.cs @@ -0,0 +1,65 @@ +using System.Threading; + +namespace System +{ + /// The exception that is thrown in a thread upon cancellation of an operation that the thread was executing. + public class OperationCanceledException : Exception + { + private CancellationToken _cancellationToken; + + /// Gets a token associated with the operation that was canceled. + public CancellationToken CancellationToken + { + get { return _cancellationToken; } + private set { _cancellationToken = value; } + } + + /// Initializes the exception. + public OperationCanceledException() + : base(Strings.OperationCanceled) + { + } + + /// Initializes the exception. + /// The error message that explains the reason for the exception. + public OperationCanceledException(String message) + : base(message) + { + } + + /// Initializes the exception. + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. + public OperationCanceledException(String message, Exception innerException) + : base(message, innerException) + { + } + + /// Initializes the exception. + /// A cancellation token associated with the operation that was canceled. + public OperationCanceledException(CancellationToken token) + : this() + { + CancellationToken = token; + } + + /// Initializes the exception. + /// The error message that explains the reason for the exception. + /// A cancellation token associated with the operation that was canceled. + public OperationCanceledException(String message, CancellationToken token) + : this(message) + { + CancellationToken = token; + } + + /// Initializes the exception. + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. + /// A cancellation token associated with the operation that was canceled. + public OperationCanceledException(String message, Exception innerException, CancellationToken token) + : this(message, innerException) + { + CancellationToken = token; + } + } +} \ No newline at end of file diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs new file mode 100644 index 000000000..e98cdf79e --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Security; +using System.Text; +using System.Threading; + +namespace System.Runtime.CompilerServices +{ + /// Holds state related to the builder's IAsyncStateMachine. + /// This is a mutable struct. Be very delicate with it. + internal struct AsyncMethodBuilderCore + { + /// A reference to the heap-allocated state machine object associated with this builder. + internal IAsyncStateMachine m_stateMachine; + + /// Initiates the builder's execution with the associated state machine. + /// Specifies the type of the state machine. + /// The state machine instance, passed by reference. + /// The argument is null (Nothing in Visual Basic). +#if !SILVERLIGHT + // [SecuritySafeCritical] +#endif + [DebuggerStepThrough] + internal void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + if (stateMachine == null) throw new ArgumentNullException("stateMachine"); + Contract.EndContractBlock(); + + stateMachine.MoveNext(); + } + + /// Associates the builder with the state machine it represents. + /// The heap-allocated state machine object. + /// The argument was null (Nothing in Visual Basic). + /// The builder is incorrectly initialized. + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + if (stateMachine == null) throw new ArgumentNullException("stateMachine"); + Contract.EndContractBlock(); + if (m_stateMachine != null) throw new InvalidOperationException("The builder was not properly initialized."); + m_stateMachine = stateMachine; + } + + /// + /// Gets the Action to use with an awaiter's OnCompleted or UnsafeOnCompleted method. + /// On first invocation, the supplied state machine will be boxed. + /// + /// Specifies the type of the method builder used. + /// Specifies the type of the state machine used. + /// The builder. + /// The state machine. + /// An Action to provide to the awaiter. +#if !SILVERLIGHT + // [SecuritySafeCritical] +#endif + internal Action GetCompletionAction( + ref TMethodBuilder builder, ref TStateMachine stateMachine) + where TMethodBuilder : IAsyncMethodBuilder + where TStateMachine : IAsyncStateMachine + { + Contract.Requires(builder != null, "Expected valid builder"); + Contract.Requires(stateMachine != null, "Expected valid state machine reference"); + + // The builder needs to flow ExecutionContext, so capture it. + var capturedContext = ExecutionContextLightup.Instance.Capture(); + + MoveNextRunner runner = new MoveNextRunner(capturedContext); + Action action = new Action(runner.Run); + + // If this is our first await, such that we've not yet boxed the state machine, do so now. + if (m_stateMachine == null) + { + // This is our first await, and we're not boxed yet. First performance any work that + // must affect both the non-boxed and boxed builders. + builder.PreBoxInitialization(); + + // Box the state machine, then tell the boxed instance to call back into its own builder, + // so we can cache the boxed reference. + Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference"); + m_stateMachine = (IAsyncStateMachine)stateMachine; + m_stateMachine.SetStateMachine(m_stateMachine); + } + + Contract.Assert(runner.m_stateMachine == null, "The runner's state machine should not yet have been populated."); + Contract.Assert(m_stateMachine != null, "The builder's state machine field should have been initialized."); + + // Now that we have the state machine, store it into the runner that the action delegate points to. + // And return the action. + runner.m_stateMachine = m_stateMachine; // only after this line is the Action delegate usable + return action; + } + + + + /// Provides the ability to invoke a state machine's MoveNext method under a supplied ExecutionContext. + private sealed class MoveNextRunner + { + /// The context with which to run MoveNext. + private readonly ExecutionContextLightup m_context; + /// The state machine whose MoveNext method should be invoked. + internal IAsyncStateMachine m_stateMachine; + + /// Initializes the runner. + /// The context with which to run MoveNext. + internal MoveNextRunner(ExecutionContextLightup context) + { + m_context = context; + } + + /// Invokes MoveNext under the provided context. + internal void Run() + { + Contract.Assert(m_stateMachine != null, "The state machine must have been set before calling Run."); + + if (m_context != null) + { + try + { + // Get the callback, lazily initializing it as necessary + Action callback = s_invokeMoveNext; + if (callback == null) { s_invokeMoveNext = callback = InvokeMoveNext; } + + if (m_context == null) + { + callback(m_stateMachine); + } + else + { + // Use the context and callback to invoke m_stateMachine.MoveNext. + ExecutionContextLightup.Instance.Run(m_context, callback, m_stateMachine); + } + } + finally { if (m_context != null) m_context.Dispose(); } + } + else + { + m_stateMachine.MoveNext(); + } + } + + /// Cached delegate used with ExecutionContext.Run. + private static Action s_invokeMoveNext; // lazily-initialized due to SecurityCritical attribution + + /// Invokes the MoveNext method on the supplied IAsyncStateMachine. + /// The IAsyncStateMachine machine instance. + private static void InvokeMoveNext(object stateMachine) + { + ((IAsyncStateMachine)stateMachine).MoveNext(); + } + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncMethodTaskCacheOfTResult.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncMethodTaskCacheOfTResult.cs new file mode 100644 index 000000000..20b30502c --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncMethodTaskCacheOfTResult.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + /// Provides a base class used to cache tasks of a specific return type. + /// Specifies the type of results the cached tasks return. + internal class AsyncMethodTaskCache + { + /// + /// A singleton cache for this result type. + /// This may be null if there are no cached tasks for this TResult. + /// + internal readonly static AsyncMethodTaskCache Singleton = CreateCache(); + + /// Creates a non-disposable task. + /// The result for the task. + /// The cacheable task. + internal static TaskCompletionSource CreateCompleted(TResult result) + { + var tcs = new TaskCompletionSource(); + tcs.TrySetResult(result); + return tcs; + } + + /// Creates a cache. + /// A task cache for this result type. + private static AsyncMethodTaskCache CreateCache() + { + // Get the result type + var resultType = typeof(TResult); + + // Return a new cache for this particular kind of task. + // If we don't have a specialized cache for this type, return null. + if (resultType == typeof(Boolean)) + { + return (AsyncMethodTaskCache)(object)new AsyncMethodBooleanTaskCache(); + } + else if (resultType == typeof(int)) + { + return (AsyncMethodTaskCache)(object)new AsyncMethodInt32TaskCache(); + } + else return null; + } + + /// Gets a cached task if one exists. + /// The result for which we want a cached task. + /// A cached task if one exists; otherwise, null. + internal virtual TaskCompletionSource FromResult(TResult result) + { + return CreateCompleted(result); + } + + /// Provides a cache for Boolean tasks. + private sealed class AsyncMethodBooleanTaskCache : AsyncMethodTaskCache + { + /// A true task. + internal readonly TaskCompletionSource m_true = CreateCompleted(true); + /// A false task. + internal readonly TaskCompletionSource m_false = CreateCompleted(false); + + /// Gets a cached task for the Boolean result. + /// true or false + /// A cached task for the Boolean result. + internal sealed override TaskCompletionSource FromResult(Boolean result) + { + return result ? m_true : m_false; + } + } + + /// Provides a cache for zero Int32 tasks. + private sealed class AsyncMethodInt32TaskCache : AsyncMethodTaskCache + { + /// The cache of Task{Int32}. + internal readonly static TaskCompletionSource[] Int32Tasks = CreateInt32Tasks(); + /// The minimum value, inclusive, for which we want a cached task. + internal const Int32 INCLUSIVE_INT32_MIN = -1; + /// The maximum value, exclusive, for which we want a cached task. + internal const Int32 EXCLUSIVE_INT32_MAX = 9; + /// Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX). + private static TaskCompletionSource[] CreateInt32Tasks() + { + Contract.Assert(EXCLUSIVE_INT32_MAX >= INCLUSIVE_INT32_MIN, "Expected max to be at least min"); + var tasks = new TaskCompletionSource[EXCLUSIVE_INT32_MAX - INCLUSIVE_INT32_MIN]; + for (int i = 0; i < tasks.Length; i++) + { + tasks[i] = CreateCompleted(i + INCLUSIVE_INT32_MIN); + } + return tasks; + } + + + /// Gets a cached task for the zero Int32 result. + /// The integer value + /// A cached task for the Int32 result or null if not cached. + internal sealed override TaskCompletionSource FromResult(Int32 result) + { + return (result >= INCLUSIVE_INT32_MIN && result < EXCLUSIVE_INT32_MAX) ? + Int32Tasks[result - INCLUSIVE_INT32_MIN] : + CreateCompleted(result); + } + } + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncServices.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncServices.cs new file mode 100644 index 000000000..f98dfb74a --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncServices.cs @@ -0,0 +1,71 @@ +// NOTE: If you change this copy, please also change the copy under the Async partition +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace System.Runtime.CompilerServices +{ + internal static class AsyncServices + { + /// Throws the exception on the ThreadPool. + /// The exception to propagate. + /// The target context on which to propagate the exception. Null to use the ThreadPool. + internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext) + { + // If the user supplied a SynchronizationContext... + if (targetContext != null) + { + try + { + // Post the throwing of the exception to that context, and return. + targetContext.Post(state => { throw PrepareExceptionForRethrow((Exception)state); }, exception); + return; + } + catch (Exception postException) + { + // If something goes horribly wrong in the Post, we'll + // propagate both exceptions on the ThreadPool + exception = new AggregateException(exception, postException); + } + } + + // Propagate the exception(s) on the ThreadPool + ThreadPool.QueueUserWorkItem(state => { throw PrepareExceptionForRethrow((Exception)state); }, exception); + } + + /// Copies the exception's stack trace so its stack trace isn't overwritten. + /// The exception to prepare. + internal static Exception PrepareExceptionForRethrow(Exception exc) + { +#if EXCEPTION_STACK_PRESERVE + Contract.Assume(exc != null); + if (s_prepForRemoting != null) + { + try { s_prepForRemoting.Invoke(exc, s_emptyParams); } + catch { } + } +#endif + return exc; + } + +#if EXCEPTION_STACK_PRESERVE + /// A MethodInfo for the Exception.PrepForRemoting method. + private readonly static MethodInfo s_prepForRemoting = GetPrepForRemotingMethodInfo(); + /// An empty array to use with MethodInfo.Invoke. + private readonly static Object[] s_emptyParams = new object[0]; + + /// Gets the MethodInfo for the internal PrepForRemoting method on Exception. + /// The MethodInfo if it could be retrieved, or else null. + private static MethodInfo GetPrepForRemotingMethodInfo() + { + try + { + return typeof(Exception).GetMethod("PrepForRemoting", BindingFlags.NonPublic | BindingFlags.Instance); + } + catch { return null; } + } +#endif + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncTaskMethodBuilder.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncTaskMethodBuilder.cs new file mode 100644 index 000000000..a79b4493b --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncTaskMethodBuilder.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Reflection; +using System.Security; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + /// + /// Provides a builder for asynchronous methods that return . + /// This type is intended for compiler use only. + /// + /// + /// AsyncTaskMethodBuilder is a value type, and thus it is copied by value. + /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed, + /// or else the copies may end up building distinct Task instances. + /// + public struct AsyncTaskMethodBuilder : IAsyncMethodBuilder + { + /// A cached VoidTaskResult task used for builders that complete synchronously. + private readonly static TaskCompletionSource s_cachedCompleted = AsyncTaskMethodBuilder.s_defaultResultTask; + +#pragma warning disable 0649 + /// The generic builder object to which this non-generic instance delegates. + private AsyncTaskMethodBuilder m_builder; // mutable struct: must not be readonly +#pragma warning restore 0649 + + /// Initializes a new . + /// The initialized . + public static AsyncTaskMethodBuilder Create() + { + return default(AsyncTaskMethodBuilder); + // Note: If ATMB.Create is modified to do any initialization, this + // method needs to be updated to do m_builder = ATMB.Create(). + } + + /// Initiates the builder's execution with the associated state machine. + /// Specifies the type of the state machine. + /// The state machine instance, passed by reference. + [DebuggerStepThrough] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + m_builder.Start(ref stateMachine); // argument validation handled by AsyncMethodBuilderCore + } + + /// Associates the builder with the state machine it represents. + /// The heap-allocated state machine object. + /// The argument was null (Nothing in Visual Basic). + /// The builder is incorrectly initialized. + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + m_builder.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore + } + + /// Perform any initialization necessary prior to lifting the builder to the heap. + void IAsyncMethodBuilder.PreBoxInitialization() + { + // Force the Task to be initialized prior to the first suspending await so + // that the original stack-based builder has a reference to the right Task. + var ignored = this.Task; + } + + /// + /// Schedules the specified state machine to be pushed forward when the specified awaiter completes. + /// + /// Specifies the type of the awaiter. + /// Specifies the type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + m_builder.AwaitOnCompleted(ref awaiter, ref stateMachine); + } + + /// + /// Schedules the specified state machine to be pushed forward when the specified awaiter completes. + /// + /// Specifies the type of the awaiter. + /// Specifies the type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitUnsafeOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + m_builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); + } + + /// Gets the for this builder. + /// The representing the builder's asynchronous operation. + /// The builder is not initialized. + public Task Task { get { return m_builder.Task; } } + + /// + /// Completes the in the + /// RanToCompletion state. + /// + /// The builder is not initialized. + /// The task has already completed. + public void SetResult() + { + // Accessing AsyncTaskMethodBuilder.s_cachedCompleted is faster than + // accessing AsyncTaskMethodBuilder.s_defaultResultTask. + m_builder.SetResult(s_cachedCompleted); + } + + /// + /// Completes the in the + /// Faulted state with the specified exception. + /// + /// The to use to fault the task. + /// The argument is null (Nothing in Visual Basic). + /// The builder is not initialized. + /// The task has already completed. + public void SetException(Exception exception) { m_builder.SetException(exception); } + + /// + /// Called by the debugger to request notification when the first wait operation + /// (await, Wait, Result, etc.) on this builder's task completes. + /// + /// + /// true to enable notification; false to disable a previously set notification. + /// + internal void SetNotificationForWaitCompletion(bool enabled) + { + m_builder.SetNotificationForWaitCompletion(enabled); + } + + /// + /// Gets an object that may be used to uniquely identify this builder to the debugger. + /// + /// + /// This property lazily instantiates the ID in a non-thread-safe manner. + /// It must only be used by the debugger, and only in a single-threaded manner + /// when no other threads are in the middle of accessing this property or this.Task. + /// + private object ObjectIdForDebugger { get { return this.Task; } } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncTaskMethodBuilderOfTResult.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncTaskMethodBuilderOfTResult.cs new file mode 100644 index 000000000..3d5800866 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncTaskMethodBuilderOfTResult.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Security; +using System.Text; +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + + /// + /// Provides a builder for asynchronous methods that return . + /// This type is intended for compiler use only. + /// + /// + /// AsyncTaskMethodBuilder{TResult} is a value type, and thus it is copied by value. + /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed, + /// or else the copies may end up building distinct Task instances. + /// + public struct AsyncTaskMethodBuilder : IAsyncMethodBuilder + { + /// A cached task for default(TResult). + internal readonly static TaskCompletionSource s_defaultResultTask = AsyncMethodTaskCache.CreateCompleted(default(TResult)); + + // WARNING: For performance reasons, the m_task field is lazily initialized. + // For correct results, the struct AsyncTaskMethodBuilder must + // always be used from the same location/copy, at least until m_task is + // initialized. If that guarantee is broken, the field could end up being + // initialized on the wrong copy. + + /// State related to the IAsyncStateMachine. + private AsyncMethodBuilderCore m_coreState; // mutable struct: must not be readonly + /// The lazily-initialized task. + /// Must be named m_task for debugger step-over to work correctly. + private Task m_task; // lazily-initialized: must not be readonly + /// The lazily-initialized task completion source. + private TaskCompletionSource m_taskCompletionSource; // lazily-initialized: must not be readonly + + /// Temporary support for disabling crashing if tasks go unobserved. + static AsyncTaskMethodBuilder() + { + try { AsyncVoidMethodBuilder.PreventUnobservedTaskExceptions(); } + catch { } + } + + /// Initializes a new . + /// The initialized . + public static AsyncTaskMethodBuilder Create() + { + return default(AsyncTaskMethodBuilder); + // NOTE: If this method is ever updated to perform more initialization, + // ATMB.Create must also be updated to call this Create method. + } + + /// Initiates the builder's execution with the associated state machine. + /// Specifies the type of the state machine. + /// The state machine instance, passed by reference. + [DebuggerStepThrough] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + m_coreState.Start(ref stateMachine); // argument validation handled by AsyncMethodBuilderCore + } + + /// Associates the builder with the state machine it represents. + /// The heap-allocated state machine object. + /// The argument was null (Nothing in Visual Basic). + /// The builder is incorrectly initialized. + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + m_coreState.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore + } + + /// Perform any initialization necessary prior to lifting the builder to the heap. + void IAsyncMethodBuilder.PreBoxInitialization() + { + // Force the Task to be initialized prior to the first suspending await so + // that the original stack-based builder has a reference to the right Task. + var ignored = this.Task; + } + + /// + /// Schedules the specified state machine to be pushed forward when the specified awaiter completes. + /// + /// Specifies the type of the awaiter. + /// Specifies the type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + try + { + var continuation = m_coreState.GetCompletionAction(ref this, ref stateMachine); + Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + awaiter.OnCompleted(continuation); + } + catch (Exception e) + { + AsyncServices.ThrowAsync(e, targetContext: null); + } + } + + /// + /// Schedules the specified state machine to be pushed forward when the specified awaiter completes. + /// + /// Specifies the type of the awaiter. + /// Specifies the type of the state machine. + /// The awaiter. + /// The state machine. +#if !SILVERLIGHT + // [SecuritySafeCritical] +#endif + public void AwaitUnsafeOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + try + { + var continuation = m_coreState.GetCompletionAction(ref this, ref stateMachine); + Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + awaiter.UnsafeOnCompleted(continuation); + } + catch (Exception e) + { + AsyncServices.ThrowAsync(e, targetContext: null); + } + } + + /// Gets the lazily-initialized TaskCompletionSource. + internal TaskCompletionSource CompletionSource + { + get + { + // Get and return the task. If there isn't one, first create one and store it. + var tcs = m_taskCompletionSource; + if (tcs == null) + { + Contract.Assert(m_task == null, "Task should be null if TCS is null"); + m_taskCompletionSource = tcs = new TaskCompletionSource(); + m_task = tcs.Task; + } + return tcs; + } + } + + /// Gets the for this builder. + /// The representing the builder's asynchronous operation. + public Task Task + { + get + { + var tcs = CompletionSource; + Contract.Assert(tcs != null && m_task != null, "Task should have been initialized."); + return tcs.Task; + } + } + + /// + /// Completes the in the + /// RanToCompletion state with the specified result. + /// + /// The result to use to complete the task. + /// The task has already completed. + public void SetResult(TResult result) + { + // Get the currently stored task, which will be non-null if get_Task has already been accessed. + // If there isn't one, get a task and store it. + var tcs = m_taskCompletionSource; + if (tcs == null) + { + Contract.Assert(m_task == null, "Task should be null if TCS is null"); + m_taskCompletionSource = GetTaskForResult(result); + Contract.Assert(m_taskCompletionSource != null, "GetTaskForResult should never return null"); + m_task = m_taskCompletionSource.Task; + } + // Slow path: complete the existing task. + else if (!tcs.TrySetResult(result)) + { + throw new InvalidOperationException("The Task was already completed."); + } + } + + /// + /// Completes the builder by using either the supplied completed task, or by completing + /// the builder's previously accessed task using default(TResult). + /// + /// A task already completed with the value default(TResult). + /// The task has already completed. + internal void SetResult(TaskCompletionSource completedTask) + { + Contract.Requires(completedTask != null, "Expected non-null task"); + Contract.Requires(completedTask.Task.Status == TaskStatus.RanToCompletion, "Expected a successfully completed task"); + + // Get the currently stored task, which will be non-null if get_Task has already been accessed. + // If there isn't one, store the supplied completed task. + var tcs = m_taskCompletionSource; + if (tcs == null) + { + Contract.Assert(m_task == null, "Task should be null if TCS is null"); + m_taskCompletionSource = completedTask; + m_task = m_taskCompletionSource.Task; + } + // Otherwise, complete the task that's there. + else + { + SetResult(default(TResult)); + } + } + + /// + /// Completes the in the + /// Faulted state with the specified exception. + /// + /// The to use to fault the task. + /// The argument is null (Nothing in Visual Basic). + /// The task has already completed. + public void SetException(Exception exception) + { + if (exception == null) throw new ArgumentNullException("exception"); + Contract.EndContractBlock(); + + // Get the task, forcing initialization if it hasn't already been initialized. + var task = this.CompletionSource; + + // If the exception represents cancellation, cancel the task. Otherwise, fault the task. + var oce = exception as OperationCanceledException; + bool successfullySet = oce != null ? + task.TrySetCanceled() : + task.TrySetException(exception); + + // Unlike with TaskCompletionSource, we do not need to spin here until m_task is completed, + // since AsyncTaskMethodBuilder.SetException should not be immediately followed by any code + // that depends on the task having completely completed. Moreover, with correct usage, + // SetResult or SetException should only be called once, so the Try* methods should always + // return true, so no spinning would be necessary anyway (the spinning in TCS is only relevant + // if another thread won the race to complete the task). + + if (!successfullySet) + { + throw new InvalidOperationException("The Task was already completed."); + } + } + + /// + /// Called by the debugger to request notification when the first wait operation + /// (await, Wait, Result, etc.) on this builder's task completes. + /// + /// + /// true to enable notification; false to disable a previously set notification. + /// + /// + /// This should only be invoked from within an asynchronous method, + /// and only by the debugger. + /// + internal void SetNotificationForWaitCompletion(bool enabled) + { + // Nop in the compat lib + } + + /// + /// Gets an object that may be used to uniquely identify this builder to the debugger. + /// + /// + /// This property lazily instantiates the ID in a non-thread-safe manner. + /// It must only be used by the debugger, and only in a single-threaded manner + /// when no other threads are in the middle of accessing this property or this.Task. + /// + private object ObjectIdForDebugger { get { return this.Task; } } + + /// + /// Gets a task for the specified result. This will either + /// be a cached or new task, never null. + /// + /// The result for which we need a task. + /// The completed task containing the result. + private TaskCompletionSource GetTaskForResult(TResult result) + { + //Contract.Ensures( + // EqualityComparer.Default.Equals(result, Contract.Result>().Result), + // "The returned task's Result must return the same value as the specified result value."); + var cache = AsyncMethodTaskCache.Singleton; + return cache != null ? + cache.FromResult(result) : + AsyncMethodTaskCache.CreateCompleted(result); + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncVoidMethodBuilder.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncVoidMethodBuilder.cs new file mode 100644 index 000000000..156d947c9 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/AsyncVoidMethodBuilder.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Security; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + /// + /// Provides a builder for asynchronous methods that return void. + /// This type is intended for compiler use only. + /// + public struct AsyncVoidMethodBuilder : IAsyncMethodBuilder + { + /// The synchronization context associated with this operation. + private readonly SynchronizationContext m_synchronizationContext; + /// State related to the IAsyncStateMachine. + private AsyncMethodBuilderCore m_coreState; // mutable struct: must not be readonly + /// An object used by the debugger to uniquely identify this builder. Lazily initialized. + private object m_objectIdForDebugger; + + /// Temporary support for disabling crashing if tasks go unobserved. + static AsyncVoidMethodBuilder() + { + try { PreventUnobservedTaskExceptions(); } + catch { } + } + + /// Registers with UnobservedTaskException to suppress exception crashing. + internal static void PreventUnobservedTaskExceptions() + { + if (Interlocked.CompareExchange(ref s_preventUnobservedTaskExceptionsInvoked, 1, 0) == 0) + { + TaskScheduler.UnobservedTaskException += (s, e) => e.SetObserved(); + } + } + /// Non-zero if PreventUnobservedTaskExceptions has already been invoked. + private static int s_preventUnobservedTaskExceptionsInvoked; + + /// Initializes a new . + /// The initialized . + public static AsyncVoidMethodBuilder Create() + { + // Capture the current sync context. If there isn't one, use the dummy s_noContextCaptured + // instance; this allows us to tell the state of no captured context apart from the state + // of an improperly constructed builder instance. + return new AsyncVoidMethodBuilder(SynchronizationContext.Current); + } + + /// Initializes the . + /// The synchronizationContext associated with this operation. This may be null. + private AsyncVoidMethodBuilder(SynchronizationContext synchronizationContext) + { + m_synchronizationContext = synchronizationContext; + if (synchronizationContext != null) synchronizationContext.OperationStarted(); + + m_coreState = default(AsyncMethodBuilderCore); + m_objectIdForDebugger = null; + } + + /// Initiates the builder's execution with the associated state machine. + /// Specifies the type of the state machine. + /// The state machine instance, passed by reference. + /// The argument was null (Nothing in Visual Basic). + [DebuggerStepThrough] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + m_coreState.Start(ref stateMachine); // argument validation handled by AsyncMethodBuilderCore + } + + /// Associates the builder with the state machine it represents. + /// The heap-allocated state machine object. + /// The argument was null (Nothing in Visual Basic). + /// The builder is incorrectly initialized. + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + m_coreState.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore + } + + /// Perform any initialization necessary prior to lifting the builder to the heap. + void IAsyncMethodBuilder.PreBoxInitialization() { /* no initialization is necessary for AsyncVoidMethodBuilder */ } + + /// + /// Schedules the specified state machine to be pushed forward when the specified awaiter completes. + /// + /// Specifies the type of the awaiter. + /// Specifies the type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + try + { + var continuation = m_coreState.GetCompletionAction(ref this, ref stateMachine); + Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + awaiter.OnCompleted(continuation); + } + catch (Exception exc) + { + // Prevent exceptions from leaking to the call site, which could + // then allow multiple flows of execution through the same async method + // if the awaiter had already scheduled the continuation by the time + // the exception was thrown. We propagate the exception on the + // ThreadPool because we can trust it to not throw, unlike + // if we were to go to a user-supplied SynchronizationContext, + // whose Post method could easily throw. + AsyncServices.ThrowAsync(exc, targetContext: null); + } + } + + /// + /// Schedules the specified state machine to be pushed forward when the specified awaiter completes. + /// + /// Specifies the type of the awaiter. + /// Specifies the type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitUnsafeOnCompleted( + ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + try + { + var continuation = m_coreState.GetCompletionAction(ref this, ref stateMachine); + Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + awaiter.UnsafeOnCompleted(continuation); + } + catch (Exception e) + { + AsyncServices.ThrowAsync(e, targetContext: null); + } + } + + /// Completes the method builder successfully. + public void SetResult() + { + if (m_synchronizationContext != null) + { + NotifySynchronizationContextOfCompletion(); + } + } + + /// Faults the method builder with an exception. + /// The exception that is the cause of this fault. + /// The argument is null (Nothing in Visual Basic). + /// The builder is not initialized. + public void SetException(Exception exception) + { + if (exception == null) throw new ArgumentNullException("exception"); + Contract.EndContractBlock(); + + if (m_synchronizationContext != null) + { + // If we captured a synchronization context, Post the throwing of the exception to it + // and decrement its outstanding operation count. + try + { + AsyncServices.ThrowAsync(exception, targetContext: m_synchronizationContext); + } + finally + { + NotifySynchronizationContextOfCompletion(); + } + } + else + { + // Otherwise, queue the exception to be thrown on the ThreadPool. This will + // result in a crash unless legacy exception behavior is enabled by a config + // file or a CLR host. + AsyncServices.ThrowAsync(exception, targetContext: null); + } + } + + /// Notifies the current synchronization context that the operation completed. + private void NotifySynchronizationContextOfCompletion() + { + Contract.Assert(m_synchronizationContext != null, "Must only be used with a non-null context."); + try + { + m_synchronizationContext.OperationCompleted(); + } + catch (Exception exc) + { + // If the interaction with the SynchronizationContext goes awry, + // fall back to propagating on the ThreadPool. + AsyncServices.ThrowAsync(exc, targetContext: null); + } + } + + /// + /// Gets an object that may be used to uniquely identify this builder to the debugger. + /// + /// + /// This property lazily instantiates the ID in a non-thread-safe manner. + /// It must only be used by the debugger and only in a single-threaded manner. + /// + private object ObjectIdForDebugger + { + get + { + if (m_objectIdForDebugger == null) m_objectIdForDebugger = new object(); + return m_objectIdForDebugger; + } + } + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/IAsyncMethodBuilder.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/IAsyncMethodBuilder.cs new file mode 100644 index 000000000..0dadf99f7 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/IAsyncMethodBuilder.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + /// Represents an asynchronous method builder. + internal interface IAsyncMethodBuilder + { + void PreBoxInitialization(); + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/IAsyncStateMachine.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/IAsyncStateMachine.cs new file mode 100644 index 000000000..cc1db2fcc --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/IAsyncStateMachine.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + /// + /// Represents state machines generated for asynchronous methods. + /// This type is intended for compiler use only. + /// + public interface IAsyncStateMachine + { + /// Moves the state machine to its next state. + void MoveNext(); + /// Configures the state machine with a heap-allocated replica. + /// The heap-allocated replica. + void SetStateMachine(IAsyncStateMachine stateMachine); + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/ICriticalNotifyCompletion.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/ICriticalNotifyCompletion.cs new file mode 100644 index 000000000..de6d6465a --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/ICriticalNotifyCompletion.cs @@ -0,0 +1,17 @@ +using System; + +namespace System.Runtime.CompilerServices +{ + /// + /// Represents an awaiter used to schedule continuations when an await operation completes. + /// + public interface ICriticalNotifyCompletion : INotifyCompletion + { + /// Schedules the continuation action to be invoked when the instance completes. + /// The action to invoke when the operation completes. + /// The argument is null (Nothing in Visual Basic). + /// Unlike OnCompleted, UnsafeOnCompleted need not propagate ExecutionContext information. + void UnsafeOnCompleted(Action continuation); + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/INotifyCompletion.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/INotifyCompletion.cs new file mode 100644 index 000000000..c9c0a85e7 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/INotifyCompletion.cs @@ -0,0 +1,15 @@ +using System; + +namespace System.Runtime.CompilerServices +{ + /// + /// Represents an operation that will schedule continuations when the operation completes. + /// + public interface INotifyCompletion + { + /// Schedules the continuation action to be invoked when the instance completes. + /// The action to invoke when the operation completes. + /// The argument is null (Nothing in Visual Basic). + void OnCompleted(Action continuation); + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/VoidTaskResult.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/VoidTaskResult.cs new file mode 100644 index 000000000..268ab4b51 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Runtime/CompilerServices/VoidTaskResult.cs @@ -0,0 +1,7 @@ +using System; + +namespace System.Runtime.CompilerServices +{ + /// Used with Task(of void) + internal struct VoidTaskResult { } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/StackCrawlMark.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/StackCrawlMark.cs new file mode 100644 index 000000000..b08523a47 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/StackCrawlMark.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Threading +{ + /// + /// A dummy replacement for the .NET internal class StackCrawlMark. + /// + internal struct StackCrawlMark + { + internal static StackCrawlMark LookForMyCaller + { + get { return new StackCrawlMark(); } + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationToken.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationToken.cs new file mode 100644 index 000000000..e8672a107 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationToken.cs @@ -0,0 +1,468 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// +// mikelid +//////////////////////////////////////////////////////////////////////////////// + +#pragma warning disable 0420 // turn off 'a reference to a volatile field will not be treated as volatile' during CAS. + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Diagnostics.Contracts; + +namespace System.Threading +{ + /// + /// Propogates notification that operations should be canceled. + /// + /// + /// + /// A may be created directly in an unchangeable canceled or non-canceled state + /// using the CancellationToken's constructors. However, to have a CancellationToken that can change + /// from a non-canceled to a canceled state, + /// CancellationTokenSource must be used. + /// CancellationTokenSource exposes the associated CancellationToken that may be canceled by the source through its + /// Token property. + /// + /// + /// Once canceled, a token may not transition to a non-canceled state, and a token whose + /// is false will never change to one that can be canceled. + /// + /// + /// All members of this struct are thread-safe and may be used concurrently from multiple threads. + /// + /// + [DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")] + public struct CancellationToken + { + // The backing TokenSource. + // if null, it implicitly represents the same thing as new CancellationToken(false). + // When required, it will be instantiated to reflect this. + private CancellationTokenSource m_source; + //!! warning. If more fields are added, the assumptions in CreateLinkedToken may no longer be valid + + /* Properties */ + + /// + /// Returns an empty CancellationToken value. + /// + /// + /// The value returned by this property will be non-cancelable by default. + /// + public static CancellationToken None + { + get + { + return new CancellationToken(); + } + } + + /// + /// Gets whether cancellation has been requested for this token. + /// + /// Whether cancellation has been requested for this token. + /// + /// + /// This property indicates whether cancellation has been requested for this token, + /// either through the token initially being construted in a canceled state, or through + /// calling Cancel + /// on the token's associated . + /// + /// + /// If this property is true, it only guarantees that cancellation has been requested. + /// It does not guarantee that every registered handler + /// has finished executing, nor that cancellation requests have finished propagating + /// to all registered handlers. Additional synchronization may be required, + /// particularly in situations where related objects are being canceled concurrently. + /// + /// + public bool IsCancellationRequested { + get + { + return m_source != null && m_source.IsCancellationRequested; + } + } + + /// + /// Gets whether this token is capable of being in the canceled state. + /// + /// + /// If CanBeCanceled returns false, it is guaranteed that the token will never transition + /// into a canceled state, meaning that will never + /// return true. + /// + public bool CanBeCanceled + { + get + { + return m_source != null && m_source.CanBeCanceled; + } + } + + /// + /// Gets a that is signaled when the token is canceled. + /// + /// Accessing this property causes a WaitHandle + /// to be instantiated. It is preferable to only use this property when necessary, and to then + /// dispose the associated instance at the earliest opportunity (disposing + /// the source will dispose of this allocated handle). The handle should not be closed or disposed directly. + /// + /// The associated CancellationTokenSource has been disposed. + public WaitHandle WaitHandle + { + get + { + if (m_source == null) + { + InitializeDefaultSource(); + } + + return m_source.WaitHandle; + } + } + + // public CancellationToken() + // this constructor is implicit for structs + // -> this should behaves exactly as for new CancellationToken(false) + + /// + /// Internal constructor only a CancellationTokenSource should create a CancellationToken + /// + internal CancellationToken(CancellationTokenSource source) + { + m_source = source; + } + + /// + /// Initializes the CancellationToken. + /// + /// + /// The canceled state for the token. + /// + /// + /// Tokens created with this constructor will remain in the canceled state specified + /// by the parameter. If is false, + /// both and will be false. + /// If is true, + /// both and will be true. + /// + public CancellationToken(bool canceled) : + this() + { + if(canceled) + m_source = CancellationTokenSource.InternalGetStaticSource(canceled); + } + + /* Methods */ + + + private static Action s_ActionToActionObjShunt = new Action(ActionToActionObjShunt); + private static void ActionToActionObjShunt(object obj) + { + Action action = obj as Action; + Contract.Assert(action != null, "Expected an Action here"); + action(); + } + + /// + /// Registers a delegate that will be called when this CancellationToken is canceled. + /// + /// + /// + /// If this token is already in the canceled state, the + /// delegate will be run immediately and synchronously. Any exception the delegate generates will be + /// propogated out of this method call. + /// + /// + /// The delegate to be executed when the CancellationToken is canceled. + /// The instance that can + /// be used to deregister the callback. + /// is null. + /// The associated CancellationTokenSource has been disposed. + public CancellationTokenRegistration Register(Action callback) + { + if (callback == null) + throw new ArgumentNullException("callback"); + + return Register( + s_ActionToActionObjShunt, + callback, + false, // useSync=false + true // useExecutionContext=true + ); + } + + /// + /// Registers a delegate that will be called when this + /// CancellationToken is canceled. + /// + /// + /// + /// If this token is already in the canceled state, the + /// delegate will be run immediately and synchronously. Any exception the delegate generates will be + /// propogated out of this method call. + /// + /// + /// The delegate to be executed when the CancellationToken is canceled. + /// A Boolean value that indicates whether to capture + /// the current SynchronizationContext and use it + /// when invoking the . + /// The instance that can + /// be used to deregister the callback. + /// is null. + /// The associated CancellationTokenSource has been disposed. + public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext) + { + if (callback == null) + throw new ArgumentNullException("callback"); + + return Register( + s_ActionToActionObjShunt, + callback, + useSynchronizationContext, + true // useExecutionContext=true + ); + } + + /// + /// Registers a delegate that will be called when this + /// CancellationToken is canceled. + /// + /// + /// + /// If this token is already in the canceled state, the + /// delegate will be run immediately and synchronously. Any exception the delegate generates will be + /// propogated out of this method call. + /// + /// + /// The delegate to be executed when the CancellationToken is canceled. + /// The state to pass to the when the delegate is invoked. This may be null. + /// The instance that can + /// be used to deregister the callback. + /// is null. + /// The associated CancellationTokenSource has been disposed. + public CancellationTokenRegistration Register(Action callback, Object state) + { + if (callback == null) + throw new ArgumentNullException("callback"); + + return Register( + callback, + state, + false, // useSync=false + true // useExecutionContext=true + ); + } + + /// + /// Registers a delegate that will be called when this + /// CancellationToken is canceled. + /// + /// + /// + /// If this token is already in the canceled state, the + /// delegate will be run immediately and synchronously. Any exception the delegate generates will be + /// propogated out of this method call. + /// + /// + /// The delegate to be executed when the CancellationToken is canceled. + /// The state to pass to the when the delegate is invoked. This may be null. + /// A Boolean value that indicates whether to capture + /// the current SynchronizationContext and use it + /// when invoking the . + /// The instance that can + /// be used to deregister the callback. + /// is null. + /// The associated CancellationTokenSource has been disposed. + public CancellationTokenRegistration Register(Action callback, Object state, bool useSynchronizationContext) + { + return Register( + callback, + state, + useSynchronizationContext, + true // useExecutionContext=true + ); + } + + // helper for internal registration needs that don't require an EC capture (e.g. creating linked token sources, or registering unstarted TPL tasks) + // has a handy signature, and skips capturing execution context. + internal CancellationTokenRegistration InternalRegisterWithoutEC(Action callback, Object state) + { + return Register( + callback, + state, + false, // useSyncContext=false + false // useExecutionContext=false + ); + } + + // the real work.. + private CancellationTokenRegistration Register(Action callback, Object state, bool useSynchronizationContext, bool useExecutionContext) + { + if (callback == null) + throw new ArgumentNullException("callback"); + + if(CanBeCanceled == false) + { + return new CancellationTokenRegistration(); // nothing to do for tokens than can never reach the canceled state. Give them a dummy registration. + } + + // Capture sync/execution contexts if required. + // Note: Only capture sync/execution contexts if IsCancellationRequested = false + // as we know that if it is true that the callback will just be called synchronously. + + SynchronizationContext capturedSyncContext = null; + if (!IsCancellationRequested && useSynchronizationContext) + capturedSyncContext = SynchronizationContext.Current; + + // Register the callback with the source. + return m_source.InternalRegister(callback, state, capturedSyncContext); + } + + /// + /// Determines whether the current CancellationToken instance is equal to the + /// specified token. + /// + /// The other CancellationToken to which to compare this + /// instance. + /// True if the instances are equal; otherwise, false. Two tokens are equal if they are associated + /// with the same CancellationTokenSource or if they were both constructed + /// from public CancellationToken constructors and their values are equal. + public bool Equals(CancellationToken other) + { + //if both sources are null, then both tokens represent the Empty token. + if (m_source == null && other.m_source == null) + { + return true; + } + + // one is null but other has inflated the default source + // these are only equal if the inflated one is the staticSource(false) + if (m_source == null) + { + return other.m_source == CancellationTokenSource.InternalGetStaticSource(false); + } + + if (other.m_source == null) + { + return m_source == CancellationTokenSource.InternalGetStaticSource(false); + } + + // general case, we check if the sources are identical + + return m_source == other.m_source; + } + + /// + /// Determines whether the current CancellationToken instance is equal to the + /// specified . + /// + /// The other object to which to compare this instance. + /// True if is a CancellationToken + /// and if the two instances are equal; otherwise, false. Two tokens are equal if they are associated + /// with the same CancellationTokenSource or if they were both constructed + /// from public CancellationToken constructors and their values are equal. + /// An associated CancellationTokenSource has been disposed. + public override bool Equals(Object other) + { + if (other is CancellationToken) + { + return Equals((CancellationToken) other); + } + + return false; + } + + /// + /// Serves as a hash function for a CancellationToken. + /// + /// A hash code for the current CancellationToken instance. + public override Int32 GetHashCode() + { + if (m_source == null) + { + // link to the common source so that we have a source to interrogate. + return CancellationTokenSource.InternalGetStaticSource(false).GetHashCode(); + } + + return m_source.GetHashCode(); + } + + /// + /// Determines whether two CancellationToken instances are equal. + /// + /// The first instance. + /// The second instance. + /// True if the instances are equal; otherwise, false. + /// An associated CancellationTokenSource has been disposed. + public static bool operator ==(CancellationToken left, CancellationToken right) + { + return left.Equals(right); + } + + /// + /// Determines whether two CancellationToken instances are not equal. + /// + /// The first instance. + /// The second instance. + /// True if the instances are not equal; otherwise, false. + /// An associated CancellationTokenSource has been disposed. + public static bool operator !=(CancellationToken left, CancellationToken right) + { + return !left.Equals(right); + } + + /// + /// Throws a OperationCanceledException if + /// this token has had cancellation requested. + /// + /// + /// This method provides functionality equivalent to: + /// + /// if (token.IsCancellationRequested) + /// throw new OperationCanceledException(token); + /// + /// + /// The token has had cancellation requested. + /// The associated CancellationTokenSource has been disposed. + public void ThrowIfCancellationRequested() + { + if (IsCancellationRequested) + throw new OperationCanceledException(Strings.OperationCanceled, this); + } + + // Throw an ODE if this CancellationToken's source is disposed. + internal void ThrowIfSourceDisposed() + { + if ((m_source != null) && m_source.IsDisposed) + { + throw new ObjectDisposedException(null, Strings.CancellationToken_SourceDisposed); + } + } + + + // ----------------------------------- + // Private helpers + + private void InitializeDefaultSource() + { + // Lazy is slower, and although multiple threads may race and set m_source repeatedly, the race is benign. + // Alternative: LazyInititalizer.EnsureInitialized(ref m_source, ()=>CancellationTokenSource.InternalGetStaticSource(false)); + + m_source = CancellationTokenSource.InternalGetStaticSource(false); + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationTokenRegistration.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationTokenRegistration.cs new file mode 100644 index 000000000..2bfeb56ea --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationTokenRegistration.cs @@ -0,0 +1,165 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// +// mikelid +//////////////////////////////////////////////////////////////////////////////// + +using System.Diagnostics.Contracts; + +namespace System.Threading +{ + /// + /// Represents a callback delegate that has been registered with a CancellationToken. + /// + /// + /// To unregister a callback, dispose the corresponding Registration instance. + /// + + public struct CancellationTokenRegistration : IEquatable, IDisposable + { + private readonly CancellationTokenSource m_tokenSource; + private readonly CancellationCallbackInfo m_callbackInfo; + private readonly SparselyPopulatedArrayAddInfo m_registrationInfo; + + internal CancellationTokenRegistration( + CancellationTokenSource tokenSource, + CancellationCallbackInfo callbackInfo, + SparselyPopulatedArrayAddInfo registrationInfo) + { + m_tokenSource = tokenSource; + m_callbackInfo = callbackInfo; + m_registrationInfo = registrationInfo; + } + + /// + /// Attempts to deregister the item. If it's already being run, this may fail. + /// Entails a full memory fence. + /// + /// True if the callback was found and deregistered, false otherwise. + internal bool TryDeregister() + { + if (m_registrationInfo.Source == null) //can be null for dummy registrations. + return false; + + // Try to remove the callback info from the array. + // It is possible the callback info is missing (removed for run, or removed by someone else) + // It is also possible there is info in the array but it doesn't match our current registration's callback info. + CancellationCallbackInfo prevailingCallbackInfoInSlot = m_registrationInfo.Source.SafeAtomicRemove(m_registrationInfo.Index, m_callbackInfo); + + if (prevailingCallbackInfoInSlot != m_callbackInfo) + return false; //the callback in the slot wasn't us. + + return true; + } + + /// + /// Disposes of the registration and unregisters the target callback from the associated + /// CancellationToken. + /// If the target callback is currently executing this method will wait until it completes, except + /// in the degenerate cases where a callback method deregisters itself. + /// + public void Dispose() + { + // If the token source has been disposed, we must throw. + if (m_tokenSource != null) + m_tokenSource.ThrowIfDisposed(); + + // Remove the entry from the array. + // This call includes a full memory fence which prevents potential reorderings of the reads below + bool deregisterOccured = TryDeregister(); + + // We guarantee that we will not return if the callback is being executed (assuming we are not currently called by the callback itself) + // We achieve this by the following rules: + // 1. if we are called in the context of an executing callback, no need to wait (determined by tracking callback-executor threadID) + // - if the currently executing callback is this CTR, then waiting would deadlock. (We choose to return rather than deadlock) + // - if not, then this CTR cannot be the one executing, hence no need to wait + // + // 2. if deregistration failed, and we are on a different thread, then the callback may be running under control of cts.Cancel() + // => poll until cts.ExecutingCallback is not the one we are trying to deregister. + + if (m_tokenSource != null && + m_tokenSource.IsCancellationRequested && //running callbacks has commenced. + ! m_tokenSource.IsCancellationCompleted && //running callbacks hasn't finished + !deregisterOccured && //deregistration failed (ie the callback is missing from the list) + m_tokenSource.ThreadIDExecutingCallbacks != Thread.CurrentThread.ManagedThreadId) //the executingThreadID is not this threadID. + { + // Callback execution is in progress, the executing thread is different to us and has taken the callback for execution + // so observe and wait until this target callback is no longer the executing callback. + m_tokenSource.WaitForCallbackToComplete(m_callbackInfo); + } + } + + /// + /// Determines whether two CancellationTokenRegistration + /// instances are equal. + /// + /// The first instance. + /// The second instance. + /// True if the instances are equal; otherwise, false. + public static bool operator ==(CancellationTokenRegistration left, CancellationTokenRegistration right) + { + return left.Equals(right); + } + + /// + /// Determines whether two CancellationTokenRegistration instances are not equal. + /// + /// The first instance. + /// The second instance. + /// True if the instances are not equal; otherwise, false. + public static bool operator !=(CancellationTokenRegistration left, CancellationTokenRegistration right) + { + return !left.Equals(right); + } + + /// + /// Determines whether the current CancellationTokenRegistration instance is equal to the + /// specified . + /// + /// The other object to which to compare this instance. + /// True, if both this and are equal. False, otherwise. + /// Two CancellationTokenRegistration instances are equal if + /// they both refer to the output of a single call to the same Register method of a + /// CancellationToken. + /// + public override bool Equals(object obj) + { + return ((obj is CancellationTokenRegistration) && Equals((CancellationTokenRegistration) obj)); + } + + /// + /// Determines whether the current CancellationToken instance is equal to the + /// specified . + /// + /// The other CancellationTokenRegistration to which to compare this instance. + /// True, if both this and are equal. False, otherwise. + /// Two CancellationTokenRegistration instances are equal if + /// they both refer to the output of a single call to the same Register method of a + /// CancellationToken. + /// + public bool Equals(CancellationTokenRegistration other) + { + + return m_tokenSource == other.m_tokenSource && + m_callbackInfo == other.m_callbackInfo && + m_registrationInfo.Source == other.m_registrationInfo.Source && + m_registrationInfo.Index == other.m_registrationInfo.Index; + } + + /// + /// Serves as a hash function for a CancellationTokenRegistration.. + /// + /// A hash code for the current CancellationTokenRegistration instance. + public override int GetHashCode() + { + if (m_registrationInfo.Source != null) + return m_registrationInfo.Source.GetHashCode() ^ m_registrationInfo.Index.GetHashCode(); + + return m_registrationInfo.Index.GetHashCode(); + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationTokenSource.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationTokenSource.cs new file mode 100644 index 000000000..3d0191955 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/CancellationTokenSource.cs @@ -0,0 +1,934 @@ +#pragma warning disable 0420 +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// +// mikelid +//////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Security; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Diagnostics.Contracts; + +namespace System.Threading +{ + /// + /// Signals to a that it should be canceled. + /// + /// + /// + /// is used to instantiate a + /// (via the source's Token property) + /// that can be handed to operations that wish to be notified of cancellation or that can be used to + /// register asynchronous operations for cancellation. That token may have cancellation requested by + /// calling to the source's Cancel + /// method. + /// + /// + /// All members of this class, except Dispose, are thread-safe and may be used + /// concurrently from multiple threads. + /// + /// + public sealed class CancellationTokenSource : IDisposable + { + //static sources that can be used as the backing source for 'fixed' CancellationTokens that never change state. + private static readonly CancellationTokenSource _staticSource_Set = new CancellationTokenSource(true); + private static readonly CancellationTokenSource _staticSource_NotCancelable = new CancellationTokenSource(false); + + //Note: the callback lists array is only created on first registration. + // the actual callback lists are only created on demand. + // Storing a registered callback costs around >60bytes, hence some overhead for the lists array is OK + // At most 24 lists seems reasonable, and caps the cost of the listsArray to 96bytes(32-bit,24-way) or 192bytes(64-bit,24-way). + private static readonly int s_nLists = (PlatformHelper.ProcessorCount > 24) ? 24 : PlatformHelper.ProcessorCount; + + private volatile ManualResetEvent m_kernelEvent; //lazily initialized if required. + + private volatile SparselyPopulatedArray[] m_registeredCallbacksLists; + + // legal values for m_state + private const int CANNOT_BE_CANCELED = 0; + private const int NOT_CANCELED = 1; + private const int NOTIFYING = 2; + private const int NOTIFYINGCOMPLETE = 3; + + //m_state uses the pattern "volatile int32 reads, with cmpxch writes" which is safe for updates and cannot suffer torn reads. + private volatile int m_state; + + + /// The ID of the thread currently executing the main body of CTS.Cancel() + /// this helps us to know if a call to ctr.Dispose() is running 'within' a cancellation callback. + /// This is updated as we move between the main thread calling cts.Cancel() and any syncContexts that are used to + /// actually run the callbacks. + private volatile int m_threadIDExecutingCallbacks = -1; + + private bool m_disposed; + + private List m_linkingRegistrations; //lazily initialized if required. + + private static readonly Action s_LinkedTokenCancelDelegate = new Action(LinkedTokenCancelDelegate); + + // we track the running callback to assist ctr.Dispose() to wait for the target callback to complete. + private volatile CancellationCallbackInfo m_executingCallback; + + private static void LinkedTokenCancelDelegate(object source) + { + CancellationTokenSource cts = source as CancellationTokenSource; + Contract.Assert(source != null); + cts.Cancel(); + } + + // ---------------------- + // ** public properties + + /// + /// Gets whether cancellation has been requested for this CancellationTokenSource. + /// + /// Whether cancellation has been requested for this CancellationTokenSource. + /// + /// + /// This property indicates whether cancellation has been requested for this token source, such as + /// due to a call to its + /// Cancel method. + /// + /// + /// If this property returns true, it only guarantees that cancellation has been requested. It does not + /// guarantee that every handler registered with the corresponding token has finished executing, nor + /// that cancellation requests have finished propagating to all registered handlers. Additional + /// synchronization may be required, particularly in situations where related objects are being + /// canceled concurrently. + /// + /// + public bool IsCancellationRequested + { + get { return m_state >= NOTIFYING; } + } + + /// + /// A simple helper to determine whether cancellation has finished. + /// + internal bool IsCancellationCompleted + { + get { return m_state == NOTIFYINGCOMPLETE; } + } + + /// + /// A simple helper to determine whether disposal has occured. + /// + internal bool IsDisposed + { + get { return m_disposed; } + } + + /// + /// The ID of the thread that is running callbacks. + /// + internal int ThreadIDExecutingCallbacks + { + set { m_threadIDExecutingCallbacks = value; } + get { return m_threadIDExecutingCallbacks; } + } + + /// + /// Gets the CancellationToken + /// associated with this . + /// + /// The CancellationToken + /// associated with this . + /// The token source has been + /// disposed. + public CancellationToken Token + { + get + { + ThrowIfDisposed(); + return new CancellationToken(this); + } + } + + // ---------------------- + // ** internal and private properties. + + /// + /// + /// + internal bool CanBeCanceled + { + get { return m_state != CANNOT_BE_CANCELED; } + } + + /// + /// + /// + internal WaitHandle WaitHandle + { + get + { + ThrowIfDisposed(); + + // fast path if already allocated. + if (m_kernelEvent != null) + return m_kernelEvent; + + // lazy-init the mre. + ManualResetEvent mre = new ManualResetEvent(false); + if (Interlocked.CompareExchange(ref m_kernelEvent, mre, null) != null) + { + ((IDisposable)mre).Dispose(); + } + + // There is a race between checking IsCancellationRequested and setting the event. + // However, at this point, the kernel object definitely exists and the cases are: + // 1. if IsCancellationRequested = true, then we will call Set() + // 2. if IsCancellationRequested = false, then NotifyCancellation will see that the event exists, and will call Set(). + if (IsCancellationRequested) + m_kernelEvent.Set(); + + return m_kernelEvent; + } + } + + + /// + /// The currently executing callback + /// + internal CancellationCallbackInfo ExecutingCallback + { + get { return m_executingCallback; } + } + +#if DEBUG + /// + /// Used by the dev unit tests to check the number of outstanding registrations. + /// They use private reflection to gain access. Because this would be dead retail + /// code, however, it is ifdef'd out to work only in debug builds. + /// + private int CallbackCount + { + get + { + SparselyPopulatedArray[] callbackLists = m_registeredCallbacksLists; + if (callbackLists == null) + return 0; + + int count = 0; + foreach(SparselyPopulatedArray sparseArray in callbackLists) + { + if(sparseArray != null) + { + SparselyPopulatedArrayFragment currCallbacks = sparseArray.Head; + while (currCallbacks != null) + { + for (int i = 0; i < currCallbacks.Length; i++) + if (currCallbacks[i] != null) + count++; + + currCallbacks = currCallbacks.Next; + } + } + } + return count; + } + } +#endif + + // ** Public Constructors + + /// + /// Initializes the . + /// + public CancellationTokenSource() + { + m_state = NOT_CANCELED; + } + + // ** Private constructors for static sources. + // set=false ==> cannot be canceled. + // set=true ==> is canceled. + private CancellationTokenSource(bool set) + { + m_state = set ? NOTIFYINGCOMPLETE : CANNOT_BE_CANCELED; + } + + // ** Public Methods + + /// + /// Communicates a request for cancellation. + /// + /// + /// + /// The associated will be + /// notified of the cancellation and will transition to a state where + /// IsCancellationRequested returns true. + /// Any callbacks or cancelable operations + /// registered with the will be executed. + /// + /// + /// Cancelable operations and callbacks registered with the token should not throw exceptions. + /// However, this overload of Cancel will aggregate any exceptions thrown into a , + /// such that one callback throwing an exception will not prevent other registered callbacks from being executed. + /// + /// + /// The that was captured when each callback was registered + /// will be reestablished when the callback is invoked. + /// + /// + /// An aggregate exception containing all the exceptions thrown + /// by the registered callbacks on the associated . + /// This has been disposed. + public void Cancel() + { + Cancel(false); + } + + /// + /// Communicates a request for cancellation. + /// + /// + /// + /// The associated will be + /// notified of the cancellation and will transition to a state where + /// IsCancellationRequested returns true. + /// Any callbacks or cancelable operations + /// registered with the will be executed. + /// + /// + /// Cancelable operations and callbacks registered with the token should not throw exceptions. + /// If is true, an exception will immediately propagate out of the + /// call to Cancel, preventing the remaining callbacks and cancelable operations from being processed. + /// If is false, this overload will aggregate any + /// exceptions thrown into a , + /// such that one callback throwing an exception will not prevent other registered callbacks from being executed. + /// + /// + /// The that was captured when each callback was registered + /// will be reestablished when the callback is invoked. + /// + /// + /// Specifies whether exceptions should immediately propagate. + /// An aggregate exception containing all the exceptions thrown + /// by the registered callbacks on the associated . + /// This has been disposed. + public void Cancel(bool throwOnFirstException) + { + ThrowIfDisposed(); + NotifyCancellation(throwOnFirstException); + } + + /// + /// Releases the resources used by this . + /// + /// + /// This method is not thread-safe for any other concurrent calls. + /// + public void Dispose() + { + if (m_disposed) + return; + + bool isLinked = m_linkingRegistrations != null; + if (isLinked) + { + foreach (CancellationTokenRegistration registration in m_linkingRegistrations) + { + registration.Dispose(); + } + m_linkingRegistrations = null; //free for GC + } + + // registered callbacks are now either complete or will never run, due to guarantees made by ctr.Dispose() + // so we can now perform main disposal work without risk of linking callbacks trying to use this CTS. + + m_registeredCallbacksLists = null; // free for GC. + + if (m_kernelEvent != null) + { + m_kernelEvent.Dispose(); // the critical cleanup to release an OS handle + m_kernelEvent = null; // free for GC. + } + + m_disposed = true; + } + + // -- Internal methods. + + /// + /// Throws an exception if the source has been disposed. + /// + internal void ThrowIfDisposed() + { + if (m_disposed) + throw new ObjectDisposedException(null, Strings.CancellationTokenSource_Disposed); + } + + /// + /// InternalGetStaticSource() + /// + /// Whether the source should be set. + /// A static source to be shared among multiple tokens. + internal static CancellationTokenSource InternalGetStaticSource(bool set) + { + return set ? _staticSource_Set : _staticSource_NotCancelable; + } + + /// + /// Registers a callback object. If cancellation has already occurred, the + /// callback will have been run by the time this method returns. + /// + internal CancellationTokenRegistration InternalRegister( + Action callback, object stateForCallback, SynchronizationContext targetSyncContext) + { + ThrowIfDisposed(); + + // the CancellationToken has already checked that the token is cancelable before calling this method. + Contract.Assert(CanBeCanceled, "Cannot register for uncancelable token src"); + + // if not canceled, register the event handlers + // if canceled already, run the callback synchronously + // Apart from the semantics of late-enlistment, this also ensures that during ExecuteCallbackHandlers() there + // will be no mutation of the _registeredCallbacks list + + if (!IsCancellationRequested) + { + int myIndex = Thread.CurrentThread.ManagedThreadId % s_nLists; + + CancellationCallbackInfo callbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, this); + + //allocate the callback list array + if (m_registeredCallbacksLists == null) + { + SparselyPopulatedArray[] list = new SparselyPopulatedArray[s_nLists]; + Interlocked.CompareExchange(ref m_registeredCallbacksLists, list, null); + } + + //allocate the actual lists on-demand to save mem in low-use situations, and to avoid false-sharing. + if (m_registeredCallbacksLists[myIndex] == null) + { + SparselyPopulatedArray callBackArray = new SparselyPopulatedArray(4); + Interlocked.CompareExchange(ref (m_registeredCallbacksLists[myIndex]), callBackArray, null); + } + + // Now add the registration to the list. + SparselyPopulatedArray callbacks = m_registeredCallbacksLists[myIndex]; + SparselyPopulatedArrayAddInfo addInfo = callbacks.Add(callbackInfo); + CancellationTokenRegistration registration = new CancellationTokenRegistration(this, callbackInfo, addInfo); + + if (!IsCancellationRequested) + return registration; + + //If a cancellation has since come in, we will try to undo the registration and run the callback directly here. + bool deregisterOccurred = registration.TryDeregister(); + + if (!deregisterOccurred) + { + // the callback execution process must have snagged the callback for execution, so + // 1. wait for the callback to complete, then + // 2. return a dummy registration. + WaitForCallbackToComplete(callbackInfo); + return new CancellationTokenRegistration(); + } + } + + // If cancellation already occurred, we run the callback on this thread and return an empty registration. + callback(stateForCallback); + return new CancellationTokenRegistration(); + } + + /// + /// + /// + private void NotifyCancellation(bool throwOnFirstException) + { + // fast-path test to check if Notify has been called previously + if (IsCancellationRequested) + return; + + // If we're the first to signal cancellation, do the main extra work. + if (Interlocked.CompareExchange(ref m_state, NOTIFYING, NOT_CANCELED) == NOT_CANCELED) + { + //record the threadID being used for running the callbacks. + ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; + + //If the kernel event is null at this point, it will be set during lazy construction. + if (m_kernelEvent != null) + m_kernelEvent.Set(); // update the MRE value. + + // - late enlisters to the Canceled event will have their callbacks called immediately in the Register() methods. + // - Callbacks are not called inside a lock. + // - After transition, no more delegates will be added to the + // - list of handlers, and hence it can be consumed and cleared at leisure by ExecuteCallbackHandlers. + ExecuteCallbackHandlers(throwOnFirstException); + Contract.Assert(IsCancellationCompleted, "Expected cancellation to have finished"); + } + } + + /// + /// Invoke the Canceled event. + /// + /// + /// The handlers are invoked synchronously in LIFO order. + /// + private void ExecuteCallbackHandlers(bool throwOnFirstException) + { + Contract.Assert(IsCancellationRequested, "ExecuteCallbackHandlers should only be called after setting IsCancellationRequested->true"); + Contract.Assert(ThreadIDExecutingCallbacks != -1, "ThreadIDExecutingCallbacks should have been set."); + + // Design decision: call the delegates in LIFO order so that callbacks fire 'deepest first'. + // This is intended to help with nesting scenarios so that child enlisters cancel before their parents. + List exceptionList = null; + SparselyPopulatedArray[] callbackLists = m_registeredCallbacksLists; + + // If there are no callbacks to run, we can safely exit. Any races to lazy initialize it + // will see IsCancellationRequested and will then run the callback themselves. + if (callbackLists == null) + { + Interlocked.Exchange(ref m_state, NOTIFYINGCOMPLETE); + return; + } + + try + { + for (int index = 0; index < callbackLists.Length; index++) + { + SparselyPopulatedArray list = callbackLists[index]; + if (list != null) + { + SparselyPopulatedArrayFragment currArrayFragment = list.Tail; + + while (currArrayFragment != null) + { + for (int i = currArrayFragment.Length - 1; i >= 0; i--) + { + // 1a. publish the indended callback, to ensure ctr.Dipose can tell if a wait is necessary. + // 1b. transition to the target syncContext and continue there.. + // On the target SyncContext. + // 2. actually remove the callback + // 3. execute the callback + // re:#2 we do the remove on the syncCtx so that we can be sure we have control of the syncCtx before + // grabbing the callback. This prevents a deadlock if ctr.Dispose() might run on the syncCtx too. + m_executingCallback = currArrayFragment[i]; + if (m_executingCallback != null) + { + //Transition to the target sync context (if necessary), and continue our work there. + CancellationCallbackCoreWorkArguments args = new CancellationCallbackCoreWorkArguments(currArrayFragment, i); + + // marshal exceptions: either aggregate or perform an immediate rethrow + // We assume that syncCtx.Send() has forwarded on user exceptions when appropriate. + try + { + if (m_executingCallback.TargetSyncContext != null) + { +#pragma warning disable 0618 // This API isn't available in Metro, but we never run in metro. + m_executingCallback.TargetSyncContext.Send(CancellationCallbackCoreWork_OnSyncContext, args); +#pragma warning restore 0618 + // CancellationCallbackCoreWork_OnSyncContext may have altered ThreadIDExecutingCallbacks, so reset it. + ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; + } + else + { + CancellationCallbackCoreWork_OnSyncContext(args); + } + } + catch(Exception ex) + { + if (throwOnFirstException) + throw; + + // Otherwise, log it and proceed. + if(exceptionList == null) + exceptionList = new List(); + exceptionList.Add(ex); + } + } + } + + currArrayFragment = currArrayFragment.Prev; + } + } + } + } + finally + { + m_state = NOTIFYINGCOMPLETE; + m_executingCallback = null; + Thread.MemoryBarrier(); // for safety, prevent reorderings crossing this point and seeing inconsistent state. + } + + if (exceptionList != null) + { + Contract.Assert(exceptionList.Count > 0, "Expected exception count > 0"); + throw new AggregateException(exceptionList); + } + } + + // The main callback work that executes on the target synchronization context + private void CancellationCallbackCoreWork_OnSyncContext(object obj) + { + CancellationCallbackCoreWorkArguments args = (CancellationCallbackCoreWorkArguments) obj; + + // now remove the intended callback..and ensure that it worked. + // otherwise the callback has disappeared in the interim and we can immediately return. + CancellationCallbackInfo callback = args.m_currArrayFragment.SafeAtomicRemove(args.m_currArrayIndex, m_executingCallback); + if (callback == m_executingCallback) + { + if (callback.TargetSyncContext != null) + { + // we are running via a custom sync context, so update the executing threadID + callback.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; + } + callback.ExecuteCallback(); + } + } + + + /// + /// Creates a CancellationTokenSource that will be in the canceled state + /// when any of the source tokens are in the canceled state. + /// + /// The first CancellationToken to observe. + /// The second CancellationToken to observe. + /// A CancellationTokenSource that is linked + /// to the source tokens. + /// A CancellationTokenSource associated with + /// one of the source tokens has been disposed. + public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) + { + CancellationTokenSource linkedTokenSource = new CancellationTokenSource(); + if( token1.CanBeCanceled ) + { + linkedTokenSource.m_linkingRegistrations = new List(); + linkedTokenSource.m_linkingRegistrations.Add(token1.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, linkedTokenSource)); + } + + if( token2.CanBeCanceled ) + { + if( linkedTokenSource.m_linkingRegistrations == null ) + { + linkedTokenSource.m_linkingRegistrations = new List(); + } + linkedTokenSource.m_linkingRegistrations.Add(token2.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, linkedTokenSource)); + } + + return linkedTokenSource; + } + + /// + /// Creates a CancellationTokenSource that will be in the canceled state + /// when any of the source tokens are in the canceled state. + /// + /// The CancellationToken instances to observe. + /// A CancellationTokenSource that is linked + /// to the source tokens. + /// is null. + /// A CancellationTokenSource associated with + /// one of the source tokens has been disposed. + public static CancellationTokenSource CreateLinkedTokenSource(params CancellationToken[] tokens) + { + if (tokens == null) + throw new ArgumentNullException("tokens"); + + if (tokens.Length == 0) + throw new ArgumentException(Strings.CancellationToken_CreateLinkedToken_TokensIsEmpty, "tokens"); + + // a defensive copy is not required as the array has value-items that have only a single IntPtr field, + // hence each item cannot be null itself, and reads of the payloads cannot be torn. + Contract.EndContractBlock(); + + CancellationTokenSource linkedTokenSource = new CancellationTokenSource(); + linkedTokenSource.m_linkingRegistrations = new List(); + + for (int i = 0; i < tokens.Length; i++) + { + if (tokens[i].CanBeCanceled) + { + linkedTokenSource.m_linkingRegistrations.Add(tokens[i].InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, linkedTokenSource)); + } + } + + return linkedTokenSource; + } + + + // Wait for a single callback to complete (or, more specifically, to not be running). + // It is ok to call this method if the callback has already finished. + // Calling this method before the target callback has been selected for execution would be an error. + internal void WaitForCallbackToComplete(CancellationCallbackInfo callbackInfo) + { + SpinWait sw = new SpinWait(); + while (ExecutingCallback == callbackInfo) + { + sw.SpinOnce(); //spin as we assume callback execution is fast and that this situation is rare. + } + } + } + + // ---------------------------------------------------------- + // -- CancellationCallbackCoreWorkArguments -- + // ---------------------------------------------------------- + // Helper struct for passing data to the target sync context + internal struct CancellationCallbackCoreWorkArguments + { + internal SparselyPopulatedArrayFragment m_currArrayFragment; + internal int m_currArrayIndex; + + public CancellationCallbackCoreWorkArguments(SparselyPopulatedArrayFragment currArrayFragment, int currArrayIndex) + { + m_currArrayFragment = currArrayFragment; + m_currArrayIndex = currArrayIndex; + } + } + + // ---------------------------------------------------------- + // -- CancellationCallbackInfo -- + // ---------------------------------------------------------- + + /// + /// A helper class for collating the various bits of information required to execute + /// cancellation callbacks. + /// + internal class CancellationCallbackInfo + { + internal readonly Action Callback; + internal readonly object StateForCallback; + internal readonly SynchronizationContext TargetSyncContext; + internal readonly CancellationTokenSource CancellationTokenSource; + + internal CancellationCallbackInfo( + Action callback, object stateForCallback, SynchronizationContext targetSyncContext, + CancellationTokenSource cancellationTokenSource) + { + Callback = callback; + StateForCallback = stateForCallback; + TargetSyncContext = targetSyncContext; + CancellationTokenSource = cancellationTokenSource; + } + + /// + /// InternalExecuteCallbackSynchronously_GeneralPath + /// This will be called on the target synchronization context, however, we still need to restore the required execution context + /// + internal void ExecuteCallback() + { + //otherwise run directly + ExecutionContextCallback(this); + } + + // the worker method to actually run the callback + // The signature is such that it can be used as a 'ContextCallback' + private static void ExecutionContextCallback(object obj) + { + CancellationCallbackInfo callbackInfo = obj as CancellationCallbackInfo; + Contract.Assert(callbackInfo != null); + callbackInfo.Callback(callbackInfo.StateForCallback); + } + } + + + // ---------------------------------------------------------- + // -- SparselyPopulatedArray -- + // ---------------------------------------------------------- + + /// + /// A sparsely populated array. Elements can be sparse and some null, but this allows for + /// lock-free additions and growth, and also for constant time removal (by nulling out). + /// + /// The kind of elements contained within. + internal class SparselyPopulatedArray where T : class + { + private readonly SparselyPopulatedArrayFragment m_head; + private volatile SparselyPopulatedArrayFragment m_tail; + + /// + /// Allocates a new array with the given initial size. + /// + /// How many array slots to pre-allocate. + internal SparselyPopulatedArray(int initialSize) + { + m_head = m_tail = new SparselyPopulatedArrayFragment(initialSize); + } + +#if DEBUG + // Used in DEBUG mode by CancellationTokenSource.CallbackCount + /// + /// The head of the doubly linked list. + /// + internal SparselyPopulatedArrayFragment Head + { + get { return m_head; } + } +#endif + + /// + /// The tail of the doubly linked list. + /// + internal SparselyPopulatedArrayFragment Tail + { + get { return m_tail; } + } + + /// + /// Adds an element in the first available slot, beginning the search from the tail-to-head. + /// If no slots are available, the array is grown. The method doesn't return until successful. + /// + /// The element to add. + /// Information about where the add happened, to enable O(1) deregistration. + internal SparselyPopulatedArrayAddInfo Add(T element) + { + while (true) + { + // Get the tail, and ensure it's up to date. + SparselyPopulatedArrayFragment tail = m_tail; + while (tail.m_next != null) + m_tail = (tail = tail.m_next); + + // Search for a free index, starting from the tail. + SparselyPopulatedArrayFragment curr = tail; + while (curr != null) + { + const int RE_SEARCH_THRESHOLD = -10; // Every 10 skips, force a search. + if (curr.m_freeCount < 1) + --curr.m_freeCount; + + if (curr.m_freeCount > 0 || curr.m_freeCount < RE_SEARCH_THRESHOLD) + { + int c = curr.Length; + + // We'll compute a start offset based on how many free slots we think there + // are. This optimizes for ordinary the LIFO deregistration pattern, and is + // far from perfect due to the non-threadsafe ++ and -- of the free counter. + int start = ((c - curr.m_freeCount) % c); + if (start < 0) + { + start = 0; + curr.m_freeCount--; // Too many free elements; fix up. + } + Contract.Assert(start >= 0 && start < c, "start is outside of bounds"); + + // Now walk the array until we find a free slot (or reach the end). + for (int i = 0; i < c; i++) + { + // If the slot is null, try to CAS our element into it. + int tryIndex = (start + i) % c; + Contract.Assert(tryIndex >= 0 && tryIndex < curr.m_elements.Length, "tryIndex is outside of bounds"); + + if (curr.m_elements[tryIndex] == null && Interlocked.CompareExchange(ref curr.m_elements[tryIndex], element, null) == null) + { + // We adjust the free count by --. Note: if this drops to 0, we will skip + // the fragment on the next search iteration. Searching threads will -- the + // count and force a search every so often, just in case fragmentation occurs. + int newFreeCount = curr.m_freeCount - 1; + curr.m_freeCount = newFreeCount > 0 ? newFreeCount : 0; + return new SparselyPopulatedArrayAddInfo(curr, tryIndex); + } + } + } + + curr = curr.m_prev; + } + + // If we got here, we need to add a new chunk to the tail and try again. + SparselyPopulatedArrayFragment newTail = new SparselyPopulatedArrayFragment( + tail.m_elements.Length == 4096 ? 4096 : tail.m_elements.Length * 2, tail); + if (Interlocked.CompareExchange(ref tail.m_next, newTail, null) == null) + { + m_tail = newTail; + } + } + } + } + + /// + /// A struct to hold a link to the exact spot in an array an element was inserted, enabling + /// constant time removal later on. + /// + internal struct SparselyPopulatedArrayAddInfo where T : class + { + private SparselyPopulatedArrayFragment m_source; + private int m_index; + + internal SparselyPopulatedArrayAddInfo(SparselyPopulatedArrayFragment source, int index) + { + Contract.Assert(source != null); + Contract.Assert(index >= 0 && index < source.Length); + m_source = source; + m_index = index; + } + + internal SparselyPopulatedArrayFragment Source + { + get { return m_source; } + } + + internal int Index + { + get { return m_index; } + } + } + + /// + /// A fragment of a sparsely populated array, doubly linked. + /// + /// The kind of elements contained within. + internal class SparselyPopulatedArrayFragment where T : class + { + internal readonly T[] m_elements; // The contents, sparsely populated (with nulls). + internal volatile int m_freeCount; // A hint of the number of free elements. + internal volatile SparselyPopulatedArrayFragment m_next; // The next fragment in the chain. + internal volatile SparselyPopulatedArrayFragment m_prev; // The previous fragment in the chain. + + internal SparselyPopulatedArrayFragment(int size) : this(size, null) + { + } + + internal SparselyPopulatedArrayFragment(int size, SparselyPopulatedArrayFragment prev) + { + m_elements = new T[size]; + m_freeCount = size; + m_prev = prev; + } + + internal T this[int index] + { + get { return m_elements[index]; } + } + + internal int Length + { + get { return m_elements.Length; } + } + +#if DEBUG + // Used in DEBUG mode by CancellationTokenSource.CallbackCount + internal SparselyPopulatedArrayFragment Next + { + get { return m_next; } + } +#endif + internal SparselyPopulatedArrayFragment Prev + { + get { return m_prev; } + } + + // only removes the item at the specified index if it is still the expected one. + // Returns the prevailing value. + // The remove occured successfully if the return value == expected element + // otherwise the remove did not occur. + internal T SafeAtomicRemove(int index, T expectedElement) + { + T prevailingValue = Interlocked.CompareExchange(ref m_elements[index], null, expectedElement); + if (prevailingValue != null) + ++m_freeCount; + return prevailingValue; + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/LazyInitializer.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/LazyInitializer.cs new file mode 100644 index 000000000..50eea98ee --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/LazyInitializer.cs @@ -0,0 +1,240 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// LazyInitializer.cs +// +// emadali +// +// a set of lightweight static helpers for lazy initialization. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +using System.Diagnostics.Contracts; +namespace System.Threading +{ + + /// + /// Provides lazy initialization routines. + /// + /// + /// These routines avoid needing to allocate a dedicated, lazy-initialization instance, instead using + /// references to ensure targets have been initialized as they are accessed. + /// + + internal static class LazyInitializer + { + // The following field is used wherever we need to insert a volatile read. + private static volatile object s_barrier = null; + + /// + /// Initializes a target reference type with the type's default constructor if the target has not + /// already been initialized. + /// + /// The refence type of the reference to be initialized. + /// A reference of type to initialize if it has not + /// already been initialized. + /// The initialized reference of type . + /// Type does not have a default + /// constructor. + /// + /// Permissions to access the constructor of type were missing. + /// + /// + /// + /// This method may only be used on reference types. To ensure initialization of value + /// types, see other overloads of EnsureInitialized. + /// + /// + /// This method may be used concurrently by multiple threads to initialize . + /// In the event that multiple threads access this method concurrently, multiple instances of + /// may be created, but only one will be stored into . In such an occurrence, this method will not dispose of the + /// objects that were not stored. If such objects must be disposed, it is up to the caller to determine + /// if an object was not used and to then dispose of the object appropriately. + /// + /// + public static T EnsureInitialized(ref T target) where T : class + { + // Fast path. + if (target != null) + { + object barrierGarbage = s_barrier; // Insert a volatile load barrier. Needed on IA64. + return target; + } + + return EnsureInitializedCore(ref target, LazyHelpers.s_activatorFactorySelector); + } + + /// + /// Initializes a target reference type using the specified function if it has not already been + /// initialized. + /// + /// The reference type of the reference to be initialized. + /// The reference of type to initialize if it has not + /// already been initialized. + /// The invoked to initialize the + /// reference. + /// The initialized reference of type . + /// Type does not have a + /// default constructor. + /// returned + /// null. + /// + /// + /// This method may only be used on reference types, and may + /// not return a null reference (Nothing in Visual Basic). To ensure initialization of value types or + /// to allow null reference types, see other overloads of EnsureInitialized. + /// + /// + /// This method may be used concurrently by multiple threads to initialize . + /// In the event that multiple threads access this method concurrently, multiple instances of + /// may be created, but only one will be stored into . In such an occurrence, this method will not dispose of the + /// objects that were not stored. If such objects must be disposed, it is up to the caller to determine + /// if an object was not used and to then dispose of the object appropriately. + /// + /// + public static T EnsureInitialized(ref T target, Func valueFactory) where T : class + { + // Fast path. + if (target != null) + { + object barrierGarbage = s_barrier; // Insert a volatile load barrier. Needed on IA64. + return target; + } + + return EnsureInitializedCore(ref target, valueFactory); + } + + /// + /// Initialize the target using the given delegate (slow path). + /// + /// The reference type of the reference to be initialized. + /// The variable that need to be initialized + /// The delegate that will be executed to initialize the target + /// The initialized variable + private static T EnsureInitializedCore(ref T target, Func valueFactory) where T : class + { + T value = valueFactory(); + if (value == null) + { + throw new InvalidOperationException(Strings.Lazy_StaticInit_InvalidOperation); + } + + Interlocked.CompareExchange(ref target, value, null); + Contract.Assert(target != null); + return target; + } + + + /// + /// Initializes a target reference or value type with its default constructor if it has not already + /// been initialized. + /// + /// The type of the reference to be initialized. + /// A reference or value of type to initialize if it + /// has not already been initialized. + /// A reference to a boolean that determines whether the target has already + /// been initialized. + /// A reference to an object used as the mutually exclusive lock for initializing + /// . + /// The initialized value of type . + public static T EnsureInitialized(ref T target, ref bool initialized, ref object syncLock) + { + // Fast path. + if (initialized) + { + object barrierGarbage = s_barrier; // Insert a volatile load barrier. Needed on IA64. + return target; + } + + return EnsureInitializedCore(ref target, ref initialized, ref syncLock, LazyHelpers.s_activatorFactorySelector); + } + + /// + /// Initializes a target reference or value type with a specified function if it has not already been + /// initialized. + /// + /// The type of the reference to be initialized. + /// A reference or value of type to initialize if it + /// has not already been initialized. + /// A reference to a boolean that determines whether the target has already + /// been initialized. + /// A reference to an object used as the mutually exclusive lock for initializing + /// . + /// The invoked to initialize the + /// reference or value. + /// The initialized value of type . + public static T EnsureInitialized(ref T target, ref bool initialized, ref object syncLock, Func valueFactory) + { + // Fast path. + if (initialized) + { + object barrierGarbage = s_barrier; // Insert a volatile load barrier. Needed on IA64. + return target; + } + + return EnsureInitializedCore(ref target, ref initialized, ref syncLock, valueFactory); + } + + /// + /// Ensure the target is initialized and return the value (slow path). This overload permits nulls + /// and also works for value type targets. Uses the supplied function to create the value. + /// + /// The type of target. + /// A reference to the target to be initialized. + /// A reference to a location tracking whether the target has been initialized. + /// A reference to a location containing a mutual exclusive lock. + /// + /// The to invoke in order to produce the lazily-initialized value. + /// + /// The initialized object. + private static T EnsureInitializedCore(ref T target, ref bool initialized, ref object syncLock, Func valueFactory) + { + // Lazily initialize the lock if necessary. + object slock = syncLock; + if (slock == null) + { + object newLock = new object(); + slock = Interlocked.CompareExchange(ref syncLock, newLock, null); + if (slock == null) + { + slock = newLock; + } + } + + // Now double check that initialization is still required. + lock (slock) + { + if (!initialized) + { + target = valueFactory(); + initialized = true; + } + } + + return target; + } + + // Caches the activation selector function to avoid delegate allocations. + private static class LazyHelpers + { + internal static Func s_activatorFactorySelector = new Func(ActivatorFactorySelector); + + private static T ActivatorFactorySelector() + { + try + { + return (T)Activator.CreateInstance(typeof(T)); + } + catch (MissingMemberException) + { + throw new MissingMemberException(Strings.Lazy_CreateValue_NoParameterlessCtorForT); + } + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ManualResetEventSlim.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ManualResetEventSlim.cs new file mode 100644 index 000000000..fce25b8f1 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ManualResetEventSlim.cs @@ -0,0 +1,859 @@ +#pragma warning disable 0420 +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// SlimManualResetEvent.cs +// +// emadali +// +// An manual-reset event that mixes a little spinning with a true Win32 event. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Diagnostics.Contracts; + +namespace System.Threading +{ + + // ManualResetEventSlim wraps a manual-reset event internally with a little bit of + // spinning. When an event will be set imminently, it is often advantageous to avoid + // a 4k+ cycle context switch in favor of briefly spinning. Therefore we layer on to + // a brief amount of spinning that should, on the average, make using the slim event + // cheaper than using Win32 events directly. This can be reset manually, much like + // a Win32 manual-reset would be. + // + // Notes: + // We lazily allocate the Win32 event internally. Therefore, the caller should + // always call Dispose to clean it up, just in case. This API is a no-op of the + // event wasn't allocated, but if it was, ensures that the event goes away + // eagerly, instead of waiting for finalization. + + /// + /// Provides a slimmed down version of . + /// + /// + /// All public and protected members of are thread-safe and may be used + /// concurrently from multiple threads, with the exception of Dispose, which + /// must only be used when all other operations on the have + /// completed, and Reset, which should only be used when no other threads are + /// accessing the event. + /// + [DebuggerDisplay("Set = {IsSet}")] + internal class ManualResetEventSlim : IDisposable + { + // These are the default spin counts we use on single-proc and MP machines. + private const int DEFAULT_SPIN_SP = 1; + private const int DEFAULT_SPIN_MP = SpinWait.YIELD_THRESHOLD; + + private object m_lock; + // A lock used for waiting and pulsing. Lazily initialized via EnsureLockObjectCreated() + // This would normally be tagged 'volatile', but we can avoid this as it is only used nearby + // access to Waiters which internally uses the volatile m_combinedState. See specific + // comments in Set(bool duringCancellation) + + private ManualResetEvent m_eventObj; // A true Win32 event used for waiting. + + // -- State -- // + //For a packed word a uint would seem better, but Interlocked.* doesn't support them as uint isn't CLS-compliant. + private volatile int m_combinedState; //ie a UInt32. Used for the state items listed below. + + //1-bit for signalled state + private const int SignalledState_BitMask = unchecked((int)0x80000000);//1000 0000 0000 0000 0000 0000 0000 0000 + private const int SignalledState_ShiftCount = 31; + + //1-bit for disposed state + private const int Dispose_BitMask = unchecked((int)0x40000000);//0100 0000 0000 0000 0000 0000 0000 0000 + + //11-bits for m_spinCount + private const int SpinCountState_BitMask = unchecked((int)0x3FF80000); //0011 1111 1111 1000 0000 0000 0000 0000 + private const int SpinCountState_ShiftCount = 19; + private const int SpinCountState_MaxValue = (1 << 11) - 1; //2047 + + //19-bits for m_waiters. This allows support of 512K threads waiting which should be ample + private const int NumWaitersState_BitMask = unchecked((int)0x0007FFFF); // 0000 0000 0000 0111 1111 1111 1111 1111 + private const int NumWaitersState_ShiftCount = 0; + private const int NumWaitersState_MaxValue = (1 << 19) - 1; //512K-1 + // ----------- // + +#if DEBUG + private static int s_nextId; // The next id that will be given out. + private int m_id = Interlocked.Increment(ref s_nextId); // A unique id for debugging purposes only. + private long m_lastSetTime; + private long m_lastResetTime; +#endif + + /// + /// Gets the underlying object for this . + /// + /// The underlying event object fore this . + /// + /// Accessing this property forces initialization of an underlying event object if one hasn't + /// already been created. To simply wait on this , + /// the public Wait methods should be preferred. + /// + public WaitHandle WaitHandle + { + + get + { + ThrowIfDisposed(); + if (m_eventObj == null) + { + // Lazily initialize the event object if needed. + LazyInitializeEvent(); + } + + return m_eventObj; + } + } + + /// + /// Gets whether the event is set. + /// + /// true if the event has is set; otherwise, false. + public bool IsSet + { + get + { + return 0 != ExtractStatePortion(m_combinedState, SignalledState_BitMask); + } + + private set + { + UpdateStateAtomically(((value) ? 1 : 0) << SignalledState_ShiftCount, SignalledState_BitMask); + } + } + + /// + /// Gets the number of spin waits that will be occur before falling back to a true wait. + /// + public int SpinCount + { + get + { + return ExtractStatePortionAndShiftRight(m_combinedState, SpinCountState_BitMask, SpinCountState_ShiftCount); + } + + private set + { + Contract.Assert(value >= 0, "SpinCount is a restricted-width integer. The value supplied is outside the legal range."); + Contract.Assert(value <= SpinCountState_MaxValue, "SpinCount is a restricted-width integer. The value supplied is outside the legal range."); + // Don't worry about thread safety because it's set one time from the constructor + m_combinedState = (m_combinedState & ~SpinCountState_BitMask) | (value << SpinCountState_ShiftCount); + } + } + + /// + /// How many threads are waiting. + /// + private int Waiters + { + get + { + return ExtractStatePortionAndShiftRight(m_combinedState, NumWaitersState_BitMask, NumWaitersState_ShiftCount); + } + + set + { + //setting to <0 would indicate an internal flaw, hence Assert is appropriate. + Contract.Assert(value >= 0, "NumWaiters should never be less than zero. This indicates an internal error."); + + // it is possible for the max number of waiters to be exceeded via user-code, hence we use a real exception here. + if (value >= NumWaitersState_MaxValue) + throw new InvalidOperationException(String.Format(Strings.ManualResetEventSlim_ctor_TooManyWaiters,NumWaitersState_MaxValue)); + + UpdateStateAtomically(value << NumWaitersState_ShiftCount, NumWaitersState_BitMask); + } + + } + + //----------------------------------------------------------------------------------- + // Constructs a new event, optionally specifying the initial state and spin count. + // The defaults are that the event is unsignaled and some reasonable default spin. + // + + /// + /// Initializes a new instance of the + /// class with an initial state of nonsignaled. + /// + public ManualResetEventSlim() + : this(false) + { + + } + + /// + /// Initializes a new instance of the + /// class with a Boolen value indicating whether to set the intial state to signaled. + /// + /// true to set the initial state signaled; false to set the initial state + /// to nonsignaled. + public ManualResetEventSlim(bool initialState) + { + // Specify the defualt spin count, and use default spin if we're + // on a multi-processor machine. Otherwise, we won't. + Initialize(initialState, DEFAULT_SPIN_MP); + } + + /// + /// Initializes a new instance of the + /// class with a Boolen value indicating whether to set the intial state to signaled and a specified + /// spin count. + /// + /// true to set the initial state to signaled; false to set the initial state + /// to nonsignaled. + /// The number of spin waits that will occur before falling back to a true + /// wait. + /// is less than + /// 0 or greater than the maximum allowed value. + public ManualResetEventSlim(bool initialState, int spinCount) + { + if (spinCount < 0) + { + throw new ArgumentOutOfRangeException("spinCount"); + } + + if (spinCount > SpinCountState_MaxValue) + { + throw new ArgumentOutOfRangeException( + "spinCount", + String.Format(Strings.ManualResetEventSlim_ctor_SpinCountOutOfRange,SpinCountState_MaxValue)); + } + + // We will suppress default spin because the user specified a count. + Initialize(initialState, spinCount); + } + + /// + /// Initializes the internal state of the event. + /// + /// Whether the event is set initially or not. + /// The spin count that decides when the event will block. + private void Initialize(bool initialState, int spinCount) + { + IsSet = initialState; + + //the spinCount argument has been validated by the ctors. + //but we now sanity check our predefined constants. + Contract.Assert(DEFAULT_SPIN_SP >= 0, "Internal error - DEFAULT_SPIN_SP is outside the legal range."); + Contract.Assert(DEFAULT_SPIN_SP <= SpinCountState_MaxValue, "Internal error - DEFAULT_SPIN_SP is outside the legal range."); + + SpinCount = PlatformHelper.IsSingleProcessor ? DEFAULT_SPIN_SP : spinCount; + + } + + /// + /// Helper to ensure the lock object is created before first use. + /// + private void EnsureLockObjectCreated() + { + Contract.Ensures(m_lock != null); + + if (m_lock != null) + return; + + object newObj = new object(); + Interlocked.CompareExchange(ref m_lock, newObj, null); // failure is benign.. someone else won the race. + } + + /// + /// This method lazily initializes the event object. It uses CAS to guarantee that + /// many threads racing to call this at once don't result in more than one event + /// being stored and used. The event will be signaled or unsignaled depending on + /// the state of the thin-event itself, with synchronization taken into account. + /// + /// True if a new event was created and stored, false otherwise. + private bool LazyInitializeEvent() + { + bool preInitializeIsSet = IsSet; + ManualResetEvent newEventObj = new ManualResetEvent(preInitializeIsSet); + + // We have to CAS this in case we are racing with another thread. We must + // guarantee only one event is actually stored in this field. + if (Interlocked.CompareExchange(ref m_eventObj, newEventObj, null) != null) + { + // We raced with someone else and lost. Destroy the garbage event. + newEventObj.Dispose(); + + return false; + } + else + { + + // Now that the event is published, verify that the state hasn't changed since + // we snapped the preInitializeState. Another thread could have done that + // between our initial observation above and here. The barrier incurred from + // the CAS above (in addition to m_state being volatile) prevents this read + // from moving earlier and being collapsed with our original one. + bool currentIsSet = IsSet; + if (currentIsSet != preInitializeIsSet) + { + Contract.Assert(currentIsSet, + "The only safe concurrent transition is from unset->set: detected set->unset."); + + // We saw it as unsignaled, but it has since become set. + lock (newEventObj) + { + // If our event hasn't already been disposed of, we must set it. + if (m_eventObj == newEventObj) + { + newEventObj.Set(); + } + } + } + + return true; + } + } + + /// + /// Sets the state of the event to signaled, which allows one or more threads waiting on the event to + /// proceed. + /// + public void Set() + { + Set(false); + } + + /// + /// Private helper to actually perform the Set. + /// + /// Indicates whether we are calling Set() during cancellation. + /// The object has been canceled. + private void Set(bool duringCancellation) + { + // We need to ensure that IsSet=true does not get reordered past the read of m_eventObj + // This would be a legal movement according to the .NET memory model. + // The code is safe as IsSet involves an Interlocked.CompareExchange which provides a full memory barrier. + IsSet = true; + + // If there are waiting threads, we need to pulse them. + if (Waiters > 0) + { + + //m_lock is not volatile, but the backing store of Waiters is volatile. + //Hence READ(Waiters) was a load-acquire. READ(m_lock) will not reorder above. + //and there is no risk of loading a null m_lock and then observing Waiters > 0. + //Also, the writes to m_lock and Waiters in Wait(int millisecondsTimeout, CancellationToken cancellationToken) + //cannot reorder as all writes are Store-Release in MM + + Contract.Assert(m_lock != null); //if waiters>0, then m_lock has already been created. + lock (m_lock) + { + + Monitor.PulseAll(m_lock); + } + } + + ManualResetEvent eventObj = m_eventObj; + + //Design-decision: do not set the event if we are in cancellation -> better to deadlock than to wake up waiters incorrectly + //It would be preferable to wake up the event and have it throw OCE. This requires MRE to implement cancellation logic + + if (eventObj != null && !duringCancellation) + { + // We must surround this call to Set in a lock. The reason is fairly subtle. + // Sometimes a thread will issue a Wait and wake up after we have set m_state, + // but before we have gotten around to setting m_eventObj (just below). That's + // because Wait first checks m_state and will only access the event if absolutely + // necessary. However, the coding pattern { event.Wait(); event.Dispose() } is + // quite common, and we must support it. If the waiter woke up and disposed of + // the event object before the setter has finished, however, we would try to set a + // now-disposed Win32 event. Crash! To deal with this race, we use a lock to + // protect access to the event object when setting and disposing of it. We also + // double-check that the event has not become null in the meantime when in the lock. + + lock (eventObj) + { + if (m_eventObj != null) + { + // If somebody is waiting, we must set the event. + m_eventObj.Set(); + } + } + } + +#if DEBUG + m_lastSetTime = DateTime.Now.Ticks; +#endif + } + + /// + /// Sets the state of the event to nonsignaled, which causes threads to block. + /// + /// + /// Unlike most of the members of , is not + /// thread-safe and may not be used concurrently with other members of this instance. + /// + public void Reset() + { + ThrowIfDisposed(); + // If there's an event, reset it. + if (m_eventObj != null) + { + m_eventObj.Reset(); + } + + // There is a race here. If another thread Sets the event, we will get into a state + // where m_state will be unsignaled, yet the Win32 event object will have been signaled. + // This could cause waiting threads to wake up even though the event is in an + // unsignaled state. This is fine -- those that are calling Reset concurrently are + // responsible for doing "the right thing" -- e.g. rechecking the condition and + // resetting the event manually. + + // And finally set our state back to unsignaled. + IsSet = false; + +#if DEBUG + m_lastResetTime = DateTime.Now.Ticks; +#endif + } + + /// + /// Blocks the current thread until the current is set. + /// + /// + /// The maximum number of waiters has been exceeded. + /// + /// + /// The caller of this method blocks indefinitely until the current instance is set. The caller will + /// return immediately if the event is currently in a set state. + /// + public void Wait() + { + Wait(Timeout.Infinite, new CancellationToken()); + } + + /// + /// Blocks the current thread until the current receives a signal, + /// while observing a . + /// + /// The to + /// observe. + /// + /// The maximum number of waiters has been exceeded. + /// + /// was + /// canceled. + /// + /// The caller of this method blocks indefinitely until the current instance is set. The caller will + /// return immediately if the event is currently in a set state. + /// + public void Wait(CancellationToken cancellationToken) + { + Wait(Timeout.Infinite, cancellationToken); + } + + /// + /// Blocks the current thread until the current is set, using a + /// to measure the time interval. + /// + /// A that represents the number of milliseconds + /// to wait, or a that represents -1 milliseconds to wait indefinitely. + /// + /// true if the was set; otherwise, + /// false. + /// is a negative + /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater + /// than . + /// + /// The maximum number of waiters has been exceeded. + /// + public bool Wait(TimeSpan timeout) + { + long totalMilliseconds = (long)timeout.TotalMilliseconds; + if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue) + { + throw new ArgumentOutOfRangeException("timeout"); + } + + return Wait((int)totalMilliseconds, new CancellationToken()); + } + + /// + /// Blocks the current thread until the current is set, using a + /// to measure the time interval, while observing a . + /// + /// A that represents the number of milliseconds + /// to wait, or a that represents -1 milliseconds to wait indefinitely. + /// + /// The to + /// observe. + /// true if the was set; otherwise, + /// false. + /// is a negative + /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater + /// than . + /// was canceled. + /// + /// The maximum number of waiters has been exceeded. + /// + public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) + { + long totalMilliseconds = (long)timeout.TotalMilliseconds; + if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue) + { + throw new ArgumentOutOfRangeException("timeout"); + } + + return Wait((int)totalMilliseconds, cancellationToken); + } + + /// + /// Blocks the current thread until the current is set, using a + /// 32-bit signed integer to measure the time interval. + /// + /// The number of milliseconds to wait, or (-1) to wait indefinitely. + /// true if the was set; otherwise, + /// false. + /// is a + /// negative number other than -1, which represents an infinite time-out. + /// + /// The maximum number of waiters has been exceeded. + /// + public bool Wait(int millisecondsTimeout) + { + return Wait(millisecondsTimeout, new CancellationToken()); + } + + /// + /// Blocks the current thread until the current is set, using a + /// 32-bit signed integer to measure the time interval, while observing a . + /// + /// The number of milliseconds to wait, or (-1) to wait indefinitely. + /// The to + /// observe. + /// true if the was set; otherwise, + /// false. + /// is a + /// negative number other than -1, which represents an infinite time-out. + /// + /// The maximum number of waiters has been exceeded. + /// + /// was canceled. + public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) + { + ThrowIfDisposed(); + cancellationToken.ThrowIfCancellationRequested(); // an early convenience check + + if (millisecondsTimeout < -1) + { + throw new ArgumentOutOfRangeException("millisecondsTimeout"); + } + + if (!IsSet) + { + if (millisecondsTimeout == 0) + { + // For 0-timeouts, we just return immediately. + return false; + } + + + // We spin briefly before falling back to allocating and/or waiting on a true event. + long startTimeTicks = 0; + bool bNeedTimeoutAdjustment = false; + int realMillisecondsTimeout = millisecondsTimeout; //this will be adjusted if necessary. + + if (millisecondsTimeout != Timeout.Infinite) + { + // We will account for time spent spinning, so that we can decrement it from our + // timeout. In most cases the time spent in this section will be negligible. But + // we can't discount the possibility of our thread being switched out for a lengthy + // period of time. The timeout adjustments only take effect when and if we actually + // decide to block in the kernel below. + + startTimeTicks = DateTime.UtcNow.Ticks; + bNeedTimeoutAdjustment = true; + } + + //spin + int HOW_MANY_SPIN_BEFORE_YIELD = 10; + int HOW_MANY_YIELD_EVERY_SLEEP_0 = 5; + int HOW_MANY_YIELD_EVERY_SLEEP_1 = 20; + + for (int i = 0; i < SpinCount; i++) + { + if (IsSet) + { + return true; + } + + else if (i < HOW_MANY_SPIN_BEFORE_YIELD) + { + if (i == HOW_MANY_SPIN_BEFORE_YIELD / 2) + { +#if PFX_LEGACY_3_5 + Platform.Yield(); +#else + ThreadLightup.Current.Yield(); +#endif + } + else + { + ThreadLightup.Current.SpinWait(PlatformHelper.ProcessorCount * (4 << i)); + } + } + else if (i % HOW_MANY_YIELD_EVERY_SLEEP_1 == 0) + { + ThreadLightup.Current.Sleep(1); + } + else if (i % HOW_MANY_YIELD_EVERY_SLEEP_0 == 0) + { + ThreadLightup.Current.Sleep(0); + } + else + { +#if PFX_LEGACY_3_5 + Platform.Yield(); +#else + ThreadLightup.Current.Yield(); +#endif + } + + if (i >= 100 && i % 10 == 0) // check the cancellation token if the user passed a very large spin count + cancellationToken.ThrowIfCancellationRequested(); + } + + // Now enter the lock and wait. + EnsureLockObjectCreated(); + + // We must register and deregister the token outside of the lock, to avoid deadlocks. + using (cancellationToken.Register(s_cancellationTokenCallback, this)) + { + lock (m_lock) + { + // Loop to cope with spurious wakeups from other waits being canceled + while (!IsSet) + { + // If our token was canceled, we must throw and exit. + cancellationToken.ThrowIfCancellationRequested(); + + //update timeout (delays in wait commencement are due to spinning and/or spurious wakeups from other waits being canceled) + if (bNeedTimeoutAdjustment) + { + realMillisecondsTimeout = UpdateTimeOut(startTimeTicks, millisecondsTimeout); + if (realMillisecondsTimeout <= 0) + return false; + } + + // There is a race that Set will fail to see that there are waiters as Set does not take the lock, + // so after updating waiters, we must check IsSet again. + // Also, we must ensure there cannot be any reordering of the assignment to Waiters and the + // read from IsSet. This is guaranteed as Waiters{set;} involves an Interlocked.CompareExchange + // operation which provides a full memory barrier. + // If we see IsSet=false, then we are guaranteed that Set() will see that we are + // waiting and will pulse the monitor correctly. + + Waiters = Waiters + 1; + + if (IsSet) //This check must occur after updating Waiters. + { + Waiters--; //revert the increment. + return true; + } + + // Now finally perform the wait. + try + { + // ** the actual wait ** + if (!Monitor.Wait(m_lock, realMillisecondsTimeout)) + return false; //return immediately if the timeout has expired. + } + finally + { + // Clean up: we're done waiting. + Waiters = Waiters - 1; + } + + // Now just loop back around, and the right thing will happen. Either: + // 1. We had a spurious wake-up due to some other wait being canceled via a different cancellationToken (rewait) + // or 2. the wait was successful. (the loop will break) + + } + } + } + } // automatically disposes (and deregisters) the callback + + return true; //done. The wait was satisfied. + } + + /// + /// Releases all resources used by the current instance of . + /// + /// + /// Unlike most of the members of , is not + /// thread-safe and may not be used concurrently with other members of this instance. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// When overridden in a derived class, releases the unmanaged resources used by the + /// , and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; + /// false to release only unmanaged resources. + /// + /// Unlike most of the members of , is not + /// thread-safe and may not be used concurrently with other members of this instance. + /// + protected virtual void Dispose(bool disposing) + { + if ((m_combinedState & Dispose_BitMask) != 0) + return; // already disposed + + m_combinedState |= Dispose_BitMask; //set the dispose bit + if (disposing) + { + // We will dispose of the event object. We do this under a lock to protect + // against the race condition outlined in the Set method above. + ManualResetEvent eventObj = m_eventObj; + if (eventObj != null) + { + lock (eventObj) + { + eventObj.Dispose(); + m_eventObj = null; + } + } + } + } + + /// + /// Throw ObjectDisposedException if the MRES is disposed + /// + private void ThrowIfDisposed() + { + if ((m_combinedState & Dispose_BitMask) != 0) + throw new ObjectDisposedException(Strings.ManualResetEventSlim_Disposed); + } + + /// + /// Private helper method to wake up waiters when a cancellationToken gets canceled. + /// + private static Action s_cancellationTokenCallback = new Action(CancellationTokenCallback); + private static void CancellationTokenCallback(object obj) + { + ManualResetEventSlim mre = obj as ManualResetEventSlim; + Contract.Assert(mre != null, "Expected a ManualResetEventSlim"); + Contract.Assert(mre.m_lock != null); //the lock should have been created before this callback is registered for use. + lock (mre.m_lock) + { + Monitor.PulseAll(mre.m_lock); // awaken all waiters + } + } + + /// + /// Private helper method for updating parts of a bit-string state value. + /// Mainly called from the IsSet and Waiters properties setters + /// + /// + /// Note: the parameter types must be int as CompareExchange cannot take a Uint + /// + /// The new value + /// The mask used to set the bits + private void UpdateStateAtomically(int newBits, int updateBitsMask) + { + SpinWait sw = new SpinWait(); + + Contract.Assert((newBits | updateBitsMask) == updateBitsMask, "newBits do not fall within the updateBitsMask."); + + do + { + int oldState = m_combinedState; // cache the old value for testing in CAS + + // Procedure:(1) zero the updateBits. eg oldState = [11111111] flag= [00111000] newState = [11000111] + // then (2) map in the newBits. eg [11000111] newBits=00101000, newState=[11101111] + int newState = (oldState & ~updateBitsMask) | newBits; + + if (Interlocked.CompareExchange(ref m_combinedState, newState, oldState) == oldState) + { + return; + } + + sw.SpinOnce(); + } while (true); + } + + /// + /// Private helper method - performs Mask and shift, particular helpful to extract a field from a packed word. + /// eg ExtractStatePortionAndShiftRight(0x12345678, 0xFF000000, 24) => 0x12, ie extracting the top 8-bits as a simple integer + /// + /// ?? is there a common place to put this rather than being private to MRES? + /// + /// + /// + /// + /// + private static int ExtractStatePortionAndShiftRight(int state, int mask, int rightBitShiftCount) + { + //convert to uint before shifting so that right-shift does not replicate the sign-bit, + //then convert back to int. + return unchecked((int)(((uint)(state & mask)) >> rightBitShiftCount)); + } + + /// + /// Performs a Mask operation, but does not perform the shift. + /// This is acceptable for boolean values for which the shift is unnecessary + /// eg (val & Mask) != 0 is an appropriate way to extract a boolean rather than using + /// ((val & Mask) >> shiftAmount) == 1 + /// + /// ?? is there a common place to put this rather than being private to MRES? + /// + /// + /// + private static int ExtractStatePortion(int state, int mask) + { + return state & mask; + } + + /// + /// Helper function to measure and update the wait time + /// + /// The first time (in Ticks) observed when the wait started. + /// The orginal wait timeoutout in milliseconds. + /// The new wait time in milliseconds, -1 if the time expired, -2 if overflow in counters + /// has occurred. + private static int UpdateTimeOut(long startTimeTicks, int originalWaitMillisecondsTimeout) + { + // The function may only be called if time out is not infinite + Contract.Assert(originalWaitMillisecondsTimeout != Timeout.Infinite); + + long elapsedMilliseconds = (DateTime.UtcNow.Ticks - startTimeTicks) / TimeSpan.TicksPerMillisecond; + + // Check the elapsed milliseconds is greater than max int because this property is long + if (elapsedMilliseconds > int.MaxValue) + { + return -2; + } + + // Subtract the elapsed time from the current wait time + int currentWaitTimeout = originalWaitMillisecondsTimeout - (int)elapsedMilliseconds; + if (currentWaitTimeout < 0) + { + return -1; + } + + return currentWaitTimeout; + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/SpinWait.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/SpinWait.cs new file mode 100644 index 000000000..c7af69941 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/SpinWait.cs @@ -0,0 +1,326 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// SpinWait.cs +// +// emadali +// +// Central spin logic used across the entire code-base. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +//using System.Runtime.ConstrainedExecution; +using System.Threading; +using System.Diagnostics.Contracts; + +namespace System.Threading +{ + // SpinWait is just a little value type that encapsulates some common spinning + // logic. It ensures we always yield on single-proc machines (instead of using busy + // waits), and that we work well on HT. It encapsulates a good mixture of spinning + // and real yielding. It's a value type so that various areas of the engine can use + // one by allocating it on the stack w/out unnecessary GC allocation overhead, e.g.: + // + // void f() { + // SpinWait wait = new SpinWait(); + // while (!p) { wait.SpinOnce(); } + // ... + // } + // + // Internally it just maintains a counter that is used to decide when to yield, etc. + // + // A common usage is to spin before blocking. In those cases, the NextSpinWillYield + // property allows a user to decide to fall back to waiting once it returns true: + // + // void f() { + // SpinWait wait = new SpinWait(); + // while (!p) { + // if (wait.NextSpinWillYield) { /* block! */ } + // else { wait.SpinOnce(); } + // } + // ... + // } + + /// + /// Provides support for spin-based waiting. + /// + /// + /// + /// encapsulates common spinning logic. On single-processor machines, yields are + /// always used instead of busy waits, and on computers with Intel™ processors employing Hyper-Threading™ + /// technology, it helps to prevent hardware thread starvation. SpinWait encapsulates a good mixture of + /// spinning and true yielding. + /// + /// + /// is a value type, which means that low-level code can utilize SpinWait without + /// fear of unnecessary allocation overheads. SpinWait is not generally useful for ordinary applications. + /// In most cases, you should use the synchronization classes provided by the .NET Framework, such as + /// . For most purposes where spin waiting is required, however, + /// the type should be preferred over the System.Threading.Thread.SpinWait method. + /// + /// + /// While SpinWait is designed to be used in concurrent applications, it is not designed to be + /// used from multiple threads concurrently. SpinWait's members are not thread-safe. If multiple + /// threads must spin, each should use its own instance of SpinWait. + /// + /// + + internal struct SpinWait + { + + // These constants determine the frequency of yields versus spinning. The + // numbers may seem fairly arbitrary, but were derived with at least some + // thought in the design document. I fully expect they will need to change + // over time as we gain more experience with performance. + internal const int YIELD_THRESHOLD = 10; // When to switch over to a true yield. + internal const int SLEEP_0_EVERY_HOW_MANY_TIMES = 5; // After how many yields should we Sleep(0)? + internal const int SLEEP_1_EVERY_HOW_MANY_TIMES = 20; // After how many yields should we Sleep(1)? + + // The number of times we've spun already. + private int m_count; + + /// + /// Gets the number of times has been called on this instance. + /// + public int Count + { + get { return m_count; } + } + + /// + /// Gets whether the next call to will yield the processor, triggering a + /// forced context switch. + /// + /// Whether the next call to will yield the processor, triggering a + /// forced context switch. + /// + /// On a single-CPU machine, always yields the processor. On machines with + /// multiple CPUs, may yield after an unspecified number of calls. + /// + public bool NextSpinWillYield + { + get { return m_count > YIELD_THRESHOLD || PlatformHelper.IsSingleProcessor; } + } + + /// + /// Performs a single spin. + /// + /// + /// This is typically called in a loop, and may change in behavior based on the number of times a + /// has been called thus far on this instance. + /// + public void SpinOnce() + { + if (NextSpinWillYield) + { + // + // We must yield. + // + // We prefer to call Thread.Yield first, triggering a SwitchToThread. This + // unfortunately doesn't consider all runnable threads on all OS SKUs. In + // some cases, it may only consult the runnable threads whose ideal processor + // is the one currently executing code. Thus we ocassionally issue a call to + // Sleep(0), which considers all runnable threads at equal priority. Even this + // is insufficient since we may be spin waiting for lower priority threads to + // execute; we therefore must call Sleep(1) once in a while too, which considers + // all runnable threads, regardless of ideal processor and priority, but may + // remove the thread from the scheduler's queue for 10+ms, if the system is + // configured to use the (default) coarse-grained system timer. + // + +#if ETW_EVENTING // PAL doesn't support eventing, and we don't compile CDS providers for Coreclr + CdsSyncEtwBCLProvider.Log.SpinWait_NextSpinWillYield(); +#endif + int yieldsSoFar = (m_count >= YIELD_THRESHOLD ? m_count - YIELD_THRESHOLD : m_count); + + if ((yieldsSoFar % SLEEP_1_EVERY_HOW_MANY_TIMES) == (SLEEP_1_EVERY_HOW_MANY_TIMES - 1)) + { + ThreadLightup.Current.Sleep(1); + } + else if ((yieldsSoFar % SLEEP_0_EVERY_HOW_MANY_TIMES) == (SLEEP_0_EVERY_HOW_MANY_TIMES - 1)) + { + ThreadLightup.Current.Sleep(0); + } + else + { +#if PFX_LEGACY_3_5 + Platform.Yield(); +#else + ThreadLightup.Current.Yield(); +#endif + } + } + else + { + // + // Otherwise, we will spin. + // + // We do this using the CLR's SpinWait API, which is just a busy loop that + // issues YIELD/PAUSE instructions to ensure multi-threaded CPUs can react + // intelligently to avoid starving. (These are NOOPs on other CPUs.) We + // choose a number for the loop iteration count such that each successive + // call spins for longer, to reduce cache contention. We cap the total + // number of spins we are willing to tolerate to reduce delay to the caller, + // since we expect most callers will eventually block anyway. + // + ThreadLightup.Current.SpinWait(4 << m_count); + } + + // Finally, increment our spin counter. + m_count = (m_count == int.MaxValue ? YIELD_THRESHOLD : m_count + 1); + } + + /// + /// Resets the spin counter. + /// + /// + /// This makes and behave as though no calls + /// to had been issued on this instance. If a instance + /// is reused many times, it may be useful to reset it to avoid yielding too soon. + /// + public void Reset() + { + m_count = 0; + } + + #region Static Methods +#if !FEATURE_CORECLR + /// + /// Spins until the specified condition is satisfied. + /// + /// A delegate to be executed over and over until it returns true. + /// The argument is null. + public static void SpinUntil(Func condition) + { +#if DEBUG + bool result = +#endif + SpinUntil(condition, Timeout.Infinite); +#if DEBUG + Contract.Assert(result); +#endif + } + + /// + /// Spins until the specified condition is satisfied or until the specified timeout is expired. + /// + /// A delegate to be executed over and over until it returns true. + /// + /// A that represents the number of milliseconds to wait, + /// or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// True if the condition is satisfied within the timeout; otherwise, false + /// The argument is null. + /// is a negative number + /// other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater than + /// . + public static bool SpinUntil(Func condition, TimeSpan timeout) + { + // Validate the timeout + Int64 totalMilliseconds = (Int64)timeout.TotalMilliseconds; + if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) + { + throw new ArgumentOutOfRangeException( + "timeout", Strings.SpinWait_SpinUntil_TimeoutWrong); + } + + // Call wait with the timeout milliseconds + return SpinUntil(condition, (int)timeout.TotalMilliseconds); + } + + /// + /// Spins until the specified condition is satisfied or until the specified timeout is expired. + /// + /// A delegate to be executed over and over until it returns true. + /// The number of milliseconds to wait, or (-1) to wait indefinitely. + /// True if the condition is satisfied within the timeout; otherwise, false + /// The argument is null. + /// is a + /// negative number other than -1, which represents an infinite time-out. + public static bool SpinUntil(Func condition, int millisecondsTimeout) + { + if (millisecondsTimeout < Timeout.Infinite) + { + throw new ArgumentOutOfRangeException( + "millisecondsTimeout", Strings.SpinWait_SpinUntil_TimeoutWrong); + } + if (condition == null) + { + throw new ArgumentNullException("condition", Strings.SpinWait_SpinUntil_ArgumentNull); + } + long startTicks = 0; ; + if (millisecondsTimeout != 0 && millisecondsTimeout != Timeout.Infinite) + { + startTicks = DateTime.UtcNow.Ticks; + } + SpinWait spinner = new SpinWait(); + while (!condition()) + { + if (millisecondsTimeout == 0) + { + return false; + } + + spinner.SpinOnce(); + + if (millisecondsTimeout != Timeout.Infinite && spinner.NextSpinWillYield) + { + if (millisecondsTimeout <= (DateTime.UtcNow.Ticks - startTicks) / TimeSpan.TicksPerMillisecond) + { + return false; + } + } + } + return true; + + } +#endif //!FEATURE_CORECLR + #endregion + + } + + + /// + /// A helper class to get the number of preocessors, it updates the numbers of processors every sampling interval + /// + internal static class PlatformHelper + { + private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 30000; // How often to refresh the count, in milliseconds. + private static int s_processorCount = -1; // The last count seen. + private static DateTime s_nextProcessorCountRefreshTime = DateTime.MinValue; // The next time we'll refresh. + + /// + /// Gets the number of available processors + /// + internal static int ProcessorCount + { + get + { + if (DateTime.UtcNow.CompareTo(s_nextProcessorCountRefreshTime) >= 0) + { + s_processorCount = EnvironmentLightup.Instance.ProcessorCount; + s_nextProcessorCountRefreshTime = DateTime.UtcNow.AddMilliseconds(PROCESSOR_COUNT_REFRESH_INTERVAL_MS); + } + + Contract.Assert(s_processorCount > 0 && s_processorCount <= 64, + "Processor count not within the expected range (1 - 64)."); + + return s_processorCount; + } + } + + /// + /// Gets whether the current machine has only a single processor. + /// + internal static bool IsSingleProcessor + { + get { return ProcessorCount == 1; } + } + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/IThreadPoolWorkItem.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/IThreadPoolWorkItem.cs new file mode 100644 index 000000000..22157cf4e --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/IThreadPoolWorkItem.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Threading.Tasks +{ + /// + /// An interface similar to the one added in .NET 4.0. + /// + internal interface IThreadPoolWorkItem + { + void ExecuteWorkItem(); + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/Task.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/Task.cs new file mode 100644 index 000000000..4921157a8 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/Task.cs @@ -0,0 +1,4426 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// Task.cs +// +// hyildiz +// +// A schedulable unit of work. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; +using System.Threading; +using System.Diagnostics; +using System.Diagnostics.Contracts; + +// Disable the "reference to volatile field not treated as volatile" error. +#pragma warning disable 0420 + +namespace System.Threading.Tasks +{ + /// + /// Represents the current stage in the lifecycle of a . + /// + public enum TaskStatus + { + /// + /// The task has been initialized but has not yet been scheduled. + /// + Created, + /// + /// The task is waiting to be activated and scheduled internally by the .NET Framework infrastructure. + /// + WaitingForActivation, + /// + /// The task has been scheduled for execution but has not yet begun executing. + /// + WaitingToRun, + /// + /// The task is running but has not yet completed. + /// + Running, + // /// + // /// The task is currently blocked in a wait state. + // /// + // Blocked, + /// + /// The task has finished executing and is implicitly waiting for + /// attached child tasks to complete. + /// + WaitingForChildrenToComplete, + /// + /// The task completed execution successfully. + /// + RanToCompletion, + /// + /// The task acknowledged cancellation by throwing an OperationCanceledException2 with its own CancellationToken + /// while the token was in signaled state, or the task's CancellationToken was already signaled before the + /// task started executing. + /// + Canceled, + /// + /// The task completed due to an unhandled exception. + /// + Faulted + } + + + /// + /// Represents an asynchronous operation. + /// + /// + /// + /// instances may be created in a variety of ways. The most common approach is by + /// using the Task type's property to retrieve a instance that can be used to create tasks for several + /// purposes. For example, to create a that runs an action, the factory's StartNew + /// method may be used: + /// + /// // C# + /// var t = Task.Factory.StartNew(() => DoAction()); + /// + /// ' Visual Basic + /// Dim t = Task.Factory.StartNew(Function() DoAction()) + /// + /// + /// + /// The class also provides constructors that initialize the Task but that do not + /// schedule it for execution. For performance reasons, TaskFactory's StartNew method should be the + /// preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation + /// and scheduling must be separated, the constructors may be used, and the task's + /// method may then be used to schedule the task for execution at a later time. + /// + /// + /// All members of , except for , are thread-safe + /// and may be used from multiple threads concurrently. + /// + /// + /// For operations that return values, the class + /// should be used. + /// + /// + /// For developers implementing custom debuggers, several internal and private members of Task may be + /// useful (these may change from release to release). The Int32 m_taskId field serves as the backing + /// store for the property, however accessing this field directly from a debugger may be + /// more efficient than accessing the same value through the property's getter method (the + /// s_taskIdCounter Int32 counter is used to retrieve the next available ID for a Task). Similarly, the + /// Int32 m_stateFlags field stores information about the current lifecycle stage of the Task, + /// information also accessible through the property. The m_action System.Object + /// field stores a reference to the Task's delegate, and the m_stateObject System.Object field stores the + /// async state passed to the Task by the developer. Finally, for debuggers that parse stack frames, the + /// InternalWait method serves a potential marker for when a Task is entering a wait operation. + /// + /// + + [DebuggerTypeProxy(typeof(SystemThreadingTasks_TaskDebugView))] + [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}")] + public partial class Task : IThreadPoolWorkItem, IAsyncResult //, IDisposable + { + + // Accessing ThreadStatic variables on classes with class constructors is much slower than if the class + // has no class constructor. So we declasre s_currentTask inside a nested class with no constructor. + // Do not put any static variables with explicit initialization in this class, as it will regress performance. + private static class ThreadLocals + { + internal static ThreadStatic s_currentTask = new ThreadStatic(); // The currently executing task. + } + + internal static int s_taskIdCounter; //static counter used to generate unique task IDs + private static TaskFactory s_factory = new TaskFactory(); + + private int m_taskId; // this task's unique ID. initialized only if it is ever requested + + internal object m_action; // The body of the task. Might be Action, Action or Action. + // If m_action is set to null it will indicate that we operate in the + // "externally triggered completion" mode, which is exclusively meant + // for the signalling Task (aka. promise). In this mode, + // we don't call InnerInvoke() in response to a Wait(), but simply wait on + // the completion event which will be set when the Future class calls Finish(). + // But the event would now be signalled if Cancel() is called + + + internal object m_stateObject; // A state object that can be optionally supplied, passed to action. + internal TaskScheduler m_taskScheduler; // The task scheduler this task runs under. @TODO: is this required? + + internal readonly Task m_parent; // A task's parent, or null if parent-less. + internal ExecutionContextLightup m_capturedContext; // The context to run the task within, if any. + + internal volatile int m_stateFlags; + + // State constants for m_stateFlags; + // The bits of m_stateFlags are allocated as follows: + // 0x40000000 - TaskBase state flag + // 0x3FFF0000 - Task state flags + // 0x0000FF00 - internal TaskCreationOptions flags + // 0x000000FF - publicly exposed TaskCreationOptions flags + // + // See TaskCreationOptions for bit values associated with TaskCreationOptions + // + private const int OptionsMask = 0xFFFF; // signifies the Options portion of m_stateFlags + internal const int TASK_STATE_STARTED = 0x10000; + internal const int TASK_STATE_DELEGATE_INVOKED = 0x20000; + internal const int TASK_STATE_DISPOSED = 0x40000; + internal const int TASK_STATE_EXCEPTIONOBSERVEDBYPARENT = 0x80000; + internal const int TASK_STATE_CANCELLATIONACKNOWLEDGED = 0x100000; + internal const int TASK_STATE_FAULTED = 0x200000; + internal const int TASK_STATE_CANCELED = 0x400000; + internal const int TASK_STATE_WAITING_ON_CHILDREN = 0x800000; + internal const int TASK_STATE_RAN_TO_COMPLETION = 0x1000000; + internal const int TASK_STATE_WAITINGFORACTIVATION = 0x2000000; + internal const int TASK_STATE_COMPLETION_RESERVED = 0x4000000; + internal const int TASK_STATE_THREAD_WAS_ABORTED = 0x8000000; + + // Values for ContingentProperties.m_internalCancellationRequested. + internal static int CANCELLATION_REQUESTED = 0x1; + + private volatile ManualResetEventSlim m_completionEvent; // Lazily created if waiting is required. + + // We moved a number of Task properties into this class. The idea is that in most cases, these properties never + // need to be accessed during the life cycle of a Task, so we don't want to instantiate them every time. Once + // one of these properties needs to be written, we will instantiate a ContingentProperties object and set + // the appropriate property. + internal class ContingentProperties + { + public volatile int m_internalCancellationRequested; // We keep canceled in its own field because threads legally race to set it. + + internal volatile int m_completionCountdown = 1; // # of active children + 1 (for this task itself). + // Used for ensuring all children are done before this task can complete + // The extra count helps prevent the race for executing the final state transition + // (i.e. whether the last child or this task itself should call FinishStageTwo()) + + public volatile TaskExceptionHolder m_exceptionsHolder; // Tracks exceptions, if any have occurred + + public volatile List m_exceptionalChildren; // A list of child tasks that threw an exception (TCEs don't count), + // but haven't yet been waited on by the parent, lazily initialized. + + public volatile List m_continuations; // A list of tasks or actions to be started upon completion, lazily initialized. + + public CancellationToken m_cancellationToken; + public Shared m_cancellationRegistration; + } + + internal class Shared + { + internal T Value; + internal Shared(T value) { Value = value; } + } + + // This field will only be instantiated to some non-null value if any ContingentProperties need to be set. + internal volatile ContingentProperties m_contingentProperties; + + /// + /// A type initializer that runs with the appropriate permissions. + /// + // // [SecuritySafeCritical] + static Task() + { + s_ecCallback = new Action(ExecutionContextCallback); + } + + // Special internal constructor to create an already-completed task. + // if canceled==true, create a Canceled task, or else create a RanToCompletion task. + internal Task(bool canceled, TaskCreationOptions creationOptions, CancellationToken ct) + { + int optionFlags = (int)creationOptions; + if (canceled) + { + m_stateFlags = TASK_STATE_CANCELED | TASK_STATE_CANCELLATIONACKNOWLEDGED | optionFlags; + m_contingentProperties = ContingentPropertyCreator(); + m_contingentProperties.m_cancellationToken = ct; + m_contingentProperties.m_internalCancellationRequested = CANCELLATION_REQUESTED; + } + else + m_stateFlags = TASK_STATE_RAN_TO_COMPLETION | optionFlags; + } + + // Special internal constructor to create an already-Faulted task. + // Break this out when we need it. + // + //internal Task(Exception exception, bool attached) + //{ + // Task m_parent = attached ? Task.InternalCurrent : null; + // + // if(m_parent != null) m_parent.AddNewChild(); + // + // m_contingentProperties = new ContingentProperties(); + // m_contingentProperties.m_exceptionsHolder = new TaskExceptionHolder(this); + // m_contingentProperties.m_exceptionsHolder.Add(exception); + // m_stateFlags = TASK_STATE_FAULTED; + // + // if (m_parent != null) m_parent.ProcessChildCompletion(this); + //} + + + + // Special constructor for use with promise-style tasks. + // Added promiseStyle parameter as an aid to the compiler to distinguish between (state,TCO) and + // (action,TCO). It should always be true. + internal Task(object state, CancellationToken cancelationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, bool promiseStyle) + { + Contract.Assert(promiseStyle, "Promise CTOR: promiseStyle was false"); + + // Check the creationOptions. We only allow the attached/detached option to be specified for promise tasks. + if ((creationOptions & ~(TaskCreationOptions.AttachedToParent)) != 0) + { + throw new ArgumentOutOfRangeException("creationOptions"); + } + + // Make sure that no illegal InternalTaskOptions are specified + Contract.Assert((internalOptions & ~(InternalTaskOptions.PromiseTask)) == 0, "Illegal internal options in Task(obj,ct,tco,ito,bool)"); + + // m_parent is readonly, and so must be set in the constructor. + // Only set a parent if AttachedToParent is specified. + if ((creationOptions & TaskCreationOptions.AttachedToParent) != 0) + m_parent = Task.InternalCurrent; + + TaskConstructorCore(null, state, cancelationToken, creationOptions, internalOptions, TaskScheduler.Current); + } + + /// + /// Initializes a new with the specified action. + /// + /// The delegate that represents the code to execute in the Task. + /// The argument is null. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action) + : this((object)action, null, Task.InternalCurrent, CancellationToken.None, TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action and CancellationToken. + /// + /// The delegate that represents the code to execute in the Task. + /// The CancellationToken + /// that will be assigned to the new Task. + /// The argument is null. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action, CancellationToken cancellationToken) + : this((object)action, null, Task.InternalCurrent, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action and creation options. + /// + /// The delegate that represents the code to execute in the task. + /// + /// The TaskCreationOptions used to + /// customize the Task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action, TaskCreationOptions creationOptions) + : this((object)action, null, Task.InternalCurrent, CancellationToken.None, creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action and creation options. + /// + /// The delegate that represents the code to execute in the task. + /// The that will be assigned to the new task. + /// + /// The TaskCreationOptions used to + /// customize the Task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions) + : this((object)action, null, Task.InternalCurrent, cancellationToken, creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + + /// + /// Initializes a new with the specified action and state. + /// + /// The delegate that represents the code to execute in the task. + /// An object representing data to be used by the action. + /// + /// The argument is null. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action, object state) + : this((object)action, state, Task.InternalCurrent, CancellationToken.None, TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action, state, snd options. + /// + /// The delegate that represents the code to execute in the task. + /// An object representing data to be used by the action. + /// The that will be assigned to the new task. + /// + /// The argument is null. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action, object state, CancellationToken cancellationToken) + : this((object)action, state, Task.InternalCurrent, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action, state, snd options. + /// + /// The delegate that represents the code to execute in the task. + /// An object representing data to be used by the action. + /// + /// The TaskCreationOptions used to + /// customize the Task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action, object state, TaskCreationOptions creationOptions) + : this((object)action, state, Task.InternalCurrent, CancellationToken.None, creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action, state, snd options. + /// + /// The delegate that represents the code to execute in the task. + /// An object representing data to be used by the action. + /// The that will be assigned to the new task. + /// + /// The TaskCreationOptions used to + /// customize the Task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Action action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) + : this((object)action, state, Task.InternalCurrent, cancellationToken, creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + + // For Task.ContinueWith() and Future.ContinueWith() + internal Task(Action action, object state, Task parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) + : this((object)action, state, parent, cancellationToken, creationOptions, internalOptions, scheduler) + { + PossiblyCaptureContext(ref stackMark); + } + + /// + /// An internal constructor used by the factory methods on task and its descendent(s). + /// This variant does not capture the ExecutionContext; it is up to the caller to do that. + /// + /// An action to execute. + /// Optional state to pass to the action. + /// Parent of Task. + /// A CancellationToken for the task. + /// A task scheduler under which the task will run. + /// Options to control its execution. + /// Internal options to control its execution + internal Task(object action, object state, Task parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) + { + if (action == null) + { + throw new ArgumentNullException("action"); + } + + Contract.Assert(action is Action || action is Action); + + // This is readonly, and so must be set in the constructor + // Keep a link to your parent if: (A) You are attached, or (B) you are self-replicating. + // TODO: the check in the second line seems unnecessary - we already explicitly wait for replicating tasks + if (((creationOptions & TaskCreationOptions.AttachedToParent) != 0) || + ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) + ) + { + m_parent = parent; + } + + TaskConstructorCore(action, state, cancellationToken, creationOptions, internalOptions, scheduler); + } + + /// + /// Common logic used by the following internal ctors: + /// Task() + /// Task(object action, object state, Task parent, TaskCreationOptions options, TaskScheduler taskScheduler) + /// + /// ASSUMES THAT m_creatingTask IS ALREADY SET. + /// + /// + /// Action for task to execute. + /// Object to which to pass to action (may be null) + /// Task scheduler on which to run thread (only used by continuation tasks). + /// A CancellationToken for the Task. + /// Options to customize behavior of Task. + /// Internal options to customize behavior of Task. + internal void TaskConstructorCore(object action, object state, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) + { + m_action = action; + m_stateObject = state; + m_taskScheduler = scheduler; + + // Check for validity of options + if ((creationOptions & + ~(TaskCreationOptions.AttachedToParent | + TaskCreationOptions.LongRunning | + TaskCreationOptions.PreferFairness)) != 0) + { + throw new ArgumentOutOfRangeException("creationOptions"); + } + + // Check the validity of internalOptions + int illegalInternalOptions = + (int)(internalOptions & + ~(InternalTaskOptions.SelfReplicating | + InternalTaskOptions.ChildReplica | + InternalTaskOptions.PromiseTask | + InternalTaskOptions.ContinuationTask | + InternalTaskOptions.QueuedByRuntime)); + + Contract.Assert(illegalInternalOptions == 0, "TaskConstructorCore: Illegal internal options"); + + + // Throw exception if the user specifies both LongRunning and SelfReplicating + if (((creationOptions & TaskCreationOptions.LongRunning) != 0) && + ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)) + { + throw new InvalidOperationException(Strings.Task_ctor_LRandSR); + } + + // Assign options to m_stateAndOptionsFlag. + Contract.Assert(m_stateFlags == 0, "TaskConstructorCore: non-zero m_stateFlags"); + Contract.Assert((((int)creationOptions) | OptionsMask) == OptionsMask, "TaskConstructorCore: options take too many bits"); + m_stateFlags = (int)creationOptions | (int)internalOptions; + + // For continuation tasks or TaskCompletionSource.Tasks, begin life in WaitingForActivation state + // rather than Created state. + if ((m_action == null) || + ((internalOptions & InternalTaskOptions.ContinuationTask) != 0)) + { + m_stateFlags |= TASK_STATE_WAITINGFORACTIVATION; + } + + // Now is the time to add the new task to the children list + // of the creating task if the options call for it. + // We can safely call the creator task's AddNewChild() method to register it, + // because at this point we are already on its thread of execution. + + if (m_parent != null && (creationOptions & TaskCreationOptions.AttachedToParent) != 0) + { + m_parent.AddNewChild(); + } + + // if we have a non-null cancellationToken, allocate the contingent properties to save it + // we need to do this as the very last thing in the construction path, because the CT registration could modify m_stateFlags + if (cancellationToken.CanBeCanceled) + { + Contract.Assert((internalOptions & (InternalTaskOptions.ChildReplica | InternalTaskOptions.SelfReplicating)) == 0, + "TaskConstructorCore: Did not expect to see cancellable token for replica/replicating task."); + LazyInitializer.EnsureInitialized(ref m_contingentProperties, s_contingentPropertyCreator); + m_contingentProperties.m_cancellationToken = cancellationToken; + + try + { + cancellationToken.ThrowIfSourceDisposed(); + + // If an unstarted task has a valid CancellationToken that gets signalled while the task is still not queued + // we need to proactively cancel it, because it may never execute to transition itself. + // The only way to accomplish this is to register a callback on the CT. + // We exclude Promise tasks from this, because TasckCompletionSource needs to fully control the inner tasks's lifetime (i.e. not allow external cancellations) + if ((internalOptions & + (InternalTaskOptions.QueuedByRuntime | InternalTaskOptions.PromiseTask)) == 0) + { + CancellationTokenRegistration ctr = cancellationToken.InternalRegisterWithoutEC(s_taskCancelCallback, this); + m_contingentProperties.m_cancellationRegistration = new Shared(ctr); + } + } + catch + { + // If we have an exception related to our CancellationToken, then we need to subtract ourselves + // from our parent before throwing it. + if ((m_parent != null) && ((creationOptions & TaskCreationOptions.AttachedToParent) != 0)) + m_parent.DisregardChild(); + throw; + } + } + } + + /// + /// Checks if we registered a CT callback during construction, and deregisters it. + /// This should be called when we know the registration isn't useful anymore. Specifically from Finish() if the task has completed + /// successfully or with an exception. + /// + internal void DeregisterCancellationCallback() + { + if (m_contingentProperties != null && + m_contingentProperties.m_cancellationRegistration != null) + { + // Harden against ODEs thrown from disposing of the CTR. + // Since the task has already been put into a final state by the time this + // is called, all we can do here is suppress the exception. + try + { + m_contingentProperties.m_cancellationRegistration.Value.Dispose(); + } + catch (ObjectDisposedException) { } + + m_contingentProperties.m_cancellationRegistration = null; + } + } + + + // Static delegate to be used as a cancellation callback on unstarted tasks that have a valid cancellation token. + // This is necessary to transition them into canceled state if their cancellation token is signalled while they are still not queued + internal static Action s_taskCancelCallback = new Action(TaskCancelCallback); + private static void TaskCancelCallback(Object o) + { + Task t = (Task)o; + t.InternalCancel(false); + } + + // Debugger support + private string DebuggerDisplayMethodDescription + { + get + { + Delegate d = (Delegate)m_action; + return d != null ? d.Method.ToString() : "{null}"; + } + } + + + /// + /// Captures the ExecutionContext so long as flow isn't suppressed. + /// + /// A stack crawl mark pointing to the frame of the caller. + internal void PossiblyCaptureContext(ref StackCrawlMark stackMark) + { + // In the legacy .NET 3.5 build, we don't have the optimized overload of Capture() + // available, so we call the parameterless overload. +//#if PFX_LEGACY_3_5 + m_capturedContext = ExecutionContextLightup.Instance.Capture(); +//#else +// m_capturedContext = ExecutionContext.Capture( +// ref stackMark, +// ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase); +//#endif + } + + // Internal property to process TaskCreationOptions access and mutation. + internal TaskCreationOptions Options + { + get + { + Contract.Assert((OptionsMask & 1) == 1, "OptionsMask needs a shift in Options.get"); + return (TaskCreationOptions)(m_stateFlags & OptionsMask); + } + } + + // Atomically OR-in newBits to m_stateFlags, while making sure that + // no illegalBits are set. Returns true on success, false on failure. + internal bool AtomicStateUpdate(int newBits, int illegalBits) + { + int oldFlags = 0; + return AtomicStateUpdate(newBits, illegalBits, ref oldFlags); + } + + internal bool AtomicStateUpdate(int newBits, int illegalBits, ref int oldFlags) + { + SpinWait sw = new SpinWait(); + + do + { + oldFlags = m_stateFlags; + if ((oldFlags & illegalBits) != 0) return false; + if (Interlocked.CompareExchange(ref m_stateFlags, oldFlags | newBits, oldFlags) == oldFlags) + { + return true; + } + sw.SpinOnce(); + } while (true); + + } + + // Atomically mark a Task as started while making sure that it is not canceled. + internal bool MarkStarted() + { + return AtomicStateUpdate(TASK_STATE_STARTED, TASK_STATE_CANCELED | TASK_STATE_STARTED); + } + + + /// + /// Internal function that will be called by a new child task to add itself to + /// the children list of the parent (this). + /// + /// Since a child task can only be created from the thread executing the action delegate + /// of this task, reentrancy is neither required nor supported. This should not be called from + /// anywhere other than the task construction/initialization codepaths. + /// + internal void AddNewChild() + { + Contract.Assert(Task.InternalCurrent == this || this.IsSelfReplicatingRoot, "Task.AddNewChild(): Called from an external context"); + + LazyInitializer.EnsureInitialized(ref m_contingentProperties, s_contingentPropertyCreator); + + + if (m_contingentProperties.m_completionCountdown == 1 && !IsSelfReplicatingRoot) + { + // A count of 1 indicates so far there was only the parent, and this is the first child task + // Single kid => no fuss about who else is accessing the count. Let's save ourselves 100 cycles + // We exclude self replicating root tasks from this optimization, because further child creation can take place on + // other cores and with bad enough timing this write may not be visible to them. + m_contingentProperties.m_completionCountdown++; + } + else + { + // otherwise do it safely + Interlocked.Increment(ref m_contingentProperties.m_completionCountdown); + } + } + + // This is called in the case where a new child is added, but then encounters a CancellationToken-related exception. + // We need to subtract that child from m_completionCountdown, or the parent will never complete. + internal void DisregardChild() + { + Contract.Assert(Task.InternalCurrent == this, "Task.DisregardChild(): Called from an external context"); + Contract.Assert((m_contingentProperties != null) && (m_contingentProperties.m_completionCountdown >= 2), "Task.DisregardChild(): Expected parent count to be >= 2"); + + Interlocked.Decrement(ref m_contingentProperties.m_completionCountdown); + } + + /// + /// Starts the , scheduling it for execution to the current TaskScheduler. + /// + /// + /// A task may only be started and run only once. Any attempts to schedule a task a second time + /// will result in an exception. + /// + /// + /// The is not in a valid state to be started. It may have already been started, + /// executed, or canceled, or it may have been created in a manner that doesn't support direct + /// scheduling. + /// + /// + /// The instance has been disposed. + /// + public void Start() + { + Start(TaskScheduler.Current); + } + + /// + /// Starts the , scheduling it for execution to the specified TaskScheduler. + /// + /// + /// A task may only be started and run only once. Any attempts to schedule a task a second time will + /// result in an exception. + /// + /// + /// The TaskScheduler with which to associate + /// and execute this task. + /// + /// + /// The argument is null. + /// + /// + /// The is not in a valid state to be started. It may have already been started, + /// executed, or canceled, or it may have been created in a manner that doesn't support direct + /// scheduling. + /// + /// + /// The instance has been disposed. + /// + public void Start(TaskScheduler scheduler) + { + // Throw an exception if the task has previously been disposed. + //ThrowIfDisposed(); + + // Need to check this before (m_action == null) because completed tasks will + // set m_action to null. We would want to know if this is the reason that m_action == null. + if (IsCompleted) + { + throw new InvalidOperationException(Strings.Task_Start_TaskCompleted); + } + + if (m_action == null) + { + throw new InvalidOperationException(Strings.Task_Start_NullAction); + } + + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0) + { + throw new InvalidOperationException(Strings.Task_Start_ContinuationTask); + } + + // Make sure that Task only gets started once. Or else throw an exception. + if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null) + { + throw new InvalidOperationException(Strings.Task_Start_AlreadyStarted); + } + + ScheduleAndStart(true); + } + + /// + /// Runs the synchronously on the current TaskScheduler. + /// + /// + /// + /// A task may only be started and run only once. Any attempts to schedule a task a second time will + /// result in an exception. + /// + /// + /// Tasks executed with will be associated with the current TaskScheduler. + /// + /// + /// If the target scheduler does not support running this Task on the current thread, the Task will + /// be scheduled for execution on the scheduler, and the current thread will block until the + /// Task has completed execution. + /// + /// + /// + /// The is not in a valid state to be started. It may have already been started, + /// executed, or canceled, or it may have been created in a manner that doesn't support direct + /// scheduling. + /// + /// + /// The instance has been disposed. + /// + public void RunSynchronously() + { + InternalRunSynchronously(TaskScheduler.Current); + } + + /// + /// Runs the synchronously on the scheduler provided. + /// + /// + /// + /// A task may only be started and run only once. Any attempts to schedule a task a second time will + /// result in an exception. + /// + /// + /// If the target scheduler does not support running this Task on the current thread, the Task will + /// be scheduled for execution on the scheduler, and the current thread will block until the + /// Task has completed execution. + /// + /// + /// + /// The is not in a valid state to be started. It may have already been started, + /// executed, or canceled, or it may have been created in a manner that doesn't support direct + /// scheduling. + /// + /// + /// The instance has been disposed. + /// + /// The parameter + /// is null. + /// The scheduler on which to attempt to run this task inline. + public void RunSynchronously(TaskScheduler scheduler) + { + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + InternalRunSynchronously(scheduler); + } + + // + // Internal version of RunSynchronously that allows a taskScheduler argument. + // + // // [SecuritySafeCritical] // Needed for QueueTask + internal void InternalRunSynchronously(TaskScheduler scheduler) + { + Contract.Assert(scheduler != null, "Task.InternalRunSynchronously(): null TaskScheduler"); + //ThrowIfDisposed(); + + // Can't call this method on a continuation task + if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0) + { + throw new InvalidOperationException(Strings.Task_RunSynchronously_Continuation); + } + + // Can't call this method on a task that has already completed + if (IsCompleted) + { + throw new InvalidOperationException(Strings.Task_RunSynchronously_TaskCompleted); + } + + // Can't call this method on a promise-style task + if (m_action == null) + { + throw new InvalidOperationException(Strings.Task_RunSynchronously_Promise); + } + + // Make sure that Task only gets started once. Or else throw an exception. + if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null) + { + throw new InvalidOperationException(Strings.Task_RunSynchronously_AlreadyStarted); + } + + // execute only if we win the race against concurrent cancel attempts. + // otherwise throw an exception, because we've been canceled. + if (MarkStarted()) + { + bool taskQueued = false; + try + { + // We wrap TryRunInline() in a try/catch block and move an excepted task to Faulted here, + // but not in Wait()/WaitAll()/FastWaitAll(). Here, we know for sure that the + // task will not be subsequently scheduled (assuming that the scheduler adheres + // to the guideline that an exception implies that no state change took place), + // so it is safe to catch the exception and move the task to a final state. The + // same cannot be said for Wait()/WaitAll()/FastWaitAll(). + if (!scheduler.TryRunInline(this, false)) + { + scheduler.QueueTask(this); + taskQueued = true; // only mark this after successfully queuing the task. + } + + // A successful TryRunInline doesn't guarantee completion, as there may be unfinished children + // Also if we queued the task above, we need to wait. + if (!IsCompleted) + { + CompletedEvent.Wait(); + } + } + catch (Exception e) + { + // we 1) either received an unexpected exception originating from a custom scheduler, which needs to be wrapped in a TSE and thrown + // 2) or a a ThreadAbortException, which we need to skip here, because it would already have been handled in Task.Execute + if (!taskQueued && !(ThreadingServices.IsThreadAbort(e))) + { + // We had a problem with TryRunInline() or QueueTask(). + // Record the exception, marking ourselves as Completed/Faulted. + TaskSchedulerException tse = new TaskSchedulerException(e); + AddException(tse); + Finish(false); + + // Mark ourselves as "handled" to avoid crashing the finalizer thread if the caller neglects to + // call Wait() on this task. + // m_contingentProperties.m_exceptionHolder *should* already exist after AddException() + Contract.Assert((m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null), + "Task.InternalRunSynchronously(): Expected m_contingentProperties.m_exceptionsHolder to exist"); + m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); + + // And re-throw. + throw tse; + } + else + { + // We had a problem with CompletedEvent.Wait(). Just re-throw. + throw; + } + } + } + else + { + Contract.Assert((m_stateFlags & TASK_STATE_CANCELED) != 0, "Task.RunSynchronously: expected TASK_STATE_CANCELED to be set"); + // Can't call this method on canceled task. + throw new InvalidOperationException(Strings.Task_RunSynchronously_TaskCompleted); + } + } + + + //// + //// Helper methods for Factory StartNew methods. + //// + + + // Implicitly converts action to object and handles the meat of the StartNew() logic. + internal static Task InternalStartNew( + Task creatingTask, object action, object state, CancellationToken cancellationToken, TaskScheduler scheduler, + TaskCreationOptions options, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark) + { + // Validate arguments. + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + // Create and schedule the task. This throws an InvalidOperationException if already shut down. + // Here we add the InternalTaskOptions.QueuedByRuntime to the internalOptions, so that TaskConstructorCore can skip the cancellation token registration + Task t = new Task(action, state, creatingTask, cancellationToken, options, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); + t.PossiblyCaptureContext(ref stackMark); + + t.ScheduleAndStart(false); + return t; + } + + + ///////////// + // properties + + /// + /// Gets a unique ID for this Task instance. + /// + /// + /// Task IDs are assigned on-demand and do not necessarily represent the order in the which Task + /// instances were created. + /// + public int Id + { + get + { + if (m_taskId == 0) + { + int newId = 0; + // We need to repeat if Interlocked.Increment wraps around and returns 0. + // Otherwise next time this task's Id is queried it will get a new value + do + { + newId = Interlocked.Increment(ref s_taskIdCounter); + } + while (newId == 0); + + Interlocked.CompareExchange(ref m_taskId, newId, 0); + } + + return m_taskId; + } + } + + /// + /// Returns the unique ID of the currently executing Task. + /// + public static int? CurrentId + { + get + { + Task currentTask = InternalCurrent; + if (currentTask != null) + return currentTask.Id; + else + return null; + } + } + + /// + /// Gets the Task instance currently executing, or + /// null if none exists. + /// + internal static Task InternalCurrent + { + get { return ThreadLocals.s_currentTask.Value; } + } + + /// + /// Gets the Exception that caused the Task to end prematurely. If the Task completed successfully or has not yet thrown any + /// exceptions, this will return null. + /// + /// + /// Tasks that throw unhandled exceptions store the resulting exception and propagate it wrapped in a + /// in calls to Wait + /// or in accesses to the property. Any exceptions not observed by the time + /// the Task instance is garbage collected will be propagated on the finalizer thread. + /// + /// + /// The Task + /// has been disposed. + /// + public AggregateException Exception + { + get + { + AggregateException e = null; + + // If you're faulted, retrieve the exception(s) + if (IsFaulted) e = GetExceptions(false); + + // Only return an exception in faulted state (skip manufactured exceptions) + // A "benevolent" race condition makes it possible to return null when IsFaulted is + // true (i.e., if IsFaulted is set just after the check to IsFaulted above). + Contract.Assert((e == null) || IsFaulted, "Task.Exception_get(): returning non-null value when not Faulted"); + + return e; + } + } + + /// + /// Gets the TaskStatus of this Task. + /// + public TaskStatus Status + { + get + { + TaskStatus rval; + + // get a cached copy of the state flags. This should help us + // to get a consistent view of the flags if they are changing during the + // execution of this method. + int sf = m_stateFlags; + + if ((sf & TASK_STATE_FAULTED) != 0) rval = TaskStatus.Faulted; + else if ((sf & TASK_STATE_CANCELED) != 0) rval = TaskStatus.Canceled; + else if ((sf & TASK_STATE_RAN_TO_COMPLETION) != 0) rval = TaskStatus.RanToCompletion; + else if ((sf & TASK_STATE_WAITING_ON_CHILDREN) != 0) rval = TaskStatus.WaitingForChildrenToComplete; + else if ((sf & TASK_STATE_DELEGATE_INVOKED) != 0) rval = TaskStatus.Running; + else if ((sf & TASK_STATE_STARTED) != 0) rval = TaskStatus.WaitingToRun; + else if ((sf & TASK_STATE_WAITINGFORACTIVATION) != 0) rval = TaskStatus.WaitingForActivation; + else rval = TaskStatus.Created; + + return rval; + } + } + + /// + /// Gets whether this Task instance has completed + /// execution due to being canceled. + /// + /// + /// A Task will complete in Canceled state either if its CancellationToken + /// was marked for cancellation before the task started executing, or if the task acknowledged the cancellation request on + /// its already signaled CancellationToken by throwing an + /// OperationCanceledException2 that bears the same + /// CancellationToken. + /// + public bool IsCanceled + { + get + { + // Return true if canceled bit is set and faulted bit is not set + return (m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_FAULTED)) == TASK_STATE_CANCELED; + } + } + + /// + /// Returns true if this task has a cancellation token and it was signaled. + /// To be used internally in execute entry codepaths. + /// + internal bool IsCancellationRequested + { + get + { + // check both the internal cancellation request flag and the CancellationToken attached to this task + return ((m_contingentProperties != null) && (m_contingentProperties.m_internalCancellationRequested == CANCELLATION_REQUESTED)) || + CancellationToken.IsCancellationRequested; + } + } + + // Static delegate used for creating a ContingentProperties object from LazyInitializer. + internal static Func s_contingentPropertyCreator = new Func(ContingentPropertyCreator); + private static ContingentProperties ContingentPropertyCreator() + { + return new ContingentProperties(); + } + + /// + /// This internal property provides access to the CancellationToken that was set on the task + /// when it was constructed. + /// + internal CancellationToken CancellationToken + { + get + { + return (m_contingentProperties == null) ? CancellationToken.None : + m_contingentProperties.m_cancellationToken; + } + } + + /// + /// Gets whether this threw an OperationCanceledException2 while its CancellationToken was signaled. + /// + internal bool IsCancellationAcknowledged + { + get { return (m_stateFlags & TASK_STATE_CANCELLATIONACKNOWLEDGED) != 0; } + } + + + /// + /// Gets whether this Task has completed. + /// + /// + /// will return true when the Task is in one of the three + /// final states: RanToCompletion, + /// Faulted, or + /// Canceled. + /// + public bool IsCompleted + { + get + { + return ((m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_FAULTED | TASK_STATE_RAN_TO_COMPLETION)) != 0); + } + } + + // For use in InternalWait -- marginally faster than (Task.Status == TaskStatus.RanToCompletion) + internal bool CompletedSuccessfully + { + get + { + int completedMask = TASK_STATE_CANCELED | TASK_STATE_FAULTED | TASK_STATE_RAN_TO_COMPLETION; + return (m_stateFlags & completedMask) == TASK_STATE_RAN_TO_COMPLETION; + } + } + + /// + /// Checks whether this task has been disposed. + /// + internal bool IsDisposed + { + get { return (m_stateFlags & TASK_STATE_DISPOSED) != 0; } + } + + /// + /// Throws an exception if the task has been disposed, and hence can no longer be accessed. + /// + /// The task has been disposed. + internal void ThrowIfDisposed() + { + if (IsDisposed) + { + throw new ObjectDisposedException(null, Strings.Task_ThrowIfDisposed); + } + } + + + /// + /// Gets the TaskCreationOptions used + /// to create this task. + /// + public TaskCreationOptions CreationOptions + { + get { return Options & (TaskCreationOptions)(~InternalTaskOptions.InternalOptionsMask); } + } + + /// + /// Gets a that can be used to wait for the task to + /// complete. + /// + /// + /// Using the wait functionality provided by + /// should be preferred over using for similar + /// functionality. + /// + /// + /// The has been disposed. + /// + WaitHandle IAsyncResult.AsyncWaitHandle + { + // Although a slim event is used internally to avoid kernel resource allocation, this function + // forces allocation of a true WaitHandle when called. + get + { + ThrowIfDisposed(); + return CompletedEvent.WaitHandle; + } + } + + // Overridden by Task to return m_futureState + internal virtual object InternalAsyncState + { + get { return m_stateObject; } + } + + /// + /// Gets the state object supplied when the Task was created, + /// or null if none was supplied. + /// + public object AsyncState + { + get { return InternalAsyncState; } + } + + /// + /// Gets an indication of whether the asynchronous operation completed synchronously. + /// + /// true if the asynchronous operation completed synchronously; otherwise, false. + bool IAsyncResult.CompletedSynchronously + { + get + { + // @TODO: do we want to faithfully return 'true' if the task ran on the same + // thread which created it? Probably not, but we need to think about it. + return false; + } + } + + // @TODO: can this be retrieved from TLS instead of storing it? + /// + /// Provides access to the TaskScheduler responsible for executing this Task. + /// + internal TaskScheduler ExecutingTaskScheduler + { + get { return m_taskScheduler; } + } + + /// + /// Provides access to factory methods for creating and instances. + /// + /// + /// The factory returned from is a default instance + /// of , as would result from using + /// the default constructor on TaskFactory. + /// + public static TaskFactory Factory { get { return s_factory; } } + + /// + /// Provides an event that can be used to wait for completion. + /// Only called by Wait*(), which means that we really do need to instantiate a completion event. + /// + internal ManualResetEventSlim CompletedEvent + { + get + { + if (m_completionEvent == null) + { + bool wasCompleted = IsCompleted; + ManualResetEventSlim newMre = new ManualResetEventSlim(wasCompleted); + if (Interlocked.CompareExchange(ref m_completionEvent, newMre, null) != null) + { + // We lost the race, so we will just close the event right away. + newMre.Dispose(); + } + else if (!wasCompleted && IsCompleted) + { + // We published the event as unset, but the task has subsequently completed. + // Set the event's state properly so that callers don't deadlock. + newMre.Set(); + } + } + + return m_completionEvent; + } + } + + /// + /// Sets the internal completion event. + /// + private void SetCompleted() + { + + ManualResetEventSlim mres = m_completionEvent; + if (mres != null) + { + mres.Set(); + } + } + + /// + /// Determines whether this is the root task of a self replicating group. + /// + internal bool IsSelfReplicatingRoot + { + get + { + return ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0) && + ((Options & (TaskCreationOptions)InternalTaskOptions.ChildReplica) == 0); + } + } + + /// + /// Determines whether the task is a replica itself. + /// + internal bool IsChildReplica + { + get { return (Options & (TaskCreationOptions)InternalTaskOptions.ChildReplica) != 0; } + } + + internal int ActiveChildCount + { + get { return m_contingentProperties != null ? m_contingentProperties.m_completionCountdown - 1 : 0; } + } + + /// + /// The property formerly known as IsFaulted. + /// + internal bool ExceptionRecorded + { + get { return (m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null); } + } + + /// + /// Gets whether the completed due to an unhandled exception. + /// + /// + /// If is true, the Task's will be equal to + /// TaskStatus.Faulted, and its + /// property will be non-null. + /// + public bool IsFaulted + { + get + { + // Faulted is "king" -- if that bit is present (regardless of other bits), we are faulted. + return ((m_stateFlags & TASK_STATE_FAULTED) != 0); + } + } + + +#if DEBUG + /// + /// Retrieves an identifier for the task. + /// + internal int InternalId + { + get { return GetHashCode(); } + } +#endif + + ///////////// + // methods + + + /// + /// Disposes the , releasing all of its unmanaged resources. + /// + /// + /// Unlike most of the members of , this method is not thread-safe. + /// Also, may only be called on a that is in one of + /// the final states: RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// + /// The exception that is thrown if the is not in + /// one of the final states: RanToCompletion, + /// Faulted, or + /// Canceled. + /// + internal void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes the , releasing all of its unmanaged resources. + /// + /// + /// A Boolean value that indicates whether this method is being called due to a call to . + /// + /// + /// Unlike most of the members of , this method is not thread-safe. + /// + internal virtual void Dispose(bool disposing) + { + if (disposing) + { + // Task must be completed to dispose + if (!IsCompleted) + { + throw new InvalidOperationException(Strings.Task_Dispose_NotCompleted); + } + + var tmp = m_completionEvent; // make a copy to protect against racing Disposes. + + // Dispose of the underlying completion event + if (tmp != null) + { + // In the unlikely event that our completion event is inflated but not yet signaled, + // go ahead and signal the event. If you dispose of an unsignaled MRES, then any waiters + // will deadlock; an ensuing Set() will not wake them up. In the event of an AppDomainUnload, + // there is no guarantee that anyone else is going to signal the event, and it does no harm to + // call Set() twice on m_completionEvent. + if (!tmp.IsSet) tmp.Set(); + + tmp.Dispose(); + m_completionEvent = null; + } + + } + + // We OR the flags to indicate the object has been disposed. This is not + // thread-safe -- trying to dispose while a task is running can lead to corruption. + // Do this regardless of the value of "disposing". + m_stateFlags |= TASK_STATE_DISPOSED; + } + + ///////////// + // internal helpers + + + /// + /// Schedules the task for execution. + /// + /// If true, TASK_STATE_STARTED bit is turned on in + /// an atomic fashion, making sure that TASK_STATE_CANCELED does not get set + /// underneath us. If false, TASK_STATE_STARTED bit is OR-ed right in. This + /// allows us to streamline things a bit for StartNew(), where competing cancellations + /// are not a problem. + internal void ScheduleAndStart(bool needsProtection) + { + Contract.Assert(m_taskScheduler != null, "expected a task scheduler to have been selected"); + Contract.Assert((m_stateFlags & TASK_STATE_STARTED) == 0, "task has already started"); + + // Set the TASK_STATE_STARTED bit + if (needsProtection) + { + if (!MarkStarted()) + { + // A cancel has snuck in before we could get started. Quietly exit. + return; + } + } + else + { + m_stateFlags |= TASK_STATE_STARTED; + } + + try + { + // Queue to the indicated scheduler. + m_taskScheduler.QueueTask(this); + } + catch (Exception e) + { + if (ThreadingServices.IsThreadAbort(e)) + { + AddException(e); + FinishThreadAbortedTask(true, false); + } + else + { + // The scheduler had a problem queueing this task. Record the exception, leaving this task in + // a Faulted state. + TaskSchedulerException tse = new TaskSchedulerException(e); + AddException(tse); + Finish(false); + + // Now we need to mark ourselves as "handled" to avoid crashing the finalizer thread if we are called from StartNew() + // or from the self replicating logic, because in both cases the exception is either propagated outside directly, or added + // to an enclosing parent. However we won't do this for continuation tasks, because in that case we internally eat the exception + // and therefore we need to make sure the user does later observe it explicitly or see it on the finalizer. + + if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) + { + // m_contingentProperties.m_exceptionHolder *should* already exist after AddException() + Contract.Assert((m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null), + "Task.InternalRunSynchronously(): Expected m_contingentProperties.m_exceptionsHolder to exist"); + + m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); + } + + // re-throw the exception wrapped as a TaskSchedulerException. + throw tse; + } + } + } + + + /// + /// Adds an exception to the list of exceptions this task has thrown. + /// + /// An object representing either an Exception or a collection of Exceptions. + internal void AddException(object exceptionObject) + { + // + // WARNING: A great deal of care went into insuring that + // AddException() and GetExceptions() are never called + // simultaneously. See comment at start of GetExceptions(). + // + + // Lazily initialize the list, ensuring only one thread wins. + LazyInitializer.EnsureInitialized(ref m_contingentProperties, s_contingentPropertyCreator); + if (m_contingentProperties.m_exceptionsHolder == null) + { + TaskExceptionHolder holder = new TaskExceptionHolder(this); + if (Interlocked.CompareExchange( + ref m_contingentProperties.m_exceptionsHolder, holder, null) != null) + { + // If we lost the race, suppress finalization. + holder.MarkAsHandled(false); + } + } + + // Figure this out before your enter the lock. + Contract.Assert((exceptionObject is Exception) || (exceptionObject is IEnumerable), + "Task.AddException: Expected an Exception or an IEnumerable"); + + lock (m_contingentProperties) + { + m_contingentProperties.m_exceptionsHolder.Add(exceptionObject); + } + + } + + + /// + /// Returns a list of exceptions by aggregating the holder's contents. Or null if + /// no exceptions have been thrown. + /// + /// Whether to include a TCE if cancelled. + /// An aggregate exception, or null if no exceptions have been caught. + private AggregateException GetExceptions(bool includeTaskCanceledExceptions) + { + // + // WARNING: The Task/Task/TaskCompletionSource classes + // have all been carefully crafted to insure that GetExceptions() + // is never called while AddException() is being called. There + // are locks taken on m_contingentProperties in several places: + // + // -- Task.TrySetException(): The lock allows the + // task to be set to Faulted state, and all exceptions to + // be recorded, in one atomic action. + // + // -- Task.Exception_get(): The lock ensures that Task.TrySetException() + // is allowed to complete its operation before Task.Exception_get() + // can access GetExceptions(). + // + // -- Task.ThrowIfExceptional(): The lock insures that Wait() will + // not attempt to call GetExceptions() while Task.TrySetException() + // is in the process of calling AddException(). + // + // For "regular" tasks, we effectively keep AddException() and GetException() + // from being called concurrently by the way that the state flows. Until + // a Task is marked Faulted, Task.Exception_get() returns null. And + // a Task is not marked Faulted until it and all of its children have + // completed, which means that all exceptions have been recorded. + // + // It might be a lot easier to follow all of this if we just required + // that all calls to GetExceptions() and AddExceptions() were made + // under a lock on m_contingentProperties. But that would also + // increase our lock occupancy time and the frequency with which we + // would need to take the lock. + // + // If you add a call to GetExceptions() anywhere in the code, + // please continue to maintain the invariant that it can't be + // called when AddException() is being called. + // + + // We'll lazily create a TCE if the task has been canceled. + Exception canceledException = null; + if (includeTaskCanceledExceptions && IsCanceled) + { + canceledException = new TaskCanceledException(this); + } + + if (ExceptionRecorded) + { + // There are exceptions; get the aggregate and optionally add the canceled + // exception to the aggregate (if applicable). + Contract.Assert(m_contingentProperties != null); // ExceptionRecorded ==> m_contingentProperties != null + + // No need to lock around this, as other logic prevents the consumption of exceptions + // before they have been completely processed. + return m_contingentProperties.m_exceptionsHolder.CreateExceptionObject(false, canceledException); + } + else if (canceledException != null) + { + // No exceptions, but there was a cancelation. Aggregate and return it. + return new AggregateException(canceledException); + } + + return null; + } + + /// + /// Throws an aggregate exception if the task contains exceptions. + /// + internal void ThrowIfExceptional(bool includeTaskCanceledExceptions) + { + Contract.Assert(IsCompleted, "ThrowIfExceptional(): Expected IsCompleted == true"); + + Exception exception = GetExceptions(includeTaskCanceledExceptions); + if (exception != null) + { + UpdateExceptionObservedStatus(); + throw exception; + } + } + + /// + /// Checks whether this is an attached task, and whether we are being called by the parent task. + /// And sets the TASK_STATE_EXCEPTIONOBSERVEDBYPARENT status flag based on that. + /// + /// This is meant to be used internally when throwing an exception, and when WaitAll is gathering + /// exceptions for tasks it waited on. If this flag gets set, the implicit wait on children + /// will skip exceptions to prevent duplication. + /// + /// This should only be called when this task has completed with an exception + /// + /// + internal void UpdateExceptionObservedStatus() + { + if ((Options & TaskCreationOptions.AttachedToParent) != 0 && + Task.InternalCurrent == m_parent) + { + m_stateFlags |= TASK_STATE_EXCEPTIONOBSERVEDBYPARENT; + } + } + + /// + /// Checks whether the TASK_STATE_EXCEPTIONOBSERVEDBYPARENT status flag is set, + /// This will only be used by the implicit wait to prevent double throws + /// + /// + internal bool IsExceptionObservedByParent + { + get + { + return (m_stateFlags & TASK_STATE_EXCEPTIONOBSERVEDBYPARENT) != 0; + } + } + + /// + /// Checks whether the body was ever invoked. Used by task scheduler code to verify custom schedulers actually ran the task. + /// + internal bool IsDelegateInvoked + { + get + { + return (m_stateFlags & TASK_STATE_DELEGATE_INVOKED) != 0; + } + } + + /// + /// Signals completion of this particular task. + /// + /// The bUserDelegateExecuted parameter indicates whether this Finish() call comes following the + /// full execution of the user delegate. + /// + /// If bUserDelegateExecuted is false, it mean user delegate wasn't invoked at all (either due to + /// a cancellation request, or because this task is a promise style Task). In this case, the steps + /// involving child tasks (i.e. WaitForChildren) will be skipped. + /// + /// + internal void Finish(bool bUserDelegateExecuted) + { + + if (!bUserDelegateExecuted) + { + // delegate didn't execute => no children. We can safely call the remaining finish stages + FinishStageTwo(); + } + else + { + ContingentProperties properties = m_contingentProperties; + + if (properties == null || // no contingent properties, no children. Safe to complete ourselves + (properties.m_completionCountdown == 1 && !IsSelfReplicatingRoot) || + // Count of 1 => either all children finished, or there were none. Safe to complete ourselves + // without paying the price of an Interlocked.Decrement. + // However we need to exclude self replicating root tasks from this optimization, because + // they can have children joining in, or finishing even after the root task delegate is done. + Interlocked.Decrement(ref properties.m_completionCountdown) == 0) // Reaching this sub clause means there may be remaining active children, + // and we could be racing with one of them to call FinishStageTwo(). + // So whoever does the final Interlocked.Dec is responsible to finish. + { + + FinishStageTwo(); + } + else + { + // Apparently some children still remain. It will be up to the last one to process the completion of this task on their own thread. + // We will now yield the thread back to ThreadPool. Mark our state appropriately before getting out. + + // We have to use an atomic update for this and make sure not to overwrite a final state, + // because at this very moment the last child's thread may be concurrently completing us. + // Otherwise we risk overwriting the TASK_STATE_RAN_TO_COMPLETION, _CANCELED or _FAULTED bit which may have been set by that child task. + // Note that the concurrent update by the last child happening in FinishStageTwo could still wipe out the TASK_STATE_WAITING_ON_CHILDREN flag, + // but it is not critical to maintain, therefore we dont' need to intruduce a full atomic update into FinishStageTwo + + AtomicStateUpdate(TASK_STATE_WAITING_ON_CHILDREN, TASK_STATE_FAULTED | TASK_STATE_CANCELED | TASK_STATE_RAN_TO_COMPLETION); + } + } + + // Now is the time to prune exceptional children. We'll walk the list and removes the ones whose exceptions we might have observed after they threw. + // we use a local variable for exceptional children here because some other thread may be nulling out m_contingentProperties.m_exceptionalChildren + List exceptionalChildren = m_contingentProperties != null ? m_contingentProperties.m_exceptionalChildren : null; + + if (exceptionalChildren != null) + { + lock (exceptionalChildren) + { + // RemoveAll is not available in S3 - we have to use our own implementation + //exceptionalChildren.RemoveAll(s_IsExceptionObservedByParentPredicate); // RemoveAll has better performance than doing it ourselves + + List exceptionalChildrenNext = new List(); + foreach (var t in exceptionalChildren) + { + if (!s_IsExceptionObservedByParentPredicate(t)) exceptionalChildrenNext.Add(t); + } + + exceptionalChildren.Clear(); + exceptionalChildren.AddRange(exceptionalChildrenNext); + } + } + } + + // statically allocated delegate for the removeall expression in Finish() + private static Predicate s_IsExceptionObservedByParentPredicate = new Predicate((t) => { return t.IsExceptionObservedByParent; }); + + /// + /// FinishStageTwo is to be executed as soon as we known there are no more children to complete. + /// It can happen i) either on the thread that originally executed this task (if no children were spawned, or they all completed by the time this task's delegate quit) + /// ii) or on the thread that executed the last child. + /// + internal void FinishStageTwo() + { + AddExceptionsFromChildren(); + + // At this point, the task is done executing and waiting for its children, + // we can transition our task to a completion state. + int completionState; + if (ExceptionRecorded) + { + completionState = TASK_STATE_FAULTED; + } + else if (IsCancellationRequested && IsCancellationAcknowledged) + { + // We transition into the TASK_STATE_CANCELED final state if the task's CT was signalled for cancellation, + // and the user delegate acknowledged the cancellation request by throwing an OCE, + // and the task hasn't otherwise transitioned into faulted state. (TASK_STATE_FAULTED trumps TASK_STATE_CANCELED) + // + // If the task threw an OCE without cancellation being requestsed (while the CT not being in signaled state), + // then we regard it as a regular exception + + completionState = TASK_STATE_CANCELED; + } + else + { + completionState = TASK_STATE_RAN_TO_COMPLETION; + } + + // Use Interlocked.Exchange() to effect a memory fence, preventing + // any SetCompleted() (or later) instructions from sneak back before it. + Interlocked.Exchange(ref m_stateFlags, m_stateFlags | completionState); + + // Set the completion event if it's been lazy allocated. + SetCompleted(); + + // if we made a cancellation registration, it's now unnecessary. + DeregisterCancellationCallback(); + + // ready to run continuations and notify parent. + FinishStageThree(); + } + + + /// + /// Final stage of the task completion code path. Notifies the parent (if any) that another of its childre are done, and runs continuations. + /// This function is only separated out from FinishStageTwo because these two operations are also needed to be called from CancellationCleanupLogic() + /// + private void FinishStageThree() + { + // Notify parent if this was an attached task + if (m_parent != null + && (((TaskCreationOptions)(m_stateFlags & OptionsMask)) & TaskCreationOptions.AttachedToParent) != 0) + { + m_parent.ProcessChildCompletion(this); + } + + // Activate continuations (if any). + FinishContinuations(); + + // Need this to bound the memory usage on long/infinite continuation chains + m_action = null; + } + + /// + /// This is called by children of this task when they are completed. + /// + internal void ProcessChildCompletion(Task childTask) + { + Contract.Assert(childTask.m_parent == this, "ProcessChildCompletion should only be called for a child of this task"); + Contract.Assert(childTask.IsCompleted, "ProcessChildCompletion was called for an uncompleted task"); + + // if the child threw and we haven't observed it we need to save it for future reference + if (childTask.IsFaulted && !childTask.IsExceptionObservedByParent) + { + // Lazily initialize the child exception list + if (m_contingentProperties.m_exceptionalChildren == null) + { + Interlocked.CompareExchange(ref m_contingentProperties.m_exceptionalChildren, new List(), null); + } + + // In rare situations involving AppDomainUnload, it's possible (though unlikely) for FinishStageTwo() to be called + // multiple times for the same task. In that case, AddExceptionsFromChildren() could be nulling m_exceptionalChildren + // out at the same time that we're processing it, resulting in a NullReferenceException here. We'll protect + // ourselves by caching m_exceptionChildren in a local variable. + List tmp = m_contingentProperties.m_exceptionalChildren; + if (tmp != null) + { + lock (tmp) + { + tmp.Add(childTask); + } + } + + } + + if (Interlocked.Decrement(ref m_contingentProperties.m_completionCountdown) == 0) + { + // This call came from the final child to complete, and apparently we have previously given up this task's right to complete itself. + // So we need to invoke the final finish stage. + + FinishStageTwo(); + } + } + + /// + /// This is to be called just before the task does its final state transition. + /// It traverses the list of exceptional children, and appends their aggregate exceptions into this one's exception list + /// + internal void AddExceptionsFromChildren() + { + // In rare occurences during AppDomainUnload() processing, it is possible for this method to be called + // simultaneously on the same task from two different contexts. This can result in m_exceptionalChildren + // being nulled out while it is being processed, which could lead to a NullReferenceException. To + // protect ourselves, we'll cache m_exceptionalChildren in a local variable. + List tmp = (m_contingentProperties != null) ? m_contingentProperties.m_exceptionalChildren : null; + + if (tmp != null) + { + // This lock is necessary because even though AddExceptionsFromChildren is last to execute, it may still + // be racing with the code segment at the bottom of Finish() that prunes the exceptional child array. + lock (tmp) + { + foreach (Task task in tmp) + { + // Ensure any exceptions thrown by children are added to the parent. + // In doing this, we are implicitly marking children as being "handled". + Contract.Assert(task.IsCompleted, "Expected all tasks in list to be completed"); + if (task.IsFaulted && !task.IsExceptionObservedByParent) + { + TaskExceptionHolder exceptionHolder = task.m_contingentProperties.m_exceptionsHolder; + Contract.Assert(exceptionHolder != null); + + // No locking necessary since child task is finished adding exceptions + // and concurrent CreateExceptionObject() calls do not constitute + // a concurrency hazard. + AddException(exceptionHolder.CreateExceptionObject(false, null)); + } + } + } + + // Reduce memory pressure by getting rid of the array + m_contingentProperties.m_exceptionalChildren = null; + } + } + + /// + /// Special purpose Finish() entry point to be used when the task delegate throws a ThreadAbortedException + /// This makes a note in the state flags so that we avoid any costly synchronous operations in the finish codepath + /// such as inlined continuations + /// + /// + /// Indicates whether the ThreadAbortException was added to this task's exception holder. + /// This should always be true except for the case of non-root self replicating task copies. + /// + /// Whether the delegate was executed. + internal void FinishThreadAbortedTask(bool bTAEAddedToExceptionHolder, bool delegateRan) + { + Contract.Assert(!bTAEAddedToExceptionHolder || (m_contingentProperties != null && m_contingentProperties.m_exceptionsHolder != null), + "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized"); + + // this will only be false for non-root self replicating task copies, because all of their exceptions go to the root task. + if (bTAEAddedToExceptionHolder) + m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); + + // If this method has already been called for this task, or if this task has already completed, then + // return before actually calling Finish(). + if (!AtomicStateUpdate(TASK_STATE_THREAD_WAS_ABORTED, + TASK_STATE_THREAD_WAS_ABORTED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) + { + return; + } + + Finish(delegateRan); + + } + + + /// + /// Executes the task. This method will only be called once, and handles bookeeping associated with + /// self-replicating tasks, in addition to performing necessary exception marshaling. + /// + /// The task has already been disposed. + private void Execute() + { + if (IsSelfReplicatingRoot) + { + ExecuteSelfReplicating(this); + } + else + { + try + { + InnerInvoke(); + } + + catch (Exception exn) + { + if (ThreadingServices.IsThreadAbort(exn)) + { + // Don't record the TAE or call FinishThreadAbortedTask for a child replica task -- + // it's already been done downstream. + if (!IsChildReplica) + { + // Record this exception in the task's exception list + HandleException(exn); + + // This is a ThreadAbortException and it will be rethrown from this catch clause, causing us to + // skip the regular Finish codepath. In order not to leave the task unfinished, we now call + // FinishThreadAbortedTask here. + FinishThreadAbortedTask(true, true); + } + } + else + { + // Record this exception in the task's exception list + HandleException(exn); + } + } + } + } + + // Allows (internal) deriving classes to support limited replication. + // (By default, replication is basically unlimited). + internal virtual bool ShouldReplicate() + { + return true; + } + + // Allows (internal) deriving classes to instantiate the task replica as a Task super class of their choice + // (By default, we create a regular Task instance) + internal virtual Task CreateReplicaTask(Action taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler, + TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica) + { + return new Task(taskReplicaDelegate, stateObject, parentTask, CancellationToken.None, + creationOptionsForReplica, internalOptionsForReplica, parentTask.ExecutingTaskScheduler); + } + + // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica + internal virtual Object SavedStateForNextReplica + { + get { return null; } + + set { /*do nothing*/ } + } + + // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica + internal virtual Object SavedStateFromPreviousReplica + { + get { return null; } + + set { /*do nothing*/ } + } + + // Allows internal deriving classes to support replicas that exit prematurely and want to hand over the child replica that they + // had queued, so that the replacement replica can work with that child task instead of queuing up yet another one + internal virtual Task HandedOverChildReplica + { + get { return null; } + + set { /* do nothing*/ } + } + + private static void ExecuteSelfReplicating(Task root) + { + TaskCreationOptions creationOptionsForReplicas = root.CreationOptions | TaskCreationOptions.AttachedToParent; + InternalTaskOptions internalOptionsForReplicas = + InternalTaskOptions.ChildReplica | // child replica flag disables self replication for the replicas themselves. + InternalTaskOptions.SelfReplicating | // we still want to identify this as part of a self replicating group + InternalTaskOptions.QueuedByRuntime; // we queue and cancel these tasks internally, so don't allow CT registration to take place + + + // Important Note: The child replicas we launch from here will be attached the root replica (by virtue of the root.CreateReplicaTask call) + // because we need the root task to receive all their exceptions, and to block until all of them return + + + // This variable is captured in a closure and shared among all replicas. + bool replicasAreQuitting = false; + + // Set up a delegate that will form the body of the root and all recursively created replicas. + Action taskReplicaDelegate = null; + taskReplicaDelegate = delegate + { + Task currentTask = Task.InternalCurrent; + + + // Check if a child task has been handed over by a prematurely quiting replica that we might be a replacement for. + Task childTask = currentTask.HandedOverChildReplica; + + if (childTask == null) + { + // Apparently we are not a replacement task. This means we need to queue up a child task for replication to progress + + // Down-counts a counter in the root task. + if (!root.ShouldReplicate()) return; + + // If any of the replicas have quit, we will do so ourselves. + if (replicasAreQuitting) + { + return; + } + + // Propagate a copy of the context from the root task. It may be null if flow was suppressed. + ExecutionContextLightup creatorContext = root.m_capturedContext; + + + childTask = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler, + creationOptionsForReplicas, internalOptionsForReplicas); + + childTask.m_capturedContext = (creatorContext == null ? null : creatorContext.CreateCopy()); + + childTask.ScheduleAndStart(false); + } + + + + // Finally invoke the meat of the task. + // Note that we are directly calling root.InnerInvoke() even though we are currently be in the action delegate of a child replica + // This is because the actual work was passed down in that delegate, and the action delegate of the child replica simply contains this + // replication control logic. + try + { + // passing in currentTask only so that the parallel debugger can find it + root.InnerInvokeWithArg(currentTask); + } + catch (Exception exn) + { + // Record this exception in the root task's exception list + root.HandleException(exn); + + if (ThreadingServices.IsThreadAbort(exn)) + { + // If this is a ThreadAbortException it will escape this catch clause, causing us to skip the regular Finish codepath + // In order not to leave the task unfinished, we now call FinishThreadAbortedTask here + currentTask.FinishThreadAbortedTask(false, true); + } + } + + Object savedState = currentTask.SavedStateForNextReplica; + + // check for premature exit + if (savedState != null) + { + // the replica decided to exit early + // we need to queue up a replacement, attach the saved state, and yield the thread right away + + Task replacementReplica = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler, + creationOptionsForReplicas, internalOptionsForReplicas); + + // Propagate a copy of the context from the root task to the replacement task + ExecutionContextLightup creatorContext = root.m_capturedContext; + replacementReplica.m_capturedContext = (creatorContext == null ? null : creatorContext.CreateCopy()); + + replacementReplica.HandedOverChildReplica = childTask; + replacementReplica.SavedStateFromPreviousReplica = savedState; + + replacementReplica.ScheduleAndStart(false); + } + else + { + // The replica finished normally, which means it can't find more work to grab. + // Time to mark replicas quitting + + replicasAreQuitting = true; + + // InternalCancel() could conceivably throw in the underlying scheduler's TryDequeue() method. + // If it does, then make sure that we record it. + try + { + childTask.InternalCancel(true); + } + catch (Exception e) + { + // Apparently TryDequeue threw an exception. Before propagating that exception, InternalCancel should have + // attempted an atomic state transition and a call to CancellationCleanupLogic() on this task. So we know + // the task was properly cleaned up if it was possible. + // + // Now all we need to do is to Record the exception in the root task. + + root.HandleException(e); + } + + // No specific action needed if the child could not be canceled + // because we attached it to the root task, which should therefore be receiving any exceptions from the child, + // and root.wait will not return before this child finishes anyway. + + } + }; + + // + // Now we execute as the root task + // + taskReplicaDelegate(null); + } + + /// + /// IThreadPoolWorkItem override, which is the entry function for this task when the TP scheduler decides to run it. + /// + /// + // [SecurityCritical] + void IThreadPoolWorkItem.ExecuteWorkItem() + { + ExecuteEntry(false); + } + + ///// + ///// The ThreadPool calls this if a ThreadAbortException is thrown while trying to execute this workitem. This may occur + ///// before Task would otherwise be able to observe it. + ///// + //[SecurityCritical] + //void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) + //{ + // // If the task has marked itself as Completed, then it either a) already observed this exception (so we shouldn't handle it here) + // // or b) completed before the exception ocurred (in which case it shouldn't count against this Task). + // if (!IsCompleted) + // { + // HandleException(tae); + // FinishThreadAbortedTask(true, false); + // } + //} + + /// + /// Outermost entry function to execute this task. Handles all aspects of executing a task on the caller thread. + /// Currently this is called by IThreadPoolWorkItem.ExecuteWorkItem(), and TaskManager.TryExecuteInline. + /// + /// + /// Performs atomic updates to prevent double execution. Should only be set to true + /// in codepaths servicing user provided TaskSchedulers. The ConcRT or ThreadPool schedulers don't need this. + // // [SecuritySafeCritical] + internal bool ExecuteEntry(bool bPreventDoubleExecution) + { + if (bPreventDoubleExecution || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0)) + { + int previousState = 0; + + // Do atomic state transition from queued to invoked. If we observe a task that's already invoked, + // we will return false so that TaskScheduler.ExecuteTask can throw an exception back to the custom scheduler. + // However we don't want this exception to be throw if the task was already canceled, because it's a + // legitimate scenario for custom schedulers to dequeue a task and mark it as canceled (example: throttling scheduler) + if (!AtomicStateUpdate(TASK_STATE_DELEGATE_INVOKED, TASK_STATE_DELEGATE_INVOKED, ref previousState) + && (previousState & TASK_STATE_CANCELED) == 0) + { + // This task has already been invoked. Don't invoke it again. + return false; + } + } + else + { + // Remember that we started running the task delegate. + m_stateFlags |= TASK_STATE_DELEGATE_INVOKED; + } + + if (!IsCancellationRequested && !IsCanceled) + { + ExecuteWithThreadLocal(); + } + else if (!IsCanceled) + { + int prevState = Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED); + if ((prevState & TASK_STATE_CANCELED) == 0) + { + CancellationCleanupLogic(); + } + } + + return true; + } + + // A trick so we can refer to the TLS slot with a byref. + // [SecurityCritical] + private void ExecuteWithThreadLocal() + { + // Remember the current task so we can restore it after running, and then + Task previousTask = ThreadLocals.s_currentTask.Value; + +#if ETW_EVENTING // PAL doesn't support eventing + // ETW event for Task Started + if (TplEtwProvider.Log.IsEnabled(EventLevel.Verbose, ((EventKeywords)(-1)))) + { + // previousTask holds the actual "current task" we want to report in the event + if (previousTask != null) + TplEtwProvider.Log.TaskStarted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id); + else + TplEtwProvider.Log.TaskStarted(TaskScheduler.Current.Id, 0, this.Id); + } +#endif + + try + { + // place the current task into TLS. + ThreadLocals.s_currentTask.Value = this; + + if (m_capturedContext == null) + { + // No context, just run the task directly. + Execute(); + } + else + { + if (IsSelfReplicatingRoot || IsChildReplica) + { + m_capturedContext = m_capturedContext.CreateCopy(); + } + + // Run the task. We need a simple shim that converts the + // object back into a Task object, so that we can Execute it. +//#if PFX_LEGACY_3_5 +// s_ecCallback(this); +//#else + ExecutionContextLightup.Instance.Run(m_capturedContext, s_ecCallback, this); +//#endif + } + + Finish(true); + } + finally + { + ThreadLocals.s_currentTask.Value = previousTask; + } + +#if ETW_EVENTING // PAL doesn't support eventing + // ETW event for Task Completed + if (TplEtwProvider.Log.IsEnabled(EventLevel.Verbose, ((EventKeywords)(-1)))) + { + // previousTask holds the actual "current task" we want to report in the event + if (previousTask != null) + TplEtwProvider.Log.TaskCompleted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id, IsFaulted); + else + TplEtwProvider.Log.TaskCompleted(TaskScheduler.Current.Id, 0, this.Id, IsFaulted); + } +#endif + } + + // [SecurityCritical] + private static Action s_ecCallback; + + // [SecurityCritical] + private static void ExecutionContextCallback(object obj) + { + Task task = obj as Task; + Contract.Assert(task != null, "expected a task object"); + + task.Execute(); + + } + + + /// + /// The actual code which invokes the body of the task. This can be overriden in derived types. + /// + internal void InnerInvoke() + { + Contract.Assert(m_action != null, "Null action in InnerInvoke()"); + + Action funcA = m_action as Action; + if (funcA != null) + { + funcA(); + } + else + { + Action funcB = m_action as Action; + funcB(m_stateObject); + } + } + + /// + /// Alternate InnerInvoke prototype to be called from ExecuteSelfReplicating() so that + /// the Parallel Debugger can discover the actual task being invoked. + /// Details: Here, InnerInvoke is actually being called on the rootTask object while we are actually executing the + /// childTask. And the debugger needs to discover the childTask, so we pass that down as an argument. + /// The NoOptimization and NoInlining flags ensure that the childTask pointer is retained, and that this + /// function appears on the callstack. + /// + /// + [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] + internal void InnerInvokeWithArg(Task childTask) + { + InnerInvoke(); + } + + /// + /// Performs whatever handling is necessary for an unhandled exception. Normally + /// this just entails adding the exception to the holder object. + /// + /// The exception that went unhandled. + private void HandleException(Exception unhandledException) + { + Contract.Assert(unhandledException != null); + + OperationCanceledException exceptionAsOce = unhandledException as OperationCanceledException; + if (exceptionAsOce != null && IsCancellationRequested && + m_contingentProperties.m_cancellationToken == exceptionAsOce.CancellationToken) + { + // All conditions are satisfied for us to go into canceled state in Finish(). + // Mark the acknowledgement, and return without adding the exception. + // + // However any OCE from the task that doesn't match the tasks' own CT, + // or that gets thrown without the CT being set will be treated as an ordinary exception and added to the aggreagate + + SetCancellationAcknowledged(); + } + else + { + + AddException(unhandledException); + } + } + + /// + /// Waits for the to complete execution. + /// + /// + /// The was canceled -or- an exception was thrown during + /// the execution of the . + /// + /// + /// The has been disposed. + /// + public void Wait() + { +#if DEBUG + bool waitResult = +#endif + Wait(Timeout.Infinite, CancellationToken.None); + +#if DEBUG + Contract.Assert(waitResult, "expected wait to succeed"); +#endif + } + + /// + /// Waits for the to complete execution. + /// + /// + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// + /// + /// true if the completed execution within the allotted time; otherwise, false. + /// + /// + /// The was canceled -or- an exception was thrown during the execution of the . + /// + /// + /// is a negative number other than -1 milliseconds, which represents an + /// infinite time-out -or- timeout is greater than + /// . + /// + /// + /// The has been disposed. + /// + public bool Wait(TimeSpan timeout) + { + long totalMilliseconds = (long)timeout.TotalMilliseconds; + if (totalMilliseconds < -1 || totalMilliseconds > 0x7fffffff) + { + throw new ArgumentOutOfRangeException("timeout"); + } + + return Wait((int)totalMilliseconds, CancellationToken.None); + } + + + /// + /// Waits for the to complete execution. + /// + /// + /// A to observe while waiting for the task to complete. + /// + /// + /// The was canceled. + /// + /// + /// The was canceled -or- an exception was thrown during the execution of the . + /// + /// + /// The + /// has been disposed. + /// + public void Wait(CancellationToken cancellationToken) + { + Wait(Timeout.Infinite, cancellationToken); + } + + + /// + /// Waits for the to complete execution. + /// + /// + /// The number of milliseconds to wait, or (-1) to + /// wait indefinitely. + /// true if the completed execution within the allotted time; otherwise, + /// false. + /// + /// + /// is a negative number other than -1, which represents an + /// infinite time-out. + /// + /// + /// The was canceled -or- an exception was thrown during the execution of the . + /// + /// + /// The + /// has been disposed. + /// + public bool Wait(int millisecondsTimeout) + { + return Wait(millisecondsTimeout, CancellationToken.None); + } + + + /// + /// Waits for the to complete execution. + /// + /// + /// The number of milliseconds to wait, or (-1) to + /// wait indefinitely. + /// + /// + /// A to observe while waiting for the task to complete. + /// + /// + /// true if the completed execution within the allotted time; otherwise, false. + /// + /// + /// The was canceled -or- an exception was thrown during the execution of the . + /// + /// + /// The + /// has been disposed. + /// + /// + /// is a negative number other than -1, which represents an + /// infinite time-out. + /// + /// + /// The was canceled. + /// + public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) + { + //ThrowIfDisposed(); + + if (millisecondsTimeout < -1) + { + throw new ArgumentOutOfRangeException("millisecondsTimeout"); + } + + // Return immediately if we know that we've completed "clean" -- no exceptions, no cancellations + if (CompletedSuccessfully) return true; + + if (!InternalWait(millisecondsTimeout, cancellationToken)) + return false; + + // If an exception occurred, or the task was cancelled, throw an exception. + ThrowIfExceptional(true); + + Contract.Assert((m_stateFlags & TASK_STATE_FAULTED) == 0, "Task.Wait() completing when in Faulted state."); + + return true; + } + + // Convenience method that wraps any scheduler exception in a TaskSchedulerException + // and rethrows it. + private bool WrappedTryRunInline() + { + if (m_taskScheduler == null) + return false; + + try + { + return m_taskScheduler.TryRunInline(this, true); + } + catch (Exception e) + { + // we 1) either received an unexpected exception originating from a custom scheduler, which needs to be wrapped in a TSE and thrown + // 2) or a a ThreadAbortException, which we need to skip here, because it would already have been handled in Task.Execute + if (!(ThreadingServices.IsThreadAbort(e))) + { + TaskSchedulerException tse = new TaskSchedulerException(e); + throw tse; + } + else + { + throw; + } + } + } + + // This overload takes advantage of known values for current scheduler & statics. + // It looks a LOT like the version above, but perf considerations prevented me + // from having the one above call this one. + private bool WrappedTryRunInline(TaskScheduler currentScheduler, object currentSchedulerStatics) + { + if (m_taskScheduler == null) + return false; + + try + { + if (currentScheduler == m_taskScheduler) + { + return currentScheduler.TryRunInline(this, true, currentSchedulerStatics); + } + else + { + return m_taskScheduler.TryRunInline(this, true); + } + } + catch (Exception e) + { + // we 1) either received an unexpected exception originating from a custom scheduler, which needs to be wrapped in a TSE and thrown + // 2) or a a ThreadAbortException, which we need to skip here, because it would already have been handled in Task.Execute + if (!(ThreadingServices.IsThreadAbort(e))) + { + TaskSchedulerException tse = new TaskSchedulerException(e); + throw tse; + } + else + { + throw; + } + } + } + + /// + /// The core wait function, which is only accesible internally. It's meant to be used in places in TPL code where + /// the current context is known or cached. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + internal bool InternalWait(int millisecondsTimeout, CancellationToken cancellationToken) + { +#if ETW_EVENTING // PAL doesn't support eventing + // ETW event for Task Wait Begin + if (TplEtwProvider.Log.IsEnabled(EventLevel.Verbose, ((EventKeywords)(-1)))) + { + Task currentTask = Task.InternalCurrent; + TplEtwProvider.Log.TaskWaitBegin((currentTask != null ? currentTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentTask != null ? currentTask.Id : 0), + this.Id); + } +#endif + + bool returnValue = IsCompleted; + + // If the event hasn't already been set, we will wait. + if (!returnValue) + { + // + // we will attempt inline execution only if an infinite wait was requested + // Inline execution doesn't make sense for finite timeouts and if a cancellation token was specified + // because we don't know how long the task delegate will take. + // + TaskScheduler tm = m_taskScheduler; + if (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled && + WrappedTryRunInline() && IsCompleted) // TryRunInline doesn't guarantee completion, as there may be unfinished children. + { + returnValue = true; + } + else + { + returnValue = CompletedEvent.Wait(millisecondsTimeout, cancellationToken); + } + } + + Contract.Assert(IsCompleted || millisecondsTimeout != Timeout.Infinite); + +#if ETW_EVENTING // PAL doesn't support eventing + // ETW event for Task Wait End + if (TplEtwProvider.Log.IsEnabled(EventLevel.Verbose, ((EventKeywords)(-1)))) + { + Task currentTask = Task.InternalCurrent; + TplEtwProvider.Log.TaskWaitEnd((currentTask != null ? currentTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentTask != null ? currentTask.Id : 0), + this.Id); + } +#endif + + return returnValue; + } + + + /// + /// Cancels the . + /// + /// Indiactes whether we should only cancel non-invoked tasks. + /// For the default scheduler this option will only be serviced through TryDequeue. + /// For custom schedulers we also attempt an atomic state transition. + /// true if the task was successfully canceled; otherwise, false. + /// The + /// has been disposed. + internal bool InternalCancel(bool bCancelNonExecutingOnly) + { + Contract.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) == 0, "Task.InternalCancel() did not expect promise-style task"); + //ThrowIfDisposed(); + + bool bPopSucceeded = false; + bool mustCleanup = false; + + TaskSchedulerException tse = null; + + // If started, and running in a task context, we can try to pop the chore. + if ((m_stateFlags & TASK_STATE_STARTED) != 0) + { + TaskScheduler ts = m_taskScheduler; + + try + { + bPopSucceeded = (ts != null) && ts.TryDequeue(this); + } + catch (Exception e) + { + // TryDequeue threw. We don't know whether the task was properly dequeued or not. So we must let the rest of + // the cancellation logic run its course (record the request, attempt atomic state transition and do cleanup where appropriate) + // Here we will only record a TaskSchedulerException, which will later be thrown at function exit. + + if (!(ThreadingServices.IsThreadAbort(e))) + { + tse = new TaskSchedulerException(e); + } + } + + bool bRequiresAtomicStartTransition = (ts != null && ts.RequiresAtomicStartTransition) || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0); + + if (!bPopSucceeded && bCancelNonExecutingOnly && bRequiresAtomicStartTransition) + { + // The caller requested cancellation of non-invoked tasks only, and TryDequeue was one way of doing it... + // Since that seems to have failed, we should now try an atomic state transition (from non-invoked state to canceled) + // An atomic transition here is only safe if we know we're on a custom task scheduler, which also forces a CAS on ExecuteEntry + + // Even though this task can't have any children, we should be ready for handling any continuations that + // may be attached to it (although currently + // So we need to remeber whether we actually did the flip, so we can do clean up (finish continuations etc) + mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_DELEGATE_INVOKED | TASK_STATE_CANCELED); + + + // PS: This is slightly different from the regular cancellation codepath + // since we record the cancellation request *after* doing the state transition. + // However that shouldn't matter too much because the task was never invoked, thus can't have children + } + + } + + if (!bCancelNonExecutingOnly || bPopSucceeded || mustCleanup) + { + // Record the cancellation request. + RecordInternalCancellationRequest(); + + // Determine whether we need to clean up + // This will be the case + // 1) if we were able to pop, and we win the race to update task state to TASK_STATE_CANCELED + // 2) if the task seems to be yet unstarted, and we win the race to transition to + // TASK_STATE_CANCELED before anyone else can transition into _STARTED or _CANCELED or + // _RAN_TO_COMPLETION or _FAULTED + // Note that we do not check for TASK_STATE_COMPLETION_RESERVED. That only applies to promise-style + // tasks, and a promise-style task should not enter into this codepath. + if (bPopSucceeded) + { + // hitting this would mean something wrong with the AtomicStateUpdate above + Contract.Assert(!mustCleanup, "Possibly an invalid state transition call was made in InternalCancel()"); + + // Include TASK_STATE_DELEGATE_INVOKED in "illegal" bits to protect against the situation where + // TS.TryDequeue() returns true but the task is still left on the queue. + mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_CANCELED | TASK_STATE_DELEGATE_INVOKED); + } + else if (!mustCleanup && (m_stateFlags & TASK_STATE_STARTED) == 0) + { + mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, + TASK_STATE_CANCELED | TASK_STATE_STARTED | TASK_STATE_RAN_TO_COMPLETION | + TASK_STATE_FAULTED | TASK_STATE_DELEGATE_INVOKED); + } + + // do the cleanup (i.e. set completion event and finish continuations) + if (mustCleanup) + { + CancellationCleanupLogic(); + } + } + + if (tse != null) + throw tse; + else + return (mustCleanup); + } + + // Breaks out logic for recording a cancellation request + internal void RecordInternalCancellationRequest() + { + // Record the cancellation request. + LazyInitializer.EnsureInitialized(ref m_contingentProperties, s_contingentPropertyCreator); + + m_contingentProperties.m_internalCancellationRequested = CANCELLATION_REQUESTED; + + } + + // ASSUMES THAT A SUCCESSFUL CANCELLATION HAS JUST OCCURRED ON THIS TASK!!! + // And this method should be called at most once per task. + internal void CancellationCleanupLogic() + { + Contract.Assert((m_stateFlags & (TASK_STATE_CANCELED | TASK_STATE_COMPLETION_RESERVED)) != 0, "Task.CancellationCleanupLogic(): Task not canceled or reserved."); + // I'd like to do this, but there is a small window for a race condition. If someone calls Wait() between InternalCancel() and + // here, that will set m_completionEvent, leading to a meaningless/harmless assertion. + //Contract.Assert((m_completionEvent == null) || !m_completionEvent.IsSet, "Task.CancellationCleanupLogic(): Completion event already set."); + + // This may have been set already, but we need to make sure. + Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED); + + // Fire completion event if it has been lazily initialized + SetCompleted(); + + // Notify parents, fire continuations, other cleanup. + FinishStageThree(); + } + + + /// + /// Sets the task's cancellation acknowledged flag. + /// + private void SetCancellationAcknowledged() + { + Contract.Assert(this == Task.InternalCurrent, "SetCancellationAcknowledged() should only be called while this is still the current task"); + Contract.Assert(IsCancellationRequested, "SetCancellationAcknowledged() should not be called if the task's CT wasn't signaled"); + + m_stateFlags |= TASK_STATE_CANCELLATIONACKNOWLEDGED; + } + + + // + // Continuation passing functionality (aka ContinueWith) + // + + /// + /// A structure to hold continuation information. + /// + internal struct TaskContinuation + { + internal object m_task; // The delegate OR unstarted continuation task. + internal TaskScheduler m_taskScheduler; // The TaskScheduler with which to associate the continuation task. + internal TaskContinuationOptions m_options; // What kind of continuation. + + /// + /// Constructs a new continuation structure. + /// + /// The task to be activated. + /// The continuation options. + /// The scheduler to use for the continuation. + internal TaskContinuation(Task task, TaskScheduler scheduler, TaskContinuationOptions options) + { + Contract.Assert(task != null, "TaskContinuation ctor: task is null"); + + m_task = task; + m_taskScheduler = scheduler; + m_options = options; + } + + internal TaskContinuation(Action action) + { + m_task = action; + m_taskScheduler = null; + m_options = TaskContinuationOptions.None; + } + + /// + /// Invokes the continuation for the target completion task. + /// + /// The completed task. + /// Whether the continuation can be inlined. + internal void Run(Task completedTask, bool bCanInlineContinuationTask) + { + Contract.Assert(completedTask.IsCompleted, "ContinuationTask.Run(): completedTask not completed"); + + Task task = m_task as Task; + if (task != null) + { + if (completedTask.ContinueWithIsRightKind(m_options)) + { + task.m_taskScheduler = m_taskScheduler; + + // Either run directly or just queue it up for execution, depending + // on whether synchronous or asynchronous execution is wanted. + if (bCanInlineContinuationTask && (m_options & TaskContinuationOptions.ExecuteSynchronously) != 0) + { + // Execute() won't set the TASK_STATE_STARTED flag, so we'll do it here. + if (!task.MarkStarted()) + { + // task has been canceled. Abort this continuation thread. + return; + } + + try + { + if (!m_taskScheduler.TryRunInline(task, false)) + { + m_taskScheduler.QueueTask(task); + } + } + catch (Exception e) + { + // Either TryRunInline() or QueueTask() threw an exception. Record the exception, marking the task as Faulted. + // However if it was a ThreadAbortException coming from TryRunInline we need to skip here, + // because it would already have been handled in Task.Execute() + if (!(ThreadingServices.IsThreadAbort(e) && + (task.m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0)) // this ensures TAEs from QueueTask will be wrapped in TSE + { + TaskSchedulerException tse = new TaskSchedulerException(e); + task.AddException(tse); + task.Finish(false); + } + + // Don't re-throw. + } + } + else + { + try + { + task.ScheduleAndStart(true); + } + catch (TaskSchedulerException) + { + // No further action is necessary -- ScheduleAndStart() already transitioned + // the task to faulted. But we want to make sure that no exception is thrown + // from here. + } + } + } + else + { + // The final state of this task does not match the desired + // continuation activation criteria; cancel it to denote this. + task.InternalCancel(false); + } + } + else + { + // Note for the future: ContinuationAction still run synchronously regardless of ThreadAbortException handling. + // This is probably not too importnat right now, because the internal use of continuationActions only involve short actions. + // However if we ever make these public, we need to turn them into tasks if the antecedent threw a ThreadAbortException. + Action action = m_task as Action; + Contract.Assert(action != null, "TaskContinuation.Run(): Unknown m_task type."); + action(completedTask); + } + } + } + + /// + /// Runs all of the continuations, as appropriate. + /// + private void FinishContinuations() + { + // Grab the list of continuations, and lock it to contend with concurrent adds. + // At this point, IsCompleted == true, so those adding will either come before + // that and add a continuation under the lock (serializing before this), so we + // will run it; or they will attempt to acquire the lock, get it, and then see the + // task is completed (serializing after this), and run it on their own. + List continuations = (m_contingentProperties == null) ? null : m_contingentProperties.m_continuations; + if (continuations != null) + { + lock (m_contingentProperties) + { + // Ensure that all concurrent adds have completed. + } + + // skip synchronous execution of continuations if this tasks thread was aborted + bool bCanInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) || + (ThreadLightup.Current.ThreadState == ThreadState.AbortRequested)); + + // Records earliest index of synchronous continuation. + // A value of -1 means that no synchronous continuations were found. + int firstSynchronousContinuation = -1; + + // Fire the asynchronous continuations first ... + // Go back-to-front to make the "firstSynchronousContinuation" logic simpler. + for (int i = continuations.Count - 1; i >= 0; i--) + { + TaskContinuation tc = continuations[i]; + // ContinuationActions, which execute synchronously, have a null scheduler + // Synchronous continuation tasks will have the ExecuteSynchronously option + if ((tc.m_taskScheduler != null) && ((tc.m_options & TaskContinuationOptions.ExecuteSynchronously) == 0)) + { + tc.Run(this, bCanInlineContinuations); + } + else firstSynchronousContinuation = i; + } + + // ... and then fire the synchronous continuations (if there are any) + if (firstSynchronousContinuation > -1) + { + for (int i = firstSynchronousContinuation; i < continuations.Count; i++) + { + TaskContinuation tc = continuations[i]; + // ContinuationActions, which execute synchronously, have a null scheduler + // Synchronous continuation tasks will have the ExecuteSynchronously option + if ((tc.m_taskScheduler == null) || ((tc.m_options & TaskContinuationOptions.ExecuteSynchronously) != 0)) + tc.Run(this, bCanInlineContinuations); + } + } + + // Don't keep references to "spent" continuations + m_contingentProperties.m_continuations = null; + } + } + + /// + /// Helper function to determine whether the current task is in the state desired by the + /// continuation kind under evaluation. Three possibilities exist: the task failed with + /// an unhandled exception (OnFailed), the task was canceled before running (OnAborted), + /// or the task completed successfully (OnCompletedSuccessfully). Note that the last + /// one includes completing due to cancellation. + /// + /// The continuation options under evaluation. + /// True if the continuation should be run given the task's current state. + internal bool ContinueWithIsRightKind(TaskContinuationOptions options) + { + Contract.Assert(IsCompleted); + + if (IsFaulted) + { + return (options & TaskContinuationOptions.NotOnFaulted) == 0; + } + else if (IsCanceled) + { + return (options & TaskContinuationOptions.NotOnCanceled) == 0; + } + else + { + return (options & TaskContinuationOptions.NotOnRanToCompletion) == 0; + } + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action continuationAction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, TaskScheduler.Current, CancellationToken.None, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// The that will be assigned to the new continuation task. + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action continuationAction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// The to associate with the continuation task and to use for its execution. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action continuationAction, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, scheduler, CancellationToken.None, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled + /// instead of scheduled. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action continuationAction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, TaskScheduler.Current, CancellationToken.None, continuationOptions, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// The that will be assigned to the new continuation task. + /// + /// The to associate with the continuation task and to use for its + /// execution. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed. If the criteria specified through the parameter + /// are not met, the continuation task will be canceled instead of scheduled. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action continuationAction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark); + } + + // Same as the above overload, just with a stack mark parameter. + private Task ContinueWith(Action continuationAction, TaskScheduler scheduler, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) + { + //ThrowIfDisposed(); + + // Throw on continuation with null action + if (continuationAction == null) + { + throw new ArgumentNullException("continuationAction"); + } + + // Throw on continuation with null TaskScheduler + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + TaskCreationOptions creationOptions; + InternalTaskOptions internalOptions; + CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); + + Task thisTask = this; + Task continuationTask = new Task( + delegate(object obj) { continuationAction(thisTask); }, + null, + Task.InternalCurrent, + cancellationToken, + creationOptions, + internalOptions, + null, // leave taskScheduler null until TaskContinuation.Run() is called + ref stackMark + ); + + // Register the continuation. If synchronous execution is requested, this may + // actually invoke the continuation before returning. + ContinueWithCore(continuationTask, scheduler, continuationOptions); + + return continuationTask; + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, TaskScheduler.Current, CancellationToken.None, + TaskContinuationOptions.None, ref stackMark); + } + + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// The that will be assigned to the new continuation task. + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func continuationFunction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// The to associate with the continuation task and to use for its execution. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func continuationFunction, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, scheduler, CancellationToken.None, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled + /// instead of scheduled. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func continuationFunction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, TaskScheduler.Current, CancellationToken.None, continuationOptions, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// The that will be assigned to the new continuation task. + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// + /// The to associate with the continuation task and to use for its + /// execution. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed. If the criteria specified through the parameter + /// are not met, the continuation task will be canceled instead of scheduled. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func continuationFunction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark); + } + + // Same as the above overload, just with a stack mark parameter. + private Task ContinueWith(Func continuationFunction, TaskScheduler scheduler, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) + { + //ThrowIfDisposed(); + + // Throw on continuation with null function + if (continuationFunction == null) + { + throw new ArgumentNullException("continuationFunction"); + } + + // Throw on continuation with null task scheduler + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + TaskCreationOptions creationOptions; + InternalTaskOptions internalOptions; + CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); + + Task thisTask = this; + Task continuationTask = new Task( + delegate() { return continuationFunction(thisTask); }, + Task.InternalCurrent, + cancellationToken, + creationOptions, + internalOptions, + null, // leave taskScheduler null until TaskContinuation.Run() is called + ref stackMark + ); + + // Register the continuation. If synchronous execution is requested, this may + // actually invoke the continuation before returning. + ContinueWithCore(continuationTask, scheduler, continuationOptions); + + return continuationTask; + } + + /// + /// Converts TaskContinuationOptions to TaskCreationOptions, and also does + /// some validity checking along the way. + /// + /// Incoming TaskContinuationOptions + /// Outgoing TaskCreationOptions + /// Outgoing InternalTaskOptions + internal static void CreationOptionsFromContinuationOptions( + TaskContinuationOptions continuationOptions, + out TaskCreationOptions creationOptions, + out InternalTaskOptions internalOptions) + { + // This is used a couple of times below + TaskContinuationOptions NotOnAnything = + TaskContinuationOptions.NotOnCanceled | + TaskContinuationOptions.NotOnFaulted | + TaskContinuationOptions.NotOnRanToCompletion; + + TaskContinuationOptions creationOptionsMask = + TaskContinuationOptions.PreferFairness | + TaskContinuationOptions.LongRunning | + TaskContinuationOptions.AttachedToParent; + + + // Check that LongRunning and ExecuteSynchronously are not specified together + TaskContinuationOptions illegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning; + if ((continuationOptions & illegalMask) == illegalMask) + { + throw new ArgumentOutOfRangeException("continuationOptions", Strings.Task_ContinueWith_ESandLR); + } + + // Check that no illegal options were specified + if ((continuationOptions & + ~(creationOptionsMask | NotOnAnything | + TaskContinuationOptions.ExecuteSynchronously)) != 0) + { + throw new ArgumentOutOfRangeException("continuationOptions"); + } + + // Check that we didn't specify "not on anything" + if ((continuationOptions & NotOnAnything) == NotOnAnything) + { + throw new ArgumentOutOfRangeException("continuationOptions", Strings.Task_ContinueWith_NotOnAnything); + } + + creationOptions = (TaskCreationOptions)(continuationOptions & creationOptionsMask); + internalOptions = InternalTaskOptions.ContinuationTask; + } + + + /// + /// Registers the continuation and possibly runs it (if the task is already finished). + /// + /// The continuation task itself. + /// TaskScheduler with which to associate continuation task. + /// Restrictions on when the continuation becomes active. + internal void ContinueWithCore(Task continuationTask, TaskScheduler scheduler, TaskContinuationOptions options) + { + Contract.Assert(continuationTask != null, "Task.ContinueWithCore(): null continuationTask"); + Contract.Assert((!continuationTask.IsCompleted) || continuationTask.CancellationToken.IsCancellationRequested, + "Task.ContinueWithCore(): continuationTask is completed and its CT is not signaled"); + + // It doesn't really do any harm to queue up an already-completed continuation, but it's + // a little wasteful. So we'll make an attempt at avoiding it (although the race condition + // here could still result in a completed continuation task being queued.) + if (continuationTask.IsCompleted) return; + + TaskContinuation continuation = new TaskContinuation(continuationTask, scheduler, options); + + // If the task has not finished, we will enqueue the continuation to fire when completed. + if (!IsCompleted) + { + // If not created yet, we will atomically initialize the queue of actions. + LazyInitializer.EnsureInitialized(ref m_contingentProperties, s_contingentPropertyCreator); + if (m_contingentProperties.m_continuations == null) + { + Interlocked.CompareExchange(ref m_contingentProperties.m_continuations, new List(), null); + } + + // Now we must serialize access to the list itself. + lock (m_contingentProperties) + { + // We have to check IsCompleted again here, since the task may have + // finished before we got around to acquiring the lock on the actions. + // There is a race condition here, but it's OK. If the thread that + // finishes the task notices a non-null actions queue it will try to + // acquire a lock on it. Thus it will have to wait for the current + // thread to exit the critical region we're currently in. + if (!IsCompleted) + { + m_contingentProperties.m_continuations.Add(continuation); + return; + } + } + } + + // If we fell through, the task has already completed. We'll invoke the action inline. + // Only start the continuation if the right kind was established. + continuation.Run(this, true); + } + + // Adds a lightweight completion action to a task. This is similar to a continuation + // task except that it is stored as an action, and thus does not require the allocation/ + // execution resources of a continuation task. + // + // Used internally by ContinueWhenAll() and ContinueWhenAny(). + internal void AddCompletionAction(Action action) + { + if (!IsCompleted) + { + LazyInitializer.EnsureInitialized(ref m_contingentProperties, s_contingentPropertyCreator); + TaskContinuation tc = new TaskContinuation(action); + if (m_contingentProperties.m_continuations == null) + { + Interlocked.CompareExchange(ref m_contingentProperties.m_continuations, new List(), null); + } + + // Serialize access to the continuations list + lock (m_contingentProperties) + { + // We have to check IsCompleted again here, since the task may have + // finished before we got around to acquiring the lock on the actions. + // There is a race condition here, but it's OK. If the thread that + // finishes the task notices a non-null actions queue it will try to + // acquire a lock on it. Thus it will have to wait for the current + // thread to exit the critical region we're currently in. + if (!IsCompleted) + { + m_contingentProperties.m_continuations.Add(tc); + return; + } + } + } + + // If we got this far, we've already completed + action(this); + } + + + // + // Wait methods + // + + /// + /// Waits for all of the provided objects to complete execution. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// At least one of the instances was canceled -or- an exception was thrown during + /// the execution of at least one of the instances. + /// + /// + /// The has been disposed. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static void WaitAll(params Task[] tasks) + { +#if DEBUG + bool waitResult = +#endif + WaitAll(tasks, Timeout.Infinite); + +#if DEBUG + Contract.Assert(waitResult, "expected wait to succeed"); +#endif + } + + /// + /// Waits for all of the provided objects to complete execution. + /// + /// + /// true if all of the instances completed execution within the allotted time; + /// otherwise, false. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// At least one of the instances was canceled -or- an exception was thrown during + /// the execution of at least one of the instances. + /// + /// + /// is a negative number other than -1 milliseconds, which represents an + /// infinite time-out -or- timeout is greater than + /// . + /// + /// + /// The has been disposed. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static bool WaitAll(Task[] tasks, TimeSpan timeout) + { + long totalMilliseconds = (long)timeout.TotalMilliseconds; + if (totalMilliseconds < -1 || totalMilliseconds > 0x7fffffff) + { + throw new ArgumentOutOfRangeException("timeout"); + } + + return WaitAll(tasks, (int)totalMilliseconds); + + } + + /// + /// Waits for all of the provided objects to complete execution. + /// + /// + /// true if all of the instances completed execution within the allotted time; + /// otherwise, false. + /// + /// + /// The number of milliseconds to wait, or (-1) to + /// wait indefinitely. + /// An array of instances on which to wait. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// At least one of the instances was canceled -or- an exception was thrown during + /// the execution of at least one of the instances. + /// + /// + /// The has been disposed. + /// + /// + /// is a negative number other than -1, which represents an + /// infinite time-out. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static bool WaitAll(Task[] tasks, int millisecondsTimeout) + { + return WaitAll(tasks, millisecondsTimeout, CancellationToken.None); + } + + /// + /// Waits for all of the provided objects to complete execution. + /// + /// + /// true if all of the instances completed execution within the allotted time; + /// otherwise, false. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// A to observe while waiting for the tasks to complete. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// At least one of the instances was canceled -or- an exception was thrown during + /// the execution of at least one of the instances. + /// + /// + /// The was canceled. + /// + /// + /// The has been disposed. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static void WaitAll(Task[] tasks, CancellationToken cancellationToken) + { + WaitAll(tasks, Timeout.Infinite, cancellationToken); + } + + /// + /// Waits for all of the provided objects to complete execution. + /// + /// + /// true if all of the instances completed execution within the allotted time; + /// otherwise, false. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// The number of milliseconds to wait, or (-1) to + /// wait indefinitely. + /// + /// + /// A to observe while waiting for the tasks to complete. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// At least one of the instances was canceled -or- an exception was thrown during + /// the execution of at least one of the instances. + /// + /// + /// The has been disposed. + /// + /// + /// is a negative number other than -1, which represents an + /// infinite time-out. + /// + /// + /// The was canceled. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static bool WaitAll(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) + { + if (tasks == null) + { + throw new ArgumentNullException("tasks"); + } + if (millisecondsTimeout < -1) + { + throw new ArgumentOutOfRangeException("timeout"); + } + +#if DEBUG + Contract.Assert(tasks != null && millisecondsTimeout >= -1, "invalid arguments passed to WaitAll"); +#endif + cancellationToken.ThrowIfCancellationRequested(); // early check before we make any allocations + + // + // In this WaitAll() implementation we have 2 alternate code paths for a task to be handled: + // CODEPATH1: skip an already completed task, CODEPATH2: actually wait on task's handle + // We make sure that the exception behavior of Task.Wait() is replicated the same for tasks handled in either of these codepaths + // + + List exceptions = null; + List waitedOnTaskList = null; // tasks whose async handles we actually grabbed + + bool returnValue = true; + Task currentTask = Task.InternalCurrent; + TaskScheduler currentTm = (currentTask == null) ? TaskScheduler.Default : currentTask.ExecutingTaskScheduler; + object currentTmStatics = currentTm.GetThreadStatics(); + + // Collects incomplete tasks in "waitedOnTaskList" + for (int i = tasks.Length - 1; i >= 0; i--) + { + Task task = tasks[i]; + + if (task == null) + { + throw new ArgumentException(Strings.Task_WaitMulti_NullTask,"tasks"); + } + + //task.ThrowIfDisposed(); + + bool taskIsCompleted = task.IsCompleted; + if (!taskIsCompleted) + { + // try inlining the task only if we have an infinite timeout and an empty cancellation token + if (millisecondsTimeout != Timeout.Infinite || cancellationToken.CanBeCanceled) + { + // We either didn't attempt inline execution because we had a non-infinite timeout or we had a cancellable token. + // In all cases we need to do a full wait on the task (=> add its event into the list.) + if (waitedOnTaskList == null) + { + waitedOnTaskList = new List(tasks.Length); + } + waitedOnTaskList.Add(task); + } + else + { + // We are eligible for inlining. + taskIsCompleted = task.WrappedTryRunInline(currentTm, currentTmStatics) && + task.IsCompleted; // A successful TryRunInline doesn't guarantee completion + + if (!taskIsCompleted) + { + // Inlining didn't work. + // Do a full wait on the task (=> add its event into the list.) + if (waitedOnTaskList == null) + { + waitedOnTaskList = new List(tasks.Length); + } + waitedOnTaskList.Add(task); + + } + } + } + + if (taskIsCompleted) + { + // The task has finished. Make sure we aggregate its exceptions. + AddExceptionsForCompletedTask(ref exceptions, task); + + } + } + + if (waitedOnTaskList != null) + { + Contract.Assert(waitedOnTaskList.Count > 0); + WaitHandle[] waitHandles = new WaitHandle[waitedOnTaskList.Count]; + for (int i = 0; i < waitHandles.Length; i++) + { + waitHandles[i] = waitedOnTaskList[i].CompletedEvent.WaitHandle; + } + returnValue = WaitAllSTAAnd64Aware(waitHandles, millisecondsTimeout, cancellationToken); + + // If the wait didn't time out, ensure exceptions are propagated. + if (returnValue) + { + for (int i = 0; i < waitedOnTaskList.Count; i++) + { + AddExceptionsForCompletedTask(ref exceptions, waitedOnTaskList[i]); + } + } + + // We need to prevent the tasks array from being GC'ed until we come out of the wait. + // This is necessary so that the Parallel Debugger can traverse it during the long wait and deduce waiter/waitee relationships + GC.KeepAlive(tasks); + } + + // If one or more threw exceptions, aggregate them. + if (exceptions != null) + { + throw new AggregateException(exceptions); + } + + return returnValue; + } + + /// + /// Waits for a set of handles in a STA-aware way. In other words, it will wait for each + /// of the events individually if we're on a STA thread, because MsgWaitForMultipleObjectsEx + /// can't do a true wait-all due to its hidden message queue event. This is not atomic, + /// of course, but we only wait on one-way (MRE) events anyway so this is OK. + /// + /// An array of wait handles to wait on. + /// The timeout to use during waits. + /// The cancellationToken that enables a wait to be canceled. + /// True if all waits succeeded, false if a timeout occurred. + private static bool WaitAllSTAAnd64Aware(WaitHandle[] waitHandles, int millisecondsTimeout, CancellationToken cancellationToken) + { + // We're on an STA thread, so we can't use the real Win32 wait-all. + // We instead walk the list, and wait on each individually. Perf will + // be poor because we'll incur O(N) context switches as we wake up. + + // CancellationToken enabled waits will also choose this codepath regardless of apartment state. + // The ability to use WaitAny to probe for cancellation during one by one waits makes it easy to support CT without introducing racy code paths. + + WaitHandle[] cancelableWHPair = null; // to be used with WaitAny if we have a CancellationToken + + if (cancellationToken.CanBeCanceled) + { + cancelableWHPair = new WaitHandle[2]; // one for the actual wait handle, other for the cancellation event + cancelableWHPair[1] = cancellationToken.WaitHandle; + } + + for (int i = 0; i < waitHandles.Length; i++) + { + long startTicks = (millisecondsTimeout == Timeout.Infinite) ? 0 : DateTime.UtcNow.Ticks; + + if (cancellationToken.CanBeCanceled) + { + // do a WaitAny on the WH of interest and the cancellation event. + cancelableWHPair[0] = waitHandles[i]; + int waitRetCode = WaitHandle.WaitAny(cancelableWHPair, millisecondsTimeout); + if (waitRetCode == WaitHandle.WaitTimeout) + return false; + + // we could have come out of the wait due to index 1 (i.e. cancellationToken.WaitHandle), check and throw + cancellationToken.ThrowIfCancellationRequested(); + + // the wait should have returned 0, otherwise we have a bug in CT or the code above + Contract.Assert(waitRetCode == 0, "Unexpected waitcode from WaitAny with cancellation event"); + } + else + { + + if (!waitHandles[i].WaitOne(millisecondsTimeout)) + return false; + } + + + // Adjust the timeout. + if (millisecondsTimeout != Timeout.Infinite) + { + long elapsedMilliseconds = (DateTime.UtcNow.Ticks - startTicks) / TimeSpan.TicksPerMillisecond; + if (elapsedMilliseconds > int.MaxValue || elapsedMilliseconds > millisecondsTimeout) + return false; + millisecondsTimeout -= (int)elapsedMilliseconds; + } + } + + return true; + } + + /// + /// Internal WaitAll implementation which is meant to be used with small number of tasks, + /// optimized for Parallel.Invoke and other structured primitives. + /// + internal static void FastWaitAll(Task[] tasks) + { +#if DEBUG + Contract.Assert(tasks != null); +#endif + + List exceptions = null; + TaskScheduler currentTm = TaskScheduler.Current; + object currentTmStatics = currentTm.GetThreadStatics(); + + // Collects incomplete tasks in "waitedOnTaskList" and their cooperative events in "cooperativeEventList" + for (int i = tasks.Length - 1; i >= 0; i--) + { + if (!tasks[i].IsCompleted) + { + // Just attempting to inline here... result doesn't matter. + // We'll do a second pass to do actual wait on each task, and to aggregate their exceptions. + // If the task is inlined here, it will register as IsCompleted in the second pass + // and will just give us the exception. + + tasks[i].WrappedTryRunInline(currentTm, currentTmStatics); + } + } + + // Wait on the tasks. + for (int i = tasks.Length - 1; i >= 0; i--) + { + tasks[i].CompletedEvent.Wait(); // Just a boolean check if the task is already done. + AddExceptionsForCompletedTask(ref exceptions, tasks[i]); + } + + // If one or more threw exceptions, aggregate them. + if (exceptions != null) + { + throw new AggregateException(exceptions); + } + } + + /// + /// This internal function is only meant to be called by WaitAll() + /// If the completed task is canceled or it has other exceptions, here we will add those + /// into the passed in exception list (which will be lazily initialized here). + /// + internal static void AddExceptionsForCompletedTask(ref List exceptions, Task t) + { + AggregateException ex = t.GetExceptions(true); + if (ex != null) + { + // make sure the task's exception observed status is set appropriately + // it's possible that WaitAll was called by the parent of an attached child, + // this will make sure it won't throw again in the implicit wait + t.UpdateExceptionObservedStatus(); + + if (exceptions == null) + { + exceptions = new List(ex.InnerExceptions.Count); + } + + exceptions.AddRange(ex.InnerExceptions); + } + } + + + /// + /// Waits for any of the provided objects to complete execution. + /// + /// + /// An array of instances on which to wait. + /// + /// The index of the completed task in the array argument. + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// The has been disposed. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static int WaitAny(params Task[] tasks) + { + int waitResult = WaitAny(tasks, Timeout.Infinite); + Contract.Assert(tasks.Length == 0 || waitResult != -1, "expected wait to succeed"); + return waitResult; + } + + /// + /// Waits for any of the provided objects to complete execution. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// + /// + /// The index of the completed task in the array argument, or -1 if the + /// timeout occurred. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// The has been disposed. + /// + /// + /// is a negative number other than -1 milliseconds, which represents an + /// infinite time-out -or- timeout is greater than + /// . + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static int WaitAny(Task[] tasks, TimeSpan timeout) + { + long totalMilliseconds = (long)timeout.TotalMilliseconds; + if (totalMilliseconds < -1 || totalMilliseconds > 0x7fffffff) + { + throw new ArgumentOutOfRangeException("timeout"); + } + + return WaitAny(tasks, (int)totalMilliseconds); + } + + /// + /// Waits for any of the provided objects to complete execution. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// A to observe while waiting for a task to complete. + /// + /// + /// The index of the completed task in the array argument. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// The has been disposed. + /// + /// + /// The was canceled. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static int WaitAny(Task[] tasks, CancellationToken cancellationToken) + { + return WaitAny(tasks, Timeout.Infinite, cancellationToken); + } + + /// + /// Waits for any of the provided objects to complete execution. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// The number of milliseconds to wait, or (-1) to + /// wait indefinitely. + /// + /// + /// The index of the completed task in the array argument, or -1 if the + /// timeout occurred. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// The has been disposed. + /// + /// + /// is a negative number other than -1, which represents an + /// infinite time-out. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static int WaitAny(Task[] tasks, int millisecondsTimeout) + { + return WaitAny(tasks, millisecondsTimeout, CancellationToken.None); + } + + /// + /// Waits for any of the provided objects to complete execution. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// The number of milliseconds to wait, or (-1) to + /// wait indefinitely. + /// + /// + /// A to observe while waiting for a task to complete. + /// + /// + /// The index of the completed task in the array argument, or -1 if the + /// timeout occurred. + /// + /// + /// The argument is null. + /// + /// + /// The argument contains a null element. + /// + /// + /// The has been disposed. + /// + /// + /// is a negative number other than -1, which represents an + /// infinite time-out. + /// + /// + /// The was canceled. + /// + [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger + public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) + { + if (tasks == null) + { + throw new ArgumentNullException("tasks"); + } + if (millisecondsTimeout < -1) + { + throw new ArgumentOutOfRangeException("millisecondsTimeout"); + } + + if (tasks.Length > 0) + { + var tcs = new TaskCompletionSource(); + Task.Factory.ContinueWhenAny(tasks, completed => tcs.TrySetResult(completed), + CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + if (tcs.Task.Wait(millisecondsTimeout, cancellationToken)) + { + var resultTask = tcs.Task.Result; + for (int i = 0; i < tasks.Length; i++) + { + if (tasks[i] == resultTask) + return i; + } + } + } + + // We need to prevent the tasks array from being GC'ed until we come out of the wait. + // This is necessary so that the Parallel Debugger can traverse it during the long wait and deduce waiter/waitee relationships + GC.KeepAlive(tasks); + + return -1; + } + + } + + // Proxy class for better debugging experience + internal class SystemThreadingTasks_TaskDebugView + { + private Task m_task; + + public SystemThreadingTasks_TaskDebugView(Task task) + { + m_task = task; + } + + public object AsyncState { get { return m_task.AsyncState; } } + public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } } + public Exception Exception { get { return m_task.Exception; } } + public int Id { get { return m_task.Id; } } + public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } } + public TaskStatus Status { get { return m_task.Status; } } + } + + /// + /// Specifies flags that control optional behavior for the creation and execution of tasks. + /// + [Flags] + + public enum TaskCreationOptions + { + /// + /// Specifies that the default behavior should be used. + /// + None = 0x0, + + /// + /// A hint to a TaskScheduler to schedule a + /// task in as fair a manner as possible, meaning that tasks scheduled sooner will be more likely to + /// be run sooner, and tasks scheduled later will be more likely to be run later. + /// + PreferFairness = 0x01, + + /// + /// Specifies that a task will be a long-running, course-grained operation. It provides a hint to the + /// TaskScheduler that oversubscription may be + /// warranted. + /// + LongRunning = 0x02, + + /// + /// Specifies that a task is attached to a parent in the task hierarchy. + /// + AttachedToParent = 0x04, + } + + + /// + /// Task creation flags which are only used internally. + /// + [Flags] + + internal enum InternalTaskOptions + { + /// Specifies "No internal task options" + None, + + /// Used to filter out internal vs. public task creation options. + InternalOptionsMask = 0x0000FF00, + + ChildReplica = 0x0100, + ContinuationTask = 0x0200, + PromiseTask = 0x0400, + SelfReplicating = 0x0800, + + /// Specifies that the task will be queued by the runtime before handing it over to the user. + /// This flag will be used to skip the cancellationtoken registration step, which is only meant for unstarted tasks. + QueuedByRuntime = 0x2000 + } + + /// + /// Specifies flags that control optional behavior for the creation and execution of continuation tasks. + /// + [Flags] + + public enum TaskContinuationOptions + { + /// + /// Default = "Continue on any, no task options, run asynchronously" + /// Specifies that the default behavior should be used. Continuations, by default, will + /// be scheduled when the antecedent task completes, regardless of the task's final TaskStatus. + /// + None = 0, + + // These are identical to their meanings and values in TaskCreationOptions + + /// + /// A hint to a TaskScheduler to schedule a + /// task in as fair a manner as possible, meaning that tasks scheduled sooner will be more likely to + /// be run sooner, and tasks scheduled later will be more likely to be run later. + /// + PreferFairness = 0x01, + + /// + /// Specifies that a task will be a long-running, course-grained operation. It provides + /// a hint to the TaskScheduler that + /// oversubscription may be warranted. + /// + LongRunning = 0x02, + /// + /// Specifies that a task is attached to a parent in the task hierarchy. + /// + AttachedToParent = 0x04, + + // These are specific to continuations + + /// + /// Specifies that the continuation task should not be scheduled if its antecedent ran to completion. + /// This option is not valid for multi-task continuations. + /// + NotOnRanToCompletion = 0x10000, + /// + /// Specifies that the continuation task should not be scheduled if its antecedent threw an unhandled + /// exception. This option is not valid for multi-task continuations. + /// + NotOnFaulted = 0x20000, + /// + /// Specifies that the continuation task should not be scheduled if its antecedent was canceled. This + /// option is not valid for multi-task continuations. + /// + NotOnCanceled = 0x40000, + /// + /// Specifies that the continuation task should be scheduled only if its antecedent ran to + /// completion. This option is not valid for multi-task continuations. + /// + OnlyOnRanToCompletion = NotOnFaulted | NotOnCanceled, + /// + /// Specifies that the continuation task should be scheduled only if its antecedent threw an + /// unhandled exception. This option is not valid for multi-task continuations. + /// + OnlyOnFaulted = NotOnRanToCompletion | NotOnCanceled, + /// + /// Specifies that the continuation task should be scheduled only if its antecedent was canceled. + /// This option is not valid for multi-task continuations. + /// + OnlyOnCanceled = NotOnRanToCompletion | NotOnFaulted, + /// + /// Specifies that the continuation task should be executed synchronously. With this option + /// specified, the continuation will be run on the same thread that causes the antecedent task to + /// transition into its final state. If the antecedent is already complete when the continuation is + /// created, the continuation will run on the thread creating the continuation. Only very + /// short-running continuations should be executed synchronously. + /// + ExecuteSynchronously = 0x80000 + } +} + diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskCanceledException.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskCanceledException.cs new file mode 100644 index 000000000..a0644dbfc --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskCanceledException.cs @@ -0,0 +1,98 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskCanceledException.cs +// +// hyildiz +// +// An exception for task cancellations. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +namespace System.Threading.Tasks +{ + + /// + /// Represents an exception used to communicate task cancellation. + /// + + public class TaskCanceledException : OperationCanceledException + { + + + private Task m_canceledTask; // The task which has been canceled. + + /// + /// Initializes a new instance of the class. + /// + public TaskCanceledException() : base(Strings.TaskCanceledException_ctor_DefaultMessage) + { + } + + /// + /// Initializes a new instance of the + /// class with a specified error message. + /// + /// The error message that explains the reason for the exception. + public TaskCanceledException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the + /// class with a specified error message and a reference to the inner exception that is the cause of + /// this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. + public TaskCanceledException(string message, Exception innerException) : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class + /// with a reference to the that has been canceled. + /// + /// A task that has been canceled. + public TaskCanceledException(Task task) : + base(Strings.TaskCanceledException_ctor_DefaultMessage, task!=null ? task.CancellationToken:new CancellationToken()) + { + m_canceledTask = task; + } + +#if SERIALIZATION + /// + /// Initializes a new instance of the + /// class with serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected TaskCanceledException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +#endif + + /// + /// Gets the task associated with this exception. + /// + /// + /// It is permissible for no Task to be associated with a + /// , in which case + /// this property will return null. + /// + public Task Task + { + get { return m_canceledTask; } + } + + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskCompletionSource.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskCompletionSource.cs new file mode 100644 index 000000000..9790fb75d --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskCompletionSource.cs @@ -0,0 +1,387 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskCompletionSource.cs +// +// joehoag +// +// TaskCompletionSource is the producer end of an unbound future. Its +// Task member may be distributed as the consumer end of the future. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Threading; +using System.Diagnostics.Contracts; +using System.Collections.Generic; + +// Disable the "reference to volatile field not treated as volatile" error. +#pragma warning disable 0420 + +namespace System.Threading.Tasks +{ + /// + /// Represents the producer side of a unbound to a + /// delegate, providing access to the consumer side through the property. + /// + /// + /// + /// It is often the case that a is desired to + /// represent another asynchronous operation. + /// TaskCompletionSource is provided for this purpose. It enables + /// the creation of a task that can be handed out to consumers, and those consumers can use the members + /// of the task as they would any other. However, unlike most tasks, the state of a task created by a + /// TaskCompletionSource is controlled explicitly by the methods on TaskCompletionSource. This enables the + /// completion of the external asynchronous operation to be propagated to the underlying Task. The + /// separation also ensures that consumers are not able to transition the state without access to the + /// corresponding TaskCompletionSource. + /// + /// + /// All members of are thread-safe + /// and may be used from multiple threads concurrently. + /// + /// + /// The type of the result value assocatied with this . + + public class TaskCompletionSource + { + private Task m_task; + + /// + /// Creates a . + /// + public TaskCompletionSource() + : this(null, TaskCreationOptions.None) + { + } + + /// + /// Creates a + /// with the specified options. + /// + /// + /// The created + /// by this instance and accessible through its property + /// will be instantiated using the specified . + /// + /// The options to use when creating the underlying + /// . + /// + /// The represent options invalid for use + /// with a . + /// + public TaskCompletionSource(TaskCreationOptions creationOptions) + : this(null, creationOptions) + { + } + + /// + /// Creates a + /// with the specified state. + /// + /// The state to use as the underlying + /// 's AsyncState. + public TaskCompletionSource(object state) + : this(state, TaskCreationOptions.None) + { + } + + /// + /// Creates a with + /// the specified state and options. + /// + /// The options to use when creating the underlying + /// . + /// The state to use as the underlying + /// 's AsyncState. + /// + /// The represent options invalid for use + /// with a . + /// + public TaskCompletionSource(object state, TaskCreationOptions creationOptions) + { + m_task = new Task(state, CancellationToken.None, creationOptions, InternalTaskOptions.PromiseTask); + } + + + /// + /// Gets the created + /// by this . + /// + /// + /// This property enables a consumer access to the that is controlled by this instance. + /// The , , + /// , and + /// methods (and their "Try" variants) on this instance all result in the relevant state + /// transitions on this underlying Task. + /// + public Task Task + { + get { return m_task; } + } + + /// + /// Attempts to transition the underlying + /// into the + /// Faulted + /// state. + /// + /// The exception to bind to this . + /// True if the operation was successful; otherwise, false. + /// This operation will return false if the + /// is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The argument is null. + /// The was disposed. + public bool TrySetException(Exception exception) + { + if (exception == null) throw new ArgumentNullException("exception"); + + bool rval = m_task.TrySetException(exception); + if (!rval && !m_task.IsCompleted) + { + // The only way that m_task is not completed is if it is in a COMPLETION_RESERVED state. + // Just wait a bit until the completion is finalized. + SpinWait sw = new SpinWait(); + while (!m_task.IsCompleted) sw.SpinOnce(); + } + + return rval; + } + + /// + /// Attempts to transition the underlying + /// into the + /// Faulted + /// state. + /// + /// The collection of exceptions to bind to this . + /// True if the operation was successful; otherwise, false. + /// This operation will return false if the + /// is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The argument is null. + /// There are one or more null elements in . + /// The collection is empty. + /// The was disposed. + public bool TrySetException(IEnumerable exceptions) + { + if (exceptions == null) throw new ArgumentNullException("exceptions"); + + List defensiveCopy = new List(); + foreach (Exception e in exceptions) + { + if (e == null) + throw new ArgumentException(Strings.TaskCompletionSourceT_TrySetException_NullException,"exceptions"); + defensiveCopy.Add(e); + } + + if (defensiveCopy.Count == 0) + throw new ArgumentException(Strings.TaskCompletionSourceT_TrySetException_NoExceptions, "exceptions"); + + bool rval = m_task.TrySetException(defensiveCopy); + if (!rval && !m_task.IsCompleted) + { + // The only way that m_task is not completed is if it is in a COMPLETION_RESERVED state. + // Just wait a bit until the completion is finalized. + SpinWait sw = new SpinWait(); + while (!m_task.IsCompleted) sw.SpinOnce(); + } + + return rval; + } + + /// + /// Transitions the underlying + /// into the + /// Faulted + /// state. + /// + /// The exception to bind to this . + /// The argument is null. + /// + /// The underlying is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The was disposed. + public void SetException(Exception exception) + { + if (exception == null) throw new ArgumentNullException("exception"); + + if (!TrySetException(exception)) + { + throw new InvalidOperationException(Strings.TaskT_TransitionToFinal_AlreadyCompleted); + } + } + + /// + /// Transitions the underlying + /// into the + /// Faulted + /// state. + /// + /// The collection of exceptions to bind to this . + /// The argument is null. + /// There are one or more null elements in . + /// + /// The underlying is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The was disposed. + public void SetException(IEnumerable exceptions) + { + if (!TrySetException(exceptions)) + { + throw new InvalidOperationException(Strings.TaskT_TransitionToFinal_AlreadyCompleted); + } + } + + + /// + /// Attempts to transition the underlying + /// into the + /// RanToCompletion + /// state. + /// + /// The result value to bind to this . + /// True if the operation was successful; otherwise, false. + /// This operation will return false if the + /// is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The was disposed. + public bool TrySetResult(TResult result) + { + bool rval = m_task.TrySetResult(result); + if(!rval && !m_task.IsCompleted) + { + // The only way that m_task is not completed is if it is in a COMPLETION_RESERVED state. + // Just wait a bit until the completion is finalized. + SpinWait sw = new SpinWait(); + while (!m_task.IsCompleted) sw.SpinOnce(); + } + + return rval; + } + + /// + /// Transitions the underlying + /// into the + /// RanToCompletion + /// state. + /// + /// The result value to bind to this . + /// + /// The underlying is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The was disposed. + public void SetResult(TResult result) + { + if (!TrySetResult(result)) + throw new InvalidOperationException(Strings.TaskT_TransitionToFinal_AlreadyCompleted); + } + + /// + /// Transitions the underlying + /// into the + /// Canceled + /// state. + /// + /// + /// The underlying is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The was disposed. + public void SetCanceled() + { + if(!TrySetCanceled()) + throw new InvalidOperationException(Strings.TaskT_TransitionToFinal_AlreadyCompleted); + } + + /// + /// Attempts to transition the underlying + /// into the + /// Canceled + /// state. + /// + /// True if the operation was successful; otherwise, false. + /// This operation will return false if the + /// is already in one + /// of the three final states: + /// RanToCompletion, + /// Faulted, or + /// Canceled. + /// + /// The was disposed. + public bool TrySetCanceled() + { + bool returnValue = false; + //m_task.ThrowIfDisposed(); + + // "Reserve" the completion for this task, while making sure that: (1) No prior reservation + // has been made, (2) The result has not already been set, (3) An exception has not previously + // been recorded, and (4) Cancellation has not been requested. + // + // If the reservation is successful, then record the cancellation and finish completion processing. + // + // Note: I had to access static Task variables through Task + // instead of Task, because I have a property named Task and that + // was confusing the compiler. + if (m_task.AtomicStateUpdate(Task.TASK_STATE_COMPLETION_RESERVED, + Task.TASK_STATE_COMPLETION_RESERVED | Task.TASK_STATE_CANCELED | + Task.TASK_STATE_FAULTED | Task.TASK_STATE_RAN_TO_COMPLETION)) + { + m_task.RecordInternalCancellationRequest(); // record the request + m_task.CancellationCleanupLogic(); // perform cancellation cleanup actions + returnValue = true; + } + else if (!m_task.IsCompleted) + { + // The only way that m_task is not completed is if it is in a COMPLETION_RESERVED state. + // Just wait a bit until the completion is finalized. + SpinWait sw = new SpinWait(); + while (!m_task.IsCompleted) sw.SpinOnce(); + } + + + return returnValue; + } + + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskExceptionHolder.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskExceptionHolder.cs new file mode 100644 index 000000000..1fce7fb3b --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskExceptionHolder.cs @@ -0,0 +1,235 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskExceptionHolder.cs +// +// hyildiz +// +// An abstraction for holding and aggregating exceptions. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +// Disable the "reference to volatile field not treated as volatile" error. +#pragma warning disable 0420 + +namespace System.Threading.Tasks +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + + /// + /// An exception holder manages a list of exceptions for one particular task. + /// It offers the ability to aggregate, but more importantly, also offers intrinsic + /// support for propagating unhandled exceptions that are never observed. It does + /// this by aggregating and throwing if the holder is ever GC'd without the holder's + /// contents ever having been requested (e.g. by a Task.Wait, Task.get_Exception, etc). + /// + internal class TaskExceptionHolder + { + private List m_exceptions; // One or more exceptions to be aggregated. + private bool m_isHandled; // Whether the holder was observed. + private Task m_task; // The task to which these exceptions belong. + + /// + /// Creates a new holder; it will be registered for finalization. + /// + /// The task this holder belongs to. + internal TaskExceptionHolder(Task task) + { + Contract.Assert(task != null, "Expected a non-null task."); + + //EnsureADUnloadCallbackRegistered(); + + m_exceptions = new List(1); + m_task = task; + } + + //private static volatile bool s_domainUnloadStarted; + //private static volatile EventHandler s_adUnloadEventHandler; + + //private static void EnsureADUnloadCallbackRegistered() + //{ + // if (s_adUnloadEventHandler == null && + // Interlocked.CompareExchange( ref s_adUnloadEventHandler, + // new EventHandler(AppDomainUnloadCallback), + // null) == null) + // { + // } + //} + + //private static void AppDomainUnloadCallback(object sender, EventArgs e) + //{ + // s_domainUnloadStarted = true; + //} + + /// + /// A finalizer that repropagates unhandled exceptions. + /// + ~TaskExceptionHolder() + { + // Raise unhandled exceptions only when we know that neither the process or nor the appdomain is being torn down. + // We need to do this filtering because all TaskExceptionHolders will be finalized during shutdown or unload + // regardles of reachability of the task (i.e. even if the user code was about to observe the task's exception), + // which can otherwise lead to spurious crashes during shutdown. + if (!m_isHandled && !Environment.HasShutdownStarted) + { + // We don't want to crash the finalizer thread if any ThreadAbortExceptions + // occur in the list or in any nested AggregateExceptions. + // (Don't rethrow ThreadAbortExceptions.) + foreach (Exception exp in m_exceptions) + { + AggregateException aggExp = exp as AggregateException; + if (aggExp != null) + { + AggregateException flattenedAggExp = aggExp.Flatten(); + foreach (Exception innerExp in flattenedAggExp.InnerExceptions) + { + if (ThreadingServices.IsThreadAbort(innerExp)) + return; + } + } + else if (ThreadingServices.IsThreadAbort(exp)) + { + return; + } + } + + // We will only propagate if this is truly unhandled. The reason this could + // ever occur is somewhat subtle: if a Task's exceptions are observed in some + // other finalizer, and the Task was finalized before the holder, the holder + // will have been marked as handled before even getting here. + + // Give users a chance to keep this exception from crashing the process + + // First, publish the unobserved exception and allow users to observe it + AggregateException exceptionToThrow = new AggregateException( + Strings.TaskExceptionHolder_UnhandledException, + m_exceptions); + UnobservedTaskExceptionEventArgs ueea = new UnobservedTaskExceptionEventArgs(exceptionToThrow); + TaskScheduler.PublishUnobservedTaskException(m_task, ueea); + + //// Now, if we are still unobserved, throw the exception + //if (!ueea.m_observed) + //{ + // throw exceptionToThrow; + //} + } + } + + /// + /// Add an exception to the internal list. This will ensure the holder is + /// in the proper state (handled/unhandled) depending on the list's contents. + /// + /// An exception object (either an Exception or an + /// IEnumerable{Exception}) to add to the list. + internal void Add(object exceptionObject) + { + Contract.Assert(exceptionObject != null); + Contract.Assert(m_exceptions != null); + + Contract.Assert(exceptionObject is Exception || exceptionObject is IEnumerable, + "TaskExceptionHolder.Add(): Expected Exception or IEnumerable"); + + Exception exception = exceptionObject as Exception; + if (exception != null) m_exceptions.Add(exception); + else + { + IEnumerable exColl = exceptionObject as IEnumerable; + if (exColl != null) m_exceptions.AddRange(exColl); + else + { + throw new ArgumentException(Strings.TaskExceptionHolder_UnknownExceptionType,"exceptionObject"); + } + } + + + // If all of the exceptions are ThreadAbortExceptions and/or + // AppDomainUnloadExceptions, we do not want the finalization + // probe to propagate them, so we consider the holder to be + // handled. If a subsequent exception comes in of a different + // kind, we will reactivate the holder. + for (int i = 0; i < m_exceptions.Count; i++) + { + if (m_exceptions[i].GetType() != ThreadingServices.ThreadAbortExceptionType && + m_exceptions[i].GetType() != ThreadingServices.AppDomainUnloadedExceptionType) + { + MarkAsUnhandled(); + break; + } + else if (i == m_exceptions.Count - 1) + { + MarkAsHandled(false); + } + } + } + + /// + /// A private helper method that ensures the holder is considered + /// unhandled, i.e. it is registered for finalization. + /// + private void MarkAsUnhandled() + { + // If a thread partially observed this thread's exceptions, we + // should revert back to "not handled" so that subsequent exceptions + // must also be seen. Otherwise, some could go missing. We also need + // to reregister for finalization. + if (m_isHandled) + { + GC.ReRegisterForFinalize(this); + m_isHandled = false; + } + } + + /// + /// A private helper method that ensures the holder is considered + /// handled, i.e. it is not registered for finalization. + /// + /// Whether this is called from the finalizer thread. + internal void MarkAsHandled(bool calledFromFinalizer) + { + if (!m_isHandled) + { + if (!calledFromFinalizer) + { + GC.SuppressFinalize(this); + } + + m_isHandled = true; + } + } + + /// + /// Allocates a new aggregate exception and adds the contents of the list to + /// it. By calling this method, the holder assumes exceptions to have been + /// "observed", such that the finalization check will be subsequently skipped. + /// + /// Whether this is being called from a finalizer. + /// An extra exception to be included (optionally). + /// The aggregate exception to throw. + internal AggregateException CreateExceptionObject(bool calledFromFinalizer, Exception includeThisException) + { + Contract.Assert(m_exceptions.Count > 0, "Expected at least one exception."); + + // Mark as handled and aggregate the exceptions. + MarkAsHandled(calledFromFinalizer); + + List exceptions = m_exceptions; + + // If the caller wants a specific exception to be included, add it now. + if (includeThisException != null) + { + exceptions = new List(exceptions); + exceptions.Add(includeThisException); + } + + // Manufacture the aggregate. + return new AggregateException(exceptions); + } + + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskExtensions.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskExtensions.cs new file mode 100644 index 000000000..595e19513 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskExtensions.cs @@ -0,0 +1,177 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskExtensions.cs +// +// joehoag +// +// Extensions to Task/Task classes +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Diagnostics.Contracts; + +namespace System.Threading.Tasks +{ + /// + /// Provides a set of static (Shared in Visual Basic) methods for working with specific kinds of + /// instances. + /// + public static class TaskExtensions + { + /// + /// Creates a proxy Task that represents the + /// asynchronous operation of a Task{Task}. + /// + /// + /// It is often useful to be able to return a Task from a + /// Task{TResult}, where the inner Task represents work done as part of the outer Task{TResult}. However, + /// doing so results in a Task{Task}, which, if not dealt with carefully, could produce unexpected behavior. Unwrap + /// solves this problem by creating a proxy Task that represents the entire asynchronous operation of such a Task{Task}. + /// + /// The Task{Task} to unwrap. + /// The exception that is thrown if the + /// argument is null. + /// A Task that represents the asynchronous operation of the provided Task{Task}. + public static Task Unwrap(this Task task) + { + if (task == null) throw new ArgumentNullException("task"); + bool result; + + // tcs.Task serves as a proxy for task.Result. + // AttachedToParent is the only legal option for TCS-style task. + var tcs = new TaskCompletionSource(task.CreationOptions & TaskCreationOptions.AttachedToParent); + + // Set up some actions to take when task has completed. + task.ContinueWith(delegate + { + switch (task.Status) + { + // If task did not run to completion, then record the cancellation/fault information + // to tcs.Task. + case TaskStatus.Canceled: + case TaskStatus.Faulted: + result = tcs.TrySetFromTask(task); + Contract.Assert(result, "Unwrap(Task): Expected TrySetFromTask #1 to succeed"); + break; + + case TaskStatus.RanToCompletion: + // task.Result == null ==> proxy should be canceled. + if (task.Result == null) tcs.TrySetCanceled(); + + // When task.Result completes, take some action to set the completion state of tcs.Task. + else + { + task.Result.ContinueWith(_ => + { + // Copy completion/cancellation/exception info from task.Result to tcs.Task. + result = tcs.TrySetFromTask(task.Result); + Contract.Assert(result, "Unwrap(Task): Expected TrySetFromTask #2 to succeed"); + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + break; + } + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + + // Return this immediately as a proxy. When task.Result completes, or task is faulted/canceled, + // the completion information will be transfered to tcs.Task. + return tcs.Task; + } + + /// + /// Creates a proxy Task{TResult} that represents the + /// asynchronous operation of a Task{Task{TResult}}. + /// + /// + /// It is often useful to be able to return a Task{TResult} from a Task{TResult}, where the inner Task{TResult} + /// represents work done as part of the outer Task{TResult}. However, doing so results in a Task{Task{TResult}}, + /// which, if not dealt with carefully, could produce unexpected behavior. Unwrap solves this problem by + /// creating a proxy Task{TResult} that represents the entire asynchronous operation of such a Task{Task{TResult}}. + /// + /// The Task{Task{TResult}} to unwrap. + /// The exception that is thrown if the + /// argument is null. + /// A Task{TResult} that represents the asynchronous operation of the provided Task{Task{TResult}}. /// Unwraps a Task that returns another Task. + public static Task Unwrap(this Task> task) + { + if (task == null) throw new ArgumentNullException("task"); + bool result; + + // tcs.Task serves as a proxy for task.Result. + // AttachedToParent is the only legal option for TCS-style task. + var tcs = new TaskCompletionSource(task.CreationOptions & TaskCreationOptions.AttachedToParent); + + // Set up some actions to take when task has completed. + task.ContinueWith(delegate + { + switch (task.Status) + { + // If task did not run to completion, then record the cancellation/fault information + // to tcs.Task. + case TaskStatus.Canceled: + case TaskStatus.Faulted: + result = tcs.TrySetFromTask(task); + Contract.Assert(result, "Unwrap(Task>): Expected TrySetFromTask #1 to succeed"); + break; + + case TaskStatus.RanToCompletion: + // task.Result == null ==> proxy should be canceled. + if (task.Result == null) tcs.TrySetCanceled(); + + // When task.Result completes, take some action to set the completion state of tcs.Task. + else + { + task.Result.ContinueWith(_ => + { + // Copy completion/cancellation/exception info from task.Result to tcs.Task. + result = tcs.TrySetFromTask(task.Result); + Contract.Assert(result, "Unwrap(Task>): Expected TrySetFromTask #2 to succeed"); + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + + break; + } + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + + // Return this immediately as a proxy. When task.Result completes, or task is faulted/canceled, + // the completion information will be transfered to tcs.Task. + return tcs.Task; + } + + // Transfer the completion status from "source" to "me". + private static bool TrySetFromTask(this TaskCompletionSource me, Task source) + { + Contract.Assert(source.IsCompleted, "TrySetFromTask: Expected source to have completed."); + bool rval = false; + + switch(source.Status) + { + case TaskStatus.Canceled: + rval = me.TrySetCanceled(); + break; + + case TaskStatus.Faulted: + rval = me.TrySetException(source.Exception.InnerExceptions); + break; + + case TaskStatus.RanToCompletion: + if(source is Task) + rval = me.TrySetResult( ((Task)source).Result); + else + rval = me.TrySetResult(default(TResult)); + break; + } + + return rval; + } + + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskFactory.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskFactory.cs new file mode 100644 index 000000000..b5bb1ca1e --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskFactory.cs @@ -0,0 +1,3271 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskFactory.cs +// +// joehoag +// +// There are a plethora of common patterns for which Tasks are created. TaskFactory encodes +// these patterns into helper methods. These helpers also pick up default configuration settings +// applicable to the entire factory and configurable through its constructors. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Security; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Diagnostics.Contracts; + +namespace System.Threading.Tasks +{ + /// + /// Provides support for creating and scheduling + /// Tasks. + /// + /// + /// + /// There are many common patterns for which tasks are relevant. The + /// class encodes some of these patterns into methods that pick up default settings, which are + /// configurable through its constructors. + /// + /// + /// A default instance of is available through the + /// Task.Factory property. + /// + /// + + public class TaskFactory + { + // member variables + private CancellationToken m_defaultCancellationToken; + private TaskScheduler m_defaultScheduler; + private TaskCreationOptions m_defaultCreationOptions; + private TaskContinuationOptions m_defaultContinuationOptions; + + + private TaskScheduler DefaultScheduler + { + get + { + if (m_defaultScheduler == null) return TaskScheduler.Current; + else return m_defaultScheduler; + } + } + + // sister method to above property -- avoids a TLS lookup + private TaskScheduler GetDefaultScheduler(Task currTask) + { + if (m_defaultScheduler != null) return m_defaultScheduler; + else if (currTask != null) return currTask.ExecutingTaskScheduler; + else return TaskScheduler.Default; + } + + /* Constructors */ + + // ctor parameters provide defaults for the factory, which can be overridden by options provided to + // specific calls on the factory + + + /// + /// Initializes a instance with the default configuration. + /// + /// + /// This constructor creates a instance with a default configuration. The + /// property is initialized to + /// TaskCreationOptions.None, the + /// property is initialized to TaskContinuationOptions.None, + /// and the TaskScheduler property is + /// initialized to the current scheduler (see TaskScheduler.Current). + /// + public TaskFactory() + : this(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, null) + { + } + + /// + /// Initializes a instance with the specified configuration. + /// + /// The default that will be assigned + /// to tasks created by this unless another CancellationToken is explicitly specified + /// while calling the factory methods. + /// + /// This constructor creates a instance with a default configuration. The + /// property is initialized to + /// TaskCreationOptions.None, the + /// property is initialized to TaskContinuationOptions.None, + /// and the TaskScheduler property is + /// initialized to the current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(CancellationToken cancellationToken) + : this(cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null) + { + } + + /// + /// Initializes a instance with the specified configuration. + /// + /// + /// The + /// TaskScheduler to use to schedule any tasks created with this TaskFactory. A null value + /// indicates that the current TaskScheduler should be used. + /// + /// + /// With this constructor, the + /// property is initialized to + /// TaskCreationOptions.None, the + /// property is initialized to TaskContinuationOptions.None, + /// and the TaskScheduler property is + /// initialized to , unless it's null, in which case the property is + /// initialized to the current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(TaskScheduler scheduler) // null means to use TaskScheduler.Current + : this(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler) + { + } + + /// + /// Initializes a instance with the specified configuration. + /// + /// + /// The default + /// TaskCreationOptions to use when creating tasks with this TaskFactory. + /// + /// + /// The default + /// TaskContinuationOptions to use when creating continuation tasks with this TaskFactory. + /// + /// + /// The exception that is thrown when the + /// argument or the + /// argument specifies an invalid value. + /// + /// + /// With this constructor, the + /// property is initialized to , + /// the + /// property is initialized to , and the TaskScheduler property is initialized to the + /// current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions) + : this(CancellationToken.None, creationOptions, continuationOptions, null) + { + } + + /// + /// Initializes a instance with the specified configuration. + /// + /// The default that will be assigned + /// to tasks created by this unless another CancellationToken is explicitly specified + /// while calling the factory methods. + /// + /// The default + /// TaskCreationOptions to use when creating tasks with this TaskFactory. + /// + /// + /// The default + /// TaskContinuationOptions to use when creating continuation tasks with this TaskFactory. + /// + /// + /// The default + /// TaskScheduler to use to schedule any Tasks created with this TaskFactory. A null value + /// indicates that TaskScheduler.Current should be used. + /// + /// + /// The exception that is thrown when the + /// argument or the + /// argumentspecifies an invalid value. + /// + /// + /// With this constructor, the + /// property is initialized to , + /// the + /// property is initialized to , and the TaskScheduler property is initialized to + /// , unless it's null, in which case the property is initialized to the + /// current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + m_defaultCancellationToken = cancellationToken; + m_defaultScheduler = scheduler; + m_defaultCreationOptions = creationOptions; + m_defaultContinuationOptions = continuationOptions; + CheckCreationOptions(m_defaultCreationOptions); + CheckMultiTaskContinuationOptions(m_defaultContinuationOptions); + } + + internal static void CheckCreationOptions(TaskCreationOptions creationOptions) + { + // Check for validity of options + if ((creationOptions & + ~(TaskCreationOptions.AttachedToParent | + TaskCreationOptions.LongRunning | + TaskCreationOptions.PreferFairness)) != 0) + { + throw new ArgumentOutOfRangeException("creationOptions"); + } + } + + /* Properties */ + + /// + /// Gets the default CancellationToken of this + /// TaskFactory. + /// + /// + /// This property returns the default that will be assigned to all + /// tasks created by this factory unless another CancellationToken value is explicitly specified + /// during the call to the factory methods. + /// + public CancellationToken CancellationToken { get { return m_defaultCancellationToken; } } + + /// + /// Gets the TaskScheduler of this + /// TaskFactory. + /// + /// + /// This property returns the default scheduler for this factory. It will be used to schedule all + /// tasks unless another scheduler is explicitly specified during calls to this factory's methods. + /// If null, TaskScheduler.Current + /// will be used. + /// + public TaskScheduler Scheduler { get { return m_defaultScheduler; } } + + /// + /// Gets the TaskCreationOptions + /// value of this TaskFactory. + /// + /// + /// This property returns the default creation options for this factory. They will be used to create all + /// tasks unless other options are explicitly specified during calls to this factory's methods. + /// + public TaskCreationOptions CreationOptions { get { return m_defaultCreationOptions; } } + + /// + /// Gets the TaskContinuationOptions + /// value of this TaskFactory. + /// + /// + /// This property returns the default continuation options for this factory. They will be used to create + /// all continuation tasks unless other options are explicitly specified during calls to this factory's methods. + /// + public TaskContinuationOptions ContinuationOptions { get { return m_defaultContinuationOptions; } } + + // + // StartNew methods + // + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors + /// and then calling + /// Start to schedule it for execution. However, + /// unless creation and scheduling must be separated, StartNew is the recommended + /// approach for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask), + m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark); + } + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// The that will be assigned to the new task. + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors + /// and then calling + /// Start to schedule it for execution. However, + /// unless creation and scheduling must be separated, StartNew is the recommended + /// approach for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.InternalStartNew(currTask, action, null, cancellationToken, GetDefaultScheduler(currTask), + m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark); + } + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// Task. + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and + /// then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action, TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask), creationOptions, + InternalTaskOptions.None, ref stackMark); + } + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// The that will be assigned to the new + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// Task. + /// The TaskScheduler + /// that is used to schedule the created Task. + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and + /// then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return Task.InternalStartNew(Task.InternalCurrent, action, null, cancellationToken, scheduler, creationOptions, + InternalTaskOptions.None, ref stackMark); + } + + // Internal version includes InternalTaskOptions for Parallel.Invoke() support. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + internal Task StartNew(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return Task.InternalStartNew(Task.InternalCurrent, action, null, cancellationToken, scheduler, creationOptions, internalOptions, ref stackMark); + } + + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// An object containing data to be used by the + /// delegate. + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and + /// then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action, Object state) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), + m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark); + } + + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// An object containing data to be used by the + /// delegate. + /// The that will be assigned to the new + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and + /// then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action, Object state, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.InternalStartNew(currTask, action, state, cancellationToken, GetDefaultScheduler(currTask), + m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark); + } + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// An object containing data to be used by the + /// delegate. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// Task. + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and + /// then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action, Object state, TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), + creationOptions, InternalTaskOptions.None, ref stackMark); + } + + /// + /// Creates and starts a Task. + /// + /// The action delegate to execute asynchronously. + /// An object containing data to be used by the + /// delegate. + /// The that will be assigned to the new task. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// Task. + /// The TaskScheduler + /// that is used to schedule the created Task. + /// The started Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a Task using one of its constructors and + /// then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Action action, Object state, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return Task.InternalStartNew(Task.InternalCurrent, action, state, cancellationToken, scheduler, + creationOptions, InternalTaskOptions.None, ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, m_defaultCancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// The that will be assigned to the new + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, cancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, m_defaultCancellationToken, + creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// The that will be assigned to the new task. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The TaskScheduler + /// that is used to schedule the created + /// Task{TResult}. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return Task.StartNew(Task.InternalCurrent, function, cancellationToken, + creationOptions, InternalTaskOptions.None, scheduler, ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, state, m_defaultCancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// The that will be assigned to the new + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, state, cancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state, TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, state, m_defaultCancellationToken, + creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// The type of the result available through the + /// Task. + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// The that will be assigned to the new task. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The TaskScheduler + /// that is used to schedule the created + /// Task{TResult}. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return Task.StartNew(Task.InternalCurrent, function, state, cancellationToken, + creationOptions, InternalTaskOptions.None, scheduler, ref stackMark); + } + + // + // FromAsync methods + // + + // Common core logic for FromAsync calls. This minimizes the chance of "drift" between overload implementations. + private static void FromAsyncCoreLogic(IAsyncResult iar, Action endMethod, TaskCompletionSource tcs) + { + Exception ex = null; + OperationCanceledException oce = null; + + try { endMethod(iar); } + catch (OperationCanceledException _oce) { oce = _oce; } + catch (Exception e) { ex = e; } + finally + { + if (oce != null) tcs.TrySetCanceled(); + else if (ex != null) + { + bool bWonSetException = tcs.TrySetException(ex); + if (bWonSetException && ThreadingServices.IsThreadAbort(ex)) + { + tcs.Task.m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); + } + } + else tcs.TrySetResult(null); + } + } + + /// + /// Creates a Task that executes an end method action + /// when a specified IAsyncResult completes. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The action delegate that processes the completed . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// A Task that represents the asynchronous + /// operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, + Action endMethod) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return FromAsync(asyncResult, endMethod, m_defaultCreationOptions, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a Task that executes an end method action + /// when a specified IAsyncResult completes. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The action delegate that processes the completed . + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// A Task that represents the asynchronous + /// operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, + Action endMethod, + TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return FromAsync(asyncResult, endMethod, creationOptions, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a Task that executes an end method action + /// when a specified IAsyncResult completes. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The action delegate that processes the completed . + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// A Task that represents the asynchronous + /// operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, + Action endMethod, + TaskCreationOptions creationOptions, + TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return FromAsync(asyncResult, endMethod, creationOptions, scheduler, ref stackMark); + } + + // private version that supports StackCrawlMark. + private Task FromAsync( + IAsyncResult asyncResult, + Action endMethod, + TaskCreationOptions creationOptions, + TaskScheduler scheduler, + ref StackCrawlMark stackMark) + { + if (asyncResult == null) + throw new ArgumentNullException("asyncResult"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + if (scheduler == null) + throw new ArgumentNullException("scheduler"); + CheckFromAsyncOptions(creationOptions, false); + + TaskCompletionSource tcs = new TaskCompletionSource(null, creationOptions); + + // Just specify this task as detached. No matter what happens, we want endMethod + // to be called -- even if the parent is canceled. + Task t = new Task(delegate + { + FromAsyncCoreLogic(asyncResult, endMethod, tcs); + }, + (object)null, Task.InternalCurrent, + CancellationToken.None, TaskCreationOptions.None, InternalTaskOptions.None, null, ref stackMark); + + if (asyncResult.IsCompleted) + { + try { t.RunSynchronously(scheduler); } + catch (Exception e) { tcs.TrySetException(e); } // catch and log any scheduler exceptions + } + else + { +#if !REGISTER_WAIT_FOR_SINGLE_OBJECT + // NOTE: This is an unfortunate hack to work around a RegisterWaitForSingleObject bug in WinPhone 7. + ThreadPool.QueueUserWorkItem(state => + { + var wh = (WaitHandle)state; + wh.WaitOne(); + try { t.RunSynchronously(scheduler); } + catch (Exception e) { tcs.TrySetException(e); } // catch and log any scheduler exceptions + }, asyncResult.AsyncWaitHandle); +#else + ThreadPool.RegisterWaitForSingleObject( + asyncResult.AsyncWaitHandle, + delegate + { + try { t.RunSynchronously(scheduler); } + catch (Exception e) { tcs.TrySetException(e); } // catch and log any scheduler exceptions + }, + null, + Timeout.Infinite, + true); +#endif + } + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, + object state) + { + return FromAsync(beginMethod, endMethod, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + CheckFromAsyncOptions(creationOptions, true); + + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(null); + throw; + } + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, + TArg1 arg1, + object state) + { + return FromAsync(beginMethod, endMethod, arg1, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, + TArg1 arg1, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + CheckFromAsyncOptions(creationOptions, true); + + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(arg1, iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(null); + throw; + } + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the + /// delegate. + /// The type of the second argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, + TArg1 arg1, TArg2 arg2, object state) + { + return FromAsync(beginMethod, endMethod, arg1, arg2, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the + /// delegate. + /// The type of the second argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, + TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + CheckFromAsyncOptions(creationOptions, true); + + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(arg1, arg2, iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(null); + throw; + } + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the + /// delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the third argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The third argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, + TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) + { + return FromAsync(beginMethod, endMethod, arg1, arg2, arg3, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of begin + /// and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the + /// delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the third argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The third argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that represents the + /// asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Action endMethod, + TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + CheckFromAsyncOptions(creationOptions, true); + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(arg1, arg2, arg3, iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(null); + throw; + } + + + return tcs.Task; + } + + // + // Additional FromAsync() overloads used for inferencing convenience + // + + /// + /// Creates a Task that executes an end + /// method function when a specified IAsyncResult completes. + /// + /// The type of the result available through the + /// Task. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The function delegate that processes the completed . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// A Task that represents the + /// asynchronous operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, Func endMethod) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return TaskFactory.FromAsyncImpl(asyncResult, endMethod, m_defaultCreationOptions, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a Task that executes an end + /// method function when a specified IAsyncResult completes. + /// + /// The type of the result available through the + /// Task. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The function delegate that processes the completed . + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// A Task that represents the + /// asynchronous operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, Func endMethod, TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return TaskFactory.FromAsyncImpl(asyncResult, endMethod, creationOptions, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a Task that executes an end + /// method function when a specified IAsyncResult completes. + /// + /// The type of the result available through the + /// Task. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The function delegate that processes the completed . + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// A Task that represents the + /// asynchronous operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, Func endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return TaskFactory.FromAsyncImpl(asyncResult, endMethod, creationOptions, scheduler, ref stackMark); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, object state) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, object state, TaskCreationOptions creationOptions) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, state, creationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, TArg1 arg1, object state) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, arg1, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, TArg1 arg1, object state, TaskCreationOptions creationOptions) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, arg1, state, creationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, object state) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, arg1, arg2, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, arg1, arg2, state, creationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the third argument passed to + /// delegate. + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The third argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, arg1, arg2, arg3, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the third argument passed to + /// delegate. + /// The type of the result available through the + /// Task. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The third argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + { + return TaskFactory.FromAsyncImpl(beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions); + } + + /// + /// Check validity of options passed to FromAsync method + /// + /// The options to be validated. + /// determines type of FromAsync method that called this method + internal static void CheckFromAsyncOptions(TaskCreationOptions creationOptions, bool hasBeginMethod) + { + if (hasBeginMethod) + { + // Options detected here cause exceptions in FromAsync methods that take beginMethod as a parameter + if ((creationOptions & TaskCreationOptions.LongRunning) != 0) + throw new ArgumentOutOfRangeException("creationOptions", Strings.Task_FromAsync_LongRunning); + if ((creationOptions & TaskCreationOptions.PreferFairness) != 0) + throw new ArgumentOutOfRangeException("creationOptions", Strings.Task_FromAsync_PreferFairness); + } + + // Check for general validity of options + if ((creationOptions & + ~(TaskCreationOptions.AttachedToParent | + TaskCreationOptions.PreferFairness | + TaskCreationOptions.LongRunning)) != 0) + { + throw new ArgumentOutOfRangeException("creationOptions"); + } + } + + // + // ContinueWhenAll methods + // + + // Performs some logic common to all ContinueWhenAll() overloads + // Returns the Task off of which to continue. + internal static Task CommonCWAllLogic(Task[] tasksCopy) + { + // tcs will be "fired" when final task completes + // We want tcs.Task to be DetachedFromParent. + // -- If rval gets directly canceled, we don't want tcs.Task recorded as a child of Task.InternalCurrent, + // because Task.InternalCurrent will then not be able to complete. + // -- If Task.InternalCurrent gets canceled, tcs.Task would never know about it. Again, best if it + // is not recorded as a child of Task.InternalCurrent. + TaskCompletionSource tcs = new TaskCompletionSource(); + + // intermediate continuation tasks will decrement tasksLeft + int tasksLeft = tasksCopy.Length; + + Action whenComplete = delegate(Task completedTask) + { + if (Interlocked.Decrement(ref tasksLeft) == 0) tcs.TrySetResult(true); + }; + + for (int i = 0; i < tasksCopy.Length; i++) + { + if (tasksCopy[i].IsCompleted) whenComplete(tasksCopy[i]); // Short-circuit the completion action, if possible + else tasksCopy[i].AddCompletionAction(whenComplete); // simple completion action + } + + return tcs.Task; + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in + /// the array have completed. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action continuationAction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in + /// the array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action continuationAction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in the array have completed. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action continuationAction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in the array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action continuationAction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + + // a private version that supports StackCrawlMark + private static Task ContinueWhenAll(Task[] tasks, Action continuationAction, TaskContinuationOptions continuationOptions, + CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + //check arguments + CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationAction == null) throw new ArgumentNullException("continuationAction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check the tasks array and make a defensive copy + Task[] tasksCopy = CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Perform some common ContinueWhenAll() setup actions + Task starter = CommonCWAllLogic(tasksCopy); + + // Preserve continuationOptions for this task, which is returned to the user. + Task rval = starter.ContinueWith(finishedTask => continuationAction(tasksCopy), scheduler, + cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in + /// the array have completed. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in + /// the array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction, + CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in the array have completed. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction, + TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The action delegate to execute when all tasks in the array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + + // a private version that supports StackCrawlMark + private static Task ContinueWhenAll(Task[] tasks, Action[]> continuationAction, + TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + //check arguments + CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationAction == null) throw new ArgumentNullException("continuationAction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check the tasks array and make a defensive copy + Task[] tasksCopy = CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Perform some common ContinueWhenAll() setup actions + Task starter = CommonCWAllLogic(tasksCopy); + + // Preserve continuationOptions for this task, which is returned to the user. + Task rval = starter.ContinueWith(finishedTask => continuationAction(tasksCopy), scheduler, + cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation . + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // a private version that supports StackCrawlMark + private Task ContinueWhenAll(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions, + CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // Delegate to TaskFactory + return TaskFactory.ContinueWhenAll(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation . + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // a private version that supports StackCrawlMark + private Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + TaskContinuationOptions continuationOptions,CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // Delegate to TaskFactory + return TaskFactory.ContinueWhenAll(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // Utility method to abstract some common logic to a single definition. + // Used by ContinueWhenAll/Any to bail out early on a pre-canceled token. + private static Task CreateCanceledTask(TaskContinuationOptions continuationOptions, CancellationToken ct) + { + InternalTaskOptions dontcare; + TaskCreationOptions tco; + Task.CreationOptionsFromContinuationOptions(continuationOptions, out tco, out dontcare); + return new Task(true, tco, ct); + } + + // + // ContinueWhenAny methods + // + + // Common ContinueWhenAny logic + // Returns Task off of which to create ultimate continuation task + internal static Task CommonCWAnyLogic(Task[] tasksCopy) + { + // tcs will be "fired" when the first task completes + TaskCompletionSource tcs = new TaskCompletionSource(); + + // The first task to complete will record itself as the Result of trs/starter. + Action whenComplete = delegate(Task t) + { + tcs.TrySetResult(t); + }; + + // At the completion of each task, fire whenComplete. + for (int i = 0; i < tasksCopy.Length; i++) + { + if (tcs.Task.IsCompleted) break; // Don't launch any more continuation tasks if trs has completed. + + // Shortcut if a task has already completed. + if (tasksCopy[i].IsCompleted) + { + // Short-circuit the creation of a completion task. + whenComplete(tasksCopy[i]); + + // We've found a winner. No need to create any more completion tasks. + break; + } + else tasksCopy[i].AddCompletionAction(whenComplete); + } + + return tcs.Task; + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the array completes. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action continuationAction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action continuationAction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the array completes. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action continuationAction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action continuationAction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // a private version that supports StackCrawlMark + private Task ContinueWhenAny(Task[] tasks, Action continuationAction, TaskContinuationOptions continuationOptions, + CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // Check arguments + CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationAction == null) throw new ArgumentNullException("continuationAction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check the tasks array and make a defensive copy + Task[] tasksCopy = CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Perform common ContinueWithAny() setup logic + Task starter = CommonCWAnyLogic(tasksCopy); + + // returned continuation task, fired when starter completes + Task rval = starter.ContinueWith(completedTask => continuationAction(completedTask.Result), scheduler, + cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation . + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // private version that supports StackCrawlMark + private Task ContinueWhenAny(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions, + CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // Delegate to TaskFactory + return TaskFactory.ContinueWhenAny(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result that is returned by the + /// delegate and associated with the created . + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation . + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // private version that supports StackCrawlMark + private Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // Delegate to TaskFactory + return TaskFactory.ContinueWhenAny(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the + /// array completes. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action> continuationAction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action> continuationAction, + CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the + /// array completes. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action> continuationAction, + TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The action delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation . + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Action> continuationAction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // private version that supports StackCrawlMark + private Task ContinueWhenAny(Task[] tasks, Action> continuationAction, + TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // check arguments + CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationAction == null) throw new ArgumentNullException("continuationAction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check tasks array and make defensive copy + Task[] tasksCopy = CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Call common ContinueWhenAny() setup logic, extract the starter + Task starter = CommonCWAnyLogic(tasksCopy); + + // returned continuation task, off of starter + Task rval = starter.ContinueWith(completedTask => + { + Task winner = completedTask.Result as Task; + continuationAction(winner); + }, scheduler, cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + // Check task array and return a defensive copy. + // Used with ContinueWhenAll()/ContinueWhenAny(). + internal static Task[] CheckMultiContinuationTasksAndCopy(Task[] tasks) + { + if (tasks == null) + throw new ArgumentNullException("tasks"); + if (tasks.Length == 0) + throw new ArgumentException(Strings.Task_MultiTaskContinuation_EmptyTaskList, "tasks"); + + Task[] tasksCopy = new Task[tasks.Length]; + for (int i = 0; i < tasks.Length; i++) + { + tasksCopy[i] = tasks[i]; + + if (tasksCopy[i] == null) + throw new ArgumentException(Strings.Task_MultiTaskContinuation_NullTask, "tasks"); + + //tasksCopy[i].ThrowIfDisposed(); + } + + return tasksCopy; + } + + internal static Task[] CheckMultiContinuationTasksAndCopy(Task[] tasks) + { + if (tasks == null) + throw new ArgumentNullException("tasks"); + if (tasks.Length == 0) + throw new ArgumentException(Strings.Task_MultiTaskContinuation_EmptyTaskList, "tasks"); + + Task[] tasksCopy = new Task[tasks.Length]; + for (int i = 0; i < tasks.Length; i++) + { + tasksCopy[i] = tasks[i]; + + if (tasksCopy[i] == null) + throw new ArgumentException(Strings.Task_MultiTaskContinuation_NullTask, "tasks"); + + //tasksCopy[i].ThrowIfDisposed(); + } + + return tasksCopy; + } + + // Throw an exception if "options" argument specifies illegal options + internal static void CheckMultiTaskContinuationOptions(TaskContinuationOptions continuationOptions) + { + // Construct a mask to check for illegal options + TaskContinuationOptions NotOnAny = TaskContinuationOptions.NotOnCanceled | + TaskContinuationOptions.NotOnFaulted | + TaskContinuationOptions.NotOnRanToCompletion; + + // Check that LongRunning and ExecuteSynchronously are not specified together + TaskContinuationOptions illegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning; + if ((continuationOptions & illegalMask) == illegalMask) + { + throw new ArgumentOutOfRangeException("continuationOptions", Strings.Task_ContinueWith_ESandLR); + } + + // Check that no nonsensical options are specified. + if ((continuationOptions & ~( + TaskContinuationOptions.LongRunning | + TaskContinuationOptions.PreferFairness | + TaskContinuationOptions.AttachedToParent | + NotOnAny | + TaskContinuationOptions.ExecuteSynchronously)) != 0) + { + throw new ArgumentOutOfRangeException("continuationOptions"); + } + + // Check that no "fire" options are specified. + if ((continuationOptions & NotOnAny) != 0) + throw new ArgumentOutOfRangeException("continuationOptions", Strings.Task_MultiTaskContinuation_FireOptions); + } + + + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskFactoryOfTResult.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskFactoryOfTResult.cs new file mode 100644 index 000000000..08d1c8d12 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskFactoryOfTResult.cs @@ -0,0 +1,1806 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// FutureFactory.cs +// +// joehoag +// +// As with TaskFactory, TaskFactory encodes common factory patterns into helper methods. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Security; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Diagnostics.Contracts; + +namespace System.Threading.Tasks +{ + /// + /// Provides support for creating and scheduling + /// Task{TResult} objects. + /// + /// The type of the results that are available though + /// the Task{TResult} objects that are associated with + /// the methods in this class. + /// + /// + /// There are many common patterns for which tasks are relevant. The + /// class encodes some of these patterns into methods that pick up default settings, which are + /// configurable through its constructors. + /// + /// + /// A default instance of is available through the + /// Task{TResult}.Factory property. + /// + /// + + public class TaskFactory + { + // Member variables, DefaultScheduler, other properties and ctors + // copied right out of TaskFactory... Lots of duplication here... + // Should we be thinking about a TaskFactoryBase class? + + // member variables + private CancellationToken m_defaultCancellationToken; + private TaskScheduler m_defaultScheduler; + private TaskCreationOptions m_defaultCreationOptions; + private TaskContinuationOptions m_defaultContinuationOptions; + + private TaskScheduler DefaultScheduler + { + get + { + if (m_defaultScheduler == null) return TaskScheduler.Current; + else return m_defaultScheduler; + } + } + + // sister method to above property -- avoids a TLS lookup + private TaskScheduler GetDefaultScheduler(Task currTask) + { + if (m_defaultScheduler != null) return m_defaultScheduler; + else if (currTask != null) return currTask.ExecutingTaskScheduler; + else return TaskScheduler.Default; + } + + /* Constructors */ + + /// + /// Initializes a instance with the default configuration. + /// + /// + /// This constructor creates a instance with a default configuration. The + /// property is initialized to + /// TaskCreationOptions.None, the + /// property is initialized to TaskContinuationOptions.None, + /// and the TaskScheduler property is + /// initialized to the current scheduler (see TaskScheduler.Current). + /// + public TaskFactory() + : this(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, null) + { + } + + /// + /// Initializes a instance with the default configuration. + /// + /// The default that will be assigned + /// to tasks created by this unless another CancellationToken is explicitly specified + /// while calling the factory methods. + /// + /// This constructor creates a instance with a default configuration. The + /// property is initialized to + /// TaskCreationOptions.None, the + /// property is initialized to TaskContinuationOptions.None, + /// and the TaskScheduler property is + /// initialized to the current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(CancellationToken cancellationToken) + : this(cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null) + { + } + + /// + /// Initializes a instance with the specified configuration. + /// + /// + /// The + /// TaskScheduler to use to schedule any tasks created with this TaskFactory{TResult}. A null value + /// indicates that the current TaskScheduler should be used. + /// + /// + /// With this constructor, the + /// property is initialized to + /// TaskCreationOptions.None, the + /// property is initialized to TaskContinuationOptions.None, + /// and the TaskScheduler property is + /// initialized to , unless it's null, in which case the property is + /// initialized to the current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(TaskScheduler scheduler) // null means to use TaskScheduler.Current + : this(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler) + { + } + + /// + /// Initializes a instance with the specified configuration. + /// + /// + /// The default + /// TaskCreationOptions to use when creating tasks with this TaskFactory{TResult}. + /// + /// + /// The default + /// TaskContinuationOptions to use when creating continuation tasks with this TaskFactory{TResult}. + /// + /// + /// The exception that is thrown when the + /// argument or the + /// argument specifies an invalid value. + /// + /// + /// With this constructor, the + /// property is initialized to , + /// the + /// property is initialized to , and the TaskScheduler property is initialized to the + /// current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions) + : this(CancellationToken.None, creationOptions, continuationOptions, null) + { + } + + /// + /// Initializes a instance with the specified configuration. + /// + /// The default that will be assigned + /// to tasks created by this unless another CancellationToken is explicitly specified + /// while calling the factory methods. + /// + /// The default + /// TaskCreationOptions to use when creating tasks with this TaskFactory{TResult}. + /// + /// + /// The default + /// TaskContinuationOptions to use when creating continuation tasks with this TaskFactory{TResult}. + /// + /// + /// The default + /// TaskScheduler to use to schedule any Tasks created with this TaskFactory{TResult}. A null value + /// indicates that TaskScheduler.Current should be used. + /// + /// + /// The exception that is thrown when the + /// argument or the + /// argumentspecifies an invalid value. + /// + /// + /// With this constructor, the + /// property is initialized to , + /// the + /// property is initialized to , and the TaskScheduler property is initialized to + /// , unless it's null, in which case the property is initialized to the + /// current scheduler (see TaskScheduler.Current). + /// + public TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + m_defaultCancellationToken = cancellationToken; + m_defaultScheduler = scheduler; + m_defaultCreationOptions = creationOptions; + m_defaultContinuationOptions = continuationOptions; + TaskFactory.CheckCreationOptions(m_defaultCreationOptions); + TaskFactory.CheckMultiTaskContinuationOptions(m_defaultContinuationOptions); + + } + + /* Properties */ + + /// + /// Gets the default CancellationToken of this + /// TaskFactory. + /// + /// + /// This property returns the default that will be assigned to all + /// tasks created by this factory unless another CancellationToken value is explicitly specified + /// during the call to the factory methods. + /// + public CancellationToken CancellationToken { get { return m_defaultCancellationToken; } } + + /// + /// Gets the TaskScheduler of this + /// TaskFactory{TResult}. + /// + /// + /// This property returns the default scheduler for this factory. It will be used to schedule all + /// tasks unless another scheduler is explicitly specified during calls to this factory's methods. + /// If null, TaskScheduler.Current + /// will be used. + /// + public TaskScheduler Scheduler { get { return m_defaultScheduler; } } + + /// + /// Gets the TaskCreationOptions + /// value of this TaskFactory{TResult}. + /// + /// + /// This property returns the default creation options for this factory. They will be used to create all + /// tasks unless other options are explicitly specified during calls to this factory's methods. + /// + public TaskCreationOptions CreationOptions { get { return m_defaultCreationOptions; } } + + /// + /// Gets the TaskContinuationOptions + /// value of this TaskFactory{TResult}. + /// + /// + /// This property returns the default continuation options for this factory. They will be used to create + /// all continuation tasks unless other options are explicitly specified during calls to this factory's methods. + /// + public TaskContinuationOptions ContinuationOptions { get { return m_defaultContinuationOptions; } } + + + /* StartNew */ + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, m_defaultCancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// The that will be assigned to the new task. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, cancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, m_defaultCancellationToken, + creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The that will be assigned to the new task. + /// The TaskScheduler + /// that is used to schedule the created + /// Task{TResult}. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return Task.StartNew(Task.InternalCurrent, function, cancellationToken, + creationOptions, InternalTaskOptions.None, scheduler, ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, state, m_defaultCancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// The that will be assigned to the new task. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, state, cancellationToken, + m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state, TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Task currTask = Task.InternalCurrent; + return Task.StartNew(currTask, function, state, m_defaultCancellationToken, + creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); + } + + /// + /// Creates and starts a . + /// + /// A function delegate that returns the future result to be available through + /// the . + /// An object containing data to be used by the + /// delegate. + /// The that will be assigned to the new task. + /// A TaskCreationOptions value that controls the behavior of the + /// created + /// . + /// The TaskScheduler + /// that is used to schedule the created + /// Task{TResult}. + /// The started . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// Calling StartNew is functionally equivalent to creating a using one + /// of its constructors and then calling + /// Start to schedule it for execution. + /// However, unless creation and scheduling must be separated, StartNew is the recommended approach + /// for both simplicity and performance. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task StartNew(Func function, Object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return Task.StartNew(Task.InternalCurrent, function, state, cancellationToken, + creationOptions, InternalTaskOptions.None, scheduler, ref stackMark); + } + + // + // APM Factory methods + // + + // Common core logic for FromAsync calls. This minimizes the chance of "drift" between overload implementations. + private static void FromAsyncCoreLogic(IAsyncResult iar, Func endMethod, TaskCompletionSource tcs) + { + Exception ex = null; + OperationCanceledException oce = null; + TResult result = default(TResult); + + try { result = endMethod(iar); } + catch (OperationCanceledException _oce) { oce = _oce; } + catch (Exception e) { ex = e; } + finally + { + if (oce != null) tcs.TrySetCanceled(); + else if (ex != null) + { + bool bWonSetException = tcs.TrySetException(ex); + if (bWonSetException && ThreadingServices.IsThreadAbort(ex)) + { + tcs.Task.m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); + } + } + else tcs.TrySetResult(result); + } + } + + /// + /// Creates a Task that executes an end + /// method function when a specified IAsyncResult completes. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The function delegate that processes the completed . + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// A Task that represents the + /// asynchronous operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, + Func endMethod) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return FromAsyncImpl(asyncResult, endMethod, m_defaultCreationOptions, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a Task that executes an end + /// method function when a specified IAsyncResult completes. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The function delegate that processes the completed . + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// A Task that represents the + /// asynchronous operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, + Func endMethod, + TaskCreationOptions creationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return FromAsyncImpl(asyncResult, endMethod, creationOptions, DefaultScheduler, ref stackMark); + } + + + + /// + /// Creates a Task that executes an end + /// method function when a specified IAsyncResult completes. + /// + /// The IAsyncResult whose completion should trigger the processing of the + /// . + /// The function delegate that processes the completed . + /// The TaskScheduler + /// that is used to schedule the task that executes the end method. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// A Task that represents the + /// asynchronous operation. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task FromAsync( + IAsyncResult asyncResult, + Func endMethod, + TaskCreationOptions creationOptions, + TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return FromAsyncImpl(asyncResult, endMethod, creationOptions, scheduler, ref stackMark); + } + + // internal overload that supports StackCrawlMark + // We also need this logic broken out into a static method so that the similar TaskFactory.FromAsync() + // method can access the logic w/o declaring a TaskFactory instance. + internal static Task FromAsyncImpl( + IAsyncResult asyncResult, + Func endMethod, + TaskCreationOptions creationOptions, + TaskScheduler scheduler, + ref StackCrawlMark stackMark) + { + if (asyncResult == null) + throw new ArgumentNullException("asyncResult"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + if (scheduler == null) + throw new ArgumentNullException("scheduler"); + TaskFactory.CheckFromAsyncOptions(creationOptions, false); + + TaskCompletionSource tcs = new TaskCompletionSource(creationOptions); + + // Just specify this task as detached. No matter what happens, we want endMethod + // to be called -- even if the parent is canceled. So we don't want to flow + // RespectParentCancellation. + Task t = new Task(delegate + { + FromAsyncCoreLogic(asyncResult, endMethod, tcs); + }, + (object)null, Task.InternalCurrent, + CancellationToken.None, TaskCreationOptions.None, InternalTaskOptions.None, null, ref stackMark); + + if (asyncResult.IsCompleted) + { + try { t.RunSynchronously(scheduler); } + catch (Exception e) { tcs.TrySetException(e); } // catch and log any scheduler exceptions + } + else + { +#if !REGISTER_WAIT_FOR_SINGLE_OBJECT + // NOTE: This is an unfortunate hack to work around a RegisterWaitForSingleObject bug in WinPhone 7. + ThreadPool.QueueUserWorkItem(state => + { + var wh = (WaitHandle)state; + wh.WaitOne(); + try { t.RunSynchronously(scheduler); } + catch (Exception e) { tcs.TrySetException(e); } // catch and log any scheduler exceptions + }, asyncResult.AsyncWaitHandle); +#else + + ThreadPool.RegisterWaitForSingleObject( + asyncResult.AsyncWaitHandle, + delegate + { + try { t.RunSynchronously(scheduler); } + catch (Exception e) { tcs.TrySetException(e); } // catch and log any scheduler exceptions + }, + null, + Timeout.Infinite, + true); +#endif + } + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, object state) + { + return FromAsyncImpl(beginMethod, endMethod, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, object state, TaskCreationOptions creationOptions) + { + return FromAsyncImpl(beginMethod, endMethod, state, creationOptions); + } + + // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() + // method can access the logic w/o declaring a TaskFactory instance. + internal static Task FromAsyncImpl( + Func beginMethod, + Func endMethod, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + TaskFactory.CheckFromAsyncOptions(creationOptions, true); + + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(default(TResult)); + throw; + } + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, + TArg1 arg1, object state) + { + return FromAsyncImpl(beginMethod, endMethod, arg1, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, + TArg1 arg1, object state, TaskCreationOptions creationOptions) + { + return FromAsyncImpl(beginMethod, endMethod, arg1, state, creationOptions); + } + + // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() + // method can access the logic w/o declaring a TaskFactory instance. + internal static Task FromAsyncImpl( + Func beginMethod, + Func endMethod, + TArg1 arg1, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + TaskFactory.CheckFromAsyncOptions(creationOptions, true); + + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(arg1, iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(default(TResult)); + throw; + } + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, + TArg1 arg1, TArg2 arg2, object state) + { + return FromAsyncImpl(beginMethod, endMethod, arg1, arg2, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, + TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + { + return FromAsyncImpl(beginMethod, endMethod, arg1, arg2, state, creationOptions); + } + + // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() + // method can access the logic w/o declaring a TaskFactory instance. + internal static Task FromAsyncImpl( + Func beginMethod, + Func endMethod, + TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + TaskFactory.CheckFromAsyncOptions(creationOptions, true); + + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(arg1, arg2, iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(default(TResult)); + throw; + } + + + return tcs.Task; + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the third argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The third argument passed to the + /// delegate. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, + TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) + { + return FromAsyncImpl(beginMethod, endMethod, arg1, arg2, arg3, state, m_defaultCreationOptions); + } + + /// + /// Creates a Task that represents a pair of + /// begin and end methods that conform to the Asynchronous Programming Model pattern. + /// + /// The type of the first argument passed to the delegate. + /// The type of the second argument passed to + /// delegate. + /// The type of the third argument passed to + /// delegate. + /// The delegate that begins the asynchronous operation. + /// The delegate that ends the asynchronous operation. + /// The first argument passed to the + /// delegate. + /// The second argument passed to the + /// delegate. + /// The third argument passed to the + /// delegate. + /// The TaskCreationOptions value that controls the behavior of the + /// created Task. + /// An object containing data to be used by the + /// delegate. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument specifies an invalid TaskCreationOptions + /// value. + /// The created Task that + /// represents the asynchronous operation. + /// + /// This method throws any exceptions thrown by the . + /// + public Task FromAsync( + Func beginMethod, + Func endMethod, + TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + { + return FromAsyncImpl(beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions); + } + + // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() + // method can access the logic w/o declaring a TaskFactory instance. + internal static Task FromAsyncImpl( + Func beginMethod, + Func endMethod, + TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + { + if (beginMethod == null) + throw new ArgumentNullException("beginMethod"); + if (endMethod == null) + throw new ArgumentNullException("endMethod"); + TaskFactory.CheckFromAsyncOptions(creationOptions, true); + + TaskCompletionSource tcs = new TaskCompletionSource(state, creationOptions); + + try + { + beginMethod(arg1, arg2, arg3, iar => + { + FromAsyncCoreLogic(iar, endMethod, tcs); + }, state); + } + catch + { + // Make sure we don't leave tcs "dangling". + tcs.TrySetResult(default(TResult)); + throw; + } + + return tcs.Task; + } + + // Utility method to create a canceled future-style task. + // Used by ContinueWhenAll/Any to bail out early on a pre-canceled token. + private static Task CreateCanceledTask(TaskContinuationOptions continuationOptions, CancellationToken ct) + { + TaskCreationOptions tco; + InternalTaskOptions dontcare; + Task.CreationOptionsFromContinuationOptions(continuationOptions, out tco, out dontcare); + return new Task(true, default(TResult), tco, ct); + } + + // + // ContinueWhenAll() methods + // + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in + /// the array have completed. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in + /// the array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the array have completed. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func continuationFunction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + + // Private method to support StackCrawlMark. + internal static Task ContinueWhenAll(Task[] tasks, Func continuationFunction, + TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // check arguments + TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationFunction == null) throw new ArgumentNullException("continuationFunction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check tasks array and make defensive copy + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Perform common ContinueWhenAll() setup logic, extract starter task + Task starter = TaskFactory.CommonCWAllLogic(tasksCopy); + + // returned continuation task, off of starter + Task rval = starter.ContinueWith(finishedTask => { return continuationFunction(tasksCopy); }, scheduler, + cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of a set of provided Tasks. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue. + /// The function delegate to execute when all tasks in the + /// array have completed. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation . + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAll. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAll(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // internal (instead of private) so that it can be called from the similar TaskFactory.ContinueWhenAll() method. + internal static Task ContinueWhenAll(Task[] tasks, Func[], TResult> continuationFunction, + TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // check arguments + TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationFunction == null) throw new ArgumentNullException("continuationFunction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check tasks array and make defensive copy + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Call common ContinueWhenAll() setup logic, extract starter task. + Task starter = TaskFactory.CommonCWAllLogic(tasksCopy); + + // returned continuation task, off of starter + Task rval = starter.ContinueWith(finishedTask => { return continuationFunction(tasksCopy); }, scheduler, + cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + + // + // ContinueWhenAny() methods + // + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the array completes. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the array completes. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation Task. + /// The new continuation Task. + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func continuationFunction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // internal version that supports StackCrawlMark + internal static Task ContinueWhenAny(Task[] tasks, Func continuationFunction, + TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // check arguments + TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationFunction == null) throw new ArgumentNullException("continuationFunction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check tasks array and make defensive copy + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Call common ContinueWhenAny() setup logic, extract starter + Task starter = TaskFactory.CommonCWAnyLogic(tasksCopy); + + // returned continuation task, off of starter + Task rval = starter.ContinueWith(completedTask => + { + return continuationFunction(completedTask.Result); + }, scheduler, cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark); + } + + /// + /// Creates a continuation Task + /// that will be started upon the completion of any Task in the provided set. + /// + /// The type of the result of the antecedent . + /// The array of tasks from which to continue when one task completes. + /// The function delegate to execute when one task in the + /// array completes. + /// The CancellationToken + /// that will be assigned to the new continuation task. + /// The + /// TaskContinuationOptions value that controls the behavior of + /// the created continuation Task. + /// The TaskScheduler + /// that is used to schedule the created continuation . + /// The new continuation . + /// The exception that is thrown when the + /// array is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// argument is null. + /// The exception that is thrown when the + /// array contains a null value. + /// The exception that is thrown when the + /// array is empty. + /// The exception that is thrown when the + /// argument specifies an invalid TaskContinuationOptions + /// value. + /// The exception that is thrown when one + /// of the elements in the array has been disposed. + /// The provided CancellationToken + /// has already been disposed. + /// + /// + /// The NotOn* and OnlyOn* TaskContinuationOptions, + /// which constrain for which TaskStatus states a continuation + /// will be executed, are illegal with ContinueWhenAny. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWhenAny(tasks, continuationFunction, continuationOptions, cancellationToken, scheduler, ref stackMark); + } + + // internal version to support StackCrawlMark + internal static Task ContinueWhenAny(Task[] tasks, Func, TResult> continuationFunction, + TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + // check arguments + TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); + if (tasks == null) throw new ArgumentNullException("tasks"); + if (continuationFunction == null) throw new ArgumentNullException("continuationFunction"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // Check tasks array and make defensive copy + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks); + + // Bail early if cancellation has been requested. + if (cancellationToken.IsCancellationRequested) + { + return CreateCanceledTask(continuationOptions, cancellationToken); + } + + // Call common ContinueWhenAny setup logic, extract starter + Task starter = TaskFactory.CommonCWAnyLogic(tasksCopy); + + // returned continuation task, off of starter + Task rval = starter.ContinueWith(completedTask => + { + Task winner = completedTask.Result as Task; + return continuationFunction(winner); + }, scheduler, cancellationToken, continuationOptions, ref stackMark); + + return rval; + } + + + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskOfTResult.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskOfTResult.cs new file mode 100644 index 000000000..2da04ebc3 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskOfTResult.cs @@ -0,0 +1,1086 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// Future.cs +// +// hyildiz +// +// A task that produces a value. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading; +using System.Diagnostics; +using System.Diagnostics.Contracts; + +// Disable the "reference to volatile field not treated as volatile" error. +#pragma warning disable 0420 + +namespace System.Threading.Tasks +{ + + /// + /// Represents an asynchronous operation that produces a result at some time in the future. + /// + /// + /// The type of the result produced by this . + /// + /// + /// + /// instances may be created in a variety of ways. The most common approach is by + /// using the task's property to retrieve a instance that can be used to create tasks for several + /// purposes. For example, to create a that runs a function, the factory's StartNew + /// method may be used: + /// + /// // C# + /// var t = Task<int>.Factory.StartNew(() => GenerateResult()); + /// - or - + /// var t = Task.Factory.StartNew(() => GenerateResult()); + /// + /// ' Visual Basic + /// Dim t = Task<int>.Factory.StartNew(Function() GenerateResult()) + /// - or - + /// Dim t = Task.Factory.StartNew(Function() GenerateResult()) + /// + /// + /// + /// The class also provides constructors that initialize the task but that do not + /// schedule it for execution. For performance reasons, the StartNew method should be the + /// preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation + /// and scheduling must be separated, the constructors may be used, and the task's + /// Start + /// method may then be used to schedule the task for execution at a later time. + /// + /// + /// All members of , except for + /// Dispose, are thread-safe + /// and may be used from multiple threads concurrently. + /// + /// + + [DebuggerTypeProxy(typeof(SystemThreadingTasks_FutureDebugView<>))] + [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}, Result = {DebuggerDisplayResultDescription}")] + public class Task : Task + { + private object m_valueSelector; // The function which produces a value. + private TResult m_result; // The value itself, if set. + internal bool m_resultWasSet; // Whether the value has been set (needed for structs). + private object m_futureState; + + + private static TaskFactory s_Factory = new TaskFactory(); + + + // Construct a promise-style task with state and options. Only used internally, for + // initializing TaskCompletionSource.m_task. + internal Task(object state, CancellationToken cancellationToken, TaskCreationOptions options, InternalTaskOptions internalOptions) + : base(null, cancellationToken, options, internalOptions, true) + { + m_valueSelector = null; + m_futureState = state; + } + + // Construct a pre-completed Task + internal Task(bool canceled, TResult result, TaskCreationOptions creationOptions, CancellationToken ct) + : base(canceled, creationOptions, ct) + { + if (!canceled) + { + m_result = result; + m_resultWasSet = true; + } + } + + /// + /// Initializes a new with the specified function. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// + /// The argument is null. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function) + : this(function, Task.InternalCurrent, CancellationToken.None, + TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + + /// + /// Initializes a new with the specified function. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// The to be assigned to this task. + /// + /// The argument is null. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function, CancellationToken cancellationToken) + : this(function, Task.InternalCurrent, cancellationToken, + TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified function and creation options. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// + /// The TaskCreationOptions used to + /// customize the task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function, TaskCreationOptions creationOptions) + : this(function, Task.InternalCurrent, CancellationToken.None, creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified function and creation options. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// The that will be assigned to the new task. + /// + /// The TaskCreationOptions used to + /// customize the task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function, CancellationToken cancellationToken, TaskCreationOptions creationOptions) + : this(function, Task.InternalCurrent, cancellationToken, creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified function and state. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// An object representing data to be used by the action. + /// + /// The argument is null. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function, object state) + : this(function, state, Task.InternalCurrent, CancellationToken.None, + TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action, state, and options. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// An object representing data to be used by the function. + /// The to be assigned to the new task. + /// + /// The argument is null. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function, object state, CancellationToken cancellationToken) + : this(function, state, Task.InternalCurrent, cancellationToken, + TaskCreationOptions.None, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Initializes a new with the specified action, state, and options. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// An object representing data to be used by the function. + /// + /// The TaskCreationOptions used to + /// customize the task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function, object state, TaskCreationOptions creationOptions) + : this(function, state, Task.InternalCurrent, CancellationToken.None, + creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + + /// + /// Initializes a new with the specified action, state, and options. + /// + /// + /// The delegate that represents the code to execute in the task. When the function has completed, + /// the task's property will be set to return the result value of the function. + /// + /// An object representing data to be used by the function. + /// The to be assigned to the new task. + /// + /// The TaskCreationOptions used to + /// customize the task's behavior. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for . + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) + : this(function, state, Task.InternalCurrent, cancellationToken, + creationOptions, InternalTaskOptions.None, null) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + PossiblyCaptureContext(ref stackMark); + } + + // For Task.ContinueWith() and Future.ContinueWith() + internal Task( + Func valueSelector, Task parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, + ref StackCrawlMark stackMark) : + this(valueSelector, parent, cancellationToken, + creationOptions, internalOptions, scheduler) + { + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Creates a new future object. + /// + /// The parent task for this future. + /// A function that yields the future value. + /// The task scheduler which will be used to execute the future. + /// The CancellationToken for the task. + /// Options to control the future's behavior. + /// Internal options to control the future's behavior. + /// The argument specifies + /// a SelfReplicating , which is illegal."/>. + internal Task(Func valueSelector, Task parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) : + base((valueSelector != null ? InvokeFuture : (Action)null), null, parent, cancellationToken, creationOptions, internalOptions, scheduler) + { + if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) + { + throw new ArgumentOutOfRangeException("creationOptions", Strings.TaskT_ctor_SelfReplicating); + } + + m_valueSelector = valueSelector; + m_stateObject = this; + } + + // For Task.ContinueWith() and Future.ContinueWith() + internal Task( + Func valueSelector, object state, Task parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) : + this(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler) + { + PossiblyCaptureContext(ref stackMark); + } + + /// + /// Creates a new future object. + /// + /// The parent task for this future. + /// An object containing data to be used by the action; may be null. + /// A function that yields the future value. + /// The CancellationToken for the task. + /// The task scheduler which will be used to execute the future. + /// Options to control the future's behavior. + /// Internal options to control the future's behavior. + /// The argument specifies + /// a SelfReplicating , which is illegal."/>. + internal Task(Func valueSelector, object state, Task parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) : + base((valueSelector != null ? InvokeFuture : (Action)null), null, parent, cancellationToken, creationOptions, internalOptions, scheduler) + { + if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) + { + throw new ArgumentOutOfRangeException("creationOptions", Strings.TaskT_ctor_SelfReplicating); + } + + m_valueSelector = valueSelector; + m_stateObject = this; + m_futureState = state; // necessary to differentiate state from "this" + } + + + // Internal method used by TaskFactory.StartNew() methods + internal static Task StartNew(Task parent, Func function, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + if (function == null) + { + throw new ArgumentNullException("function"); + } + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) + { + // @BUGBUG: the spec says this should just ignore Selfreplicating. I believe we ought to throw. + throw new ArgumentOutOfRangeException("creationOptions", Strings.TaskT_ctor_SelfReplicating); + } + + // Create and schedule the future. + Task f = new Task(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark); + + f.ScheduleAndStart(false); + return f; + } + + // Internal method used by TaskFactory.StartNew() methods + internal static Task StartNew(Task parent, Func function, object state, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) + { + if (function == null) + { + throw new ArgumentNullException("function"); + } + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) + { + throw new ArgumentOutOfRangeException("creationOptions", Strings.TaskT_ctor_SelfReplicating); + } + + // Create and schedule the future. + Task f = new Task(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark); + + f.ScheduleAndStart(false); + return f; + } + + // Debugger support + private string DebuggerDisplayResultDescription + { + get { return m_resultWasSet ? "" + m_result : Strings.TaskT_DebuggerNoResult; } + } + + // Debugger support + private string DebuggerDisplayMethodDescription + { + get + { + Delegate d = (Delegate)m_valueSelector; + return d != null ? d.Method.ToString() : "{null}"; + } + } + + + // internal helper function breaks out logic used by TaskCompletionSource + internal bool TrySetResult(TResult result) + { + //ThrowIfDisposed(); + if (IsCompleted) return false; + Contract.Assert(m_valueSelector == null, "Task.TrySetResult(): non-null m_valueSelector"); + + // "Reserve" the completion for this task, while making sure that: (1) No prior reservation + // has been made, (2) The result has not already been set, (3) An exception has not previously + // been recorded, and (4) Cancellation has not been requested. + // + // If the reservation is successful, then set the result and finish completion processing. + if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED, + TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) + { + m_result = result; + m_resultWasSet = true; + + // Signal completion, for waiting tasks + Finish(false); + + return true; + } + + return false; + } + + /// + /// Gets the result value of this . + /// + /// + /// The get accessor for this property ensures that the asynchronous operation is complete before + /// returning. Once the result of the computation is available, it is stored and will be returned + /// immediately on later calls to . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public TResult Result + { + get + { + // If the result has not been calculated yet, wait for it. + if (!IsCompleted) + { + // We call NOCTD for two reasons: + // 1. If the task runs on another thread, then we definitely need to notify that thread-slipping is required. + // 2. If the task runs inline but takes some time to complete, it will suffer ThreadAbort with possible state corruption. + // - it is best to prevent this unless the user explicitly asks to view the value with thread-slipping enabled. +//#if !PFX_LEGACY_3_5 +// Debugger.NotifyOfCrossThreadDependency(); +//#endif + Wait(); + } + + // Throw an exception if appropriate. + ThrowIfExceptional(!m_resultWasSet); + + // We shouldn't be here if the result has not been set. + Contract.Assert(m_resultWasSet, "Task.Result getter: Expected result to have been set."); + + return m_result; + } + internal set + { + Contract.Assert(m_valueSelector == null, "Task.Result_set: m_valueSelector != null"); + + if (!TrySetResult(value)) + { + throw new InvalidOperationException(Strings.TaskT_TransitionToFinal_AlreadyCompleted); + } + } + } + + // Allow multiple exceptions to be assigned to a promise-style task. + // This is useful when a TaskCompletionSource stands in as a proxy + // for a "real" task (as we do in Unwrap(), ContinueWhenAny() and ContinueWhenAll()) + // and the "real" task ends up with multiple exceptions, which is possible when + // a task has children. + // + // Called from TaskCompletionSource.SetException(IEnumerable). + internal bool TrySetException(object exceptionObject) + { + //ThrowIfDisposed(); + Contract.Assert(m_valueSelector == null, "Task.TrySetException(): non-null m_valueSelector"); + + // TCS.{Try}SetException() should have checked for this + Contract.Assert(exceptionObject != null, "Expected non-null exceptionObject argument"); + + // Only accept these types. + Contract.Assert((exceptionObject is Exception) || (exceptionObject is IEnumerable), + "Expected exceptionObject to be either Exception or IEnumerable"); + + bool returnValue = false; + + // "Reserve" the completion for this task, while making sure that: (1) No prior reservation + // has been made, (2) The result has not already been set, (3) An exception has not previously + // been recorded, and (4) Cancellation has not been requested. + // + // If the reservation is successful, then add the exception(s) and finish completion processing. + // + // The lazy initialization may not be strictly necessary, but I'd like to keep it here + // anyway. Some downstream logic may depend upon an inflated m_contingentProperties. + LazyInitializer.EnsureInitialized(ref m_contingentProperties, Task.s_contingentPropertyCreator); + if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED, + TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) + { + AddException(exceptionObject); // handles singleton exception or exception collection + Finish(false); + returnValue = true; + } + + return returnValue; + + } + + /// + /// Provides access to factory methods for creating instances. + /// + /// + /// The factory returned from is a default instance + /// of , as would result from using + /// the default constructor on the factory type. + /// + public new static TaskFactory Factory { get { return s_Factory; } } + + // Allow Task.AsyncState, inherited from Task, to function correctly. + internal override object InternalAsyncState + { + get { return m_futureState; } + } + + /// + /// Evaluates the value selector of the Task which is passed in as an object and stores the result. + /// + private static void InvokeFuture(object futureAsObj) + { + Task f = ((Task)futureAsObj); + + Contract.Assert(f.m_valueSelector != null); + + // f.m_value can be a Func or a Func. Figure out which one it is and do the right thing. + Func func = f.m_valueSelector as Func; + try + { + if (func != null) + f.m_result = func(); + else + f.m_result = ((Func)f.m_valueSelector)(f.m_futureState); + + f.m_resultWasSet = true; + } + finally + { + f.m_valueSelector = null; // bound memory usage in long continuation chains + } + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action> continuationAction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, TaskScheduler.Current, CancellationToken.None, TaskContinuationOptions.None, ref stackMark); + } + + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// The that will be assigned to the new continuation task. + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action> continuationAction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); + } + + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// The to associate with the continuation task and to use for its execution. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action> continuationAction, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, scheduler, CancellationToken.None, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled + /// instead of scheduled. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action> continuationAction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, TaskScheduler.Current, CancellationToken.None, continuationOptions, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// An action to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// The that will be assigned to the new continuation task. + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// + /// The to associate with the continuation task and to use for its + /// execution. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed. If the criteria specified through the parameter + /// are not met, the continuation task will be canceled instead of scheduled. + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Action> continuationAction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark); + } + + // Same as the above overload, only with a stack mark. + internal Task ContinueWith(Action> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) + { + //ThrowIfDisposed(); + + if (continuationAction == null) + { + throw new ArgumentNullException("continuationAction"); + } + + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + TaskCreationOptions creationOptions; + InternalTaskOptions internalOptions; + CreationOptionsFromContinuationOptions( + continuationOptions, + out creationOptions, + out internalOptions); + + Task thisFuture = this; + Task continuationTask = new Task( + delegate(object obj) { continuationAction(thisFuture); }, + null, + Task.InternalCurrent, + cancellationToken, + creationOptions, + internalOptions, + null, // leave scheduler null until TaskContinuation.Run() is called + ref stackMark + ); + + // Register the continuation. If synchronous execution is requested, this may + // actually invoke the continuation before returning. + ContinueWithCore(continuationTask, scheduler, continuationOptions); + + return continuationTask; + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current + /// task has completed, whether it completes due to running to completion successfully, faulting due + /// to an unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func, TNewResult> continuationFunction) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, TaskScheduler.Current, CancellationToken.None, TaskContinuationOptions.None, ref stackMark); + } + + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// The that will be assigned to the new task. + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current + /// task has completed, whether it completes due to running to completion successfully, faulting due + /// to an unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func, TNewResult> continuationFunction, CancellationToken cancellationToken) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// The to associate with the continuation task and to use for its execution. + /// + /// A new continuation . + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The argument is null. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func, TNewResult> continuationFunction, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, scheduler, CancellationToken.None, TaskContinuationOptions.None, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be + /// passed the completed task as an argument. + /// + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// A new continuation . + /// + /// + /// The returned will not be scheduled for execution until the current + /// task has completed, whether it completes due to running to completion successfully, faulting due + /// to an unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The , when executed, should return a . This task's completion state will be transferred to the task returned + /// from the ContinueWith call. + /// + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The has been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func, TNewResult> continuationFunction, TaskContinuationOptions continuationOptions) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, TaskScheduler.Current, CancellationToken.None, continuationOptions, ref stackMark); + } + + /// + /// Creates a continuation that executes when the target completes. + /// + /// + /// The type of the result produced by the continuation. + /// + /// + /// A function to run when the completes. When run, the delegate will be passed as + /// an argument this completed task. + /// + /// The that will be assigned to the new task. + /// + /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such + /// as OnlyOnCanceled, as + /// well as execution options, such as ExecuteSynchronously. + /// + /// + /// The to associate with the continuation task and to use for its + /// execution. + /// + /// A new continuation . + /// + /// + /// The returned will not be scheduled for execution until the current task has + /// completed, whether it completes due to running to completion successfully, faulting due to an + /// unhandled exception, or exiting out early due to being canceled. + /// + /// + /// The , when executed, should return a . + /// This task's completion state will be transferred to the task returned from the + /// ContinueWith call. + /// + /// + /// + /// The argument is null. + /// + /// + /// The argument specifies an invalid value for TaskContinuationOptions. + /// + /// + /// The argument is null. + /// + /// + /// The has been disposed. + /// + /// The provided CancellationToken + /// has already been disposed. + /// + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable + public Task ContinueWith(Func, TNewResult> continuationFunction, CancellationToken cancellationToken, + TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + { + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + return ContinueWith(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark); + } + + // Same as the above overload, just with a stack mark. + internal Task ContinueWith(Func, TNewResult> continuationFunction, TaskScheduler scheduler, + CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark) + { + //ThrowIfDisposed(); + + if (continuationFunction == null) + { + throw new ArgumentNullException("continuationFunction"); + } + + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + TaskCreationOptions creationOptions; + InternalTaskOptions internalOptions; + CreationOptionsFromContinuationOptions( + continuationOptions, + out creationOptions, + out internalOptions); + + Task thisFuture = this; + Task continuationFuture = new Task( + delegate() { return continuationFunction(thisFuture); }, + Task.InternalCurrent, + cancellationToken, + creationOptions, + internalOptions, + null, // leave scheduler null until TaskContinuation.Run() is called. + ref stackMark + ); + + // Register the continuation. If synchronous execution is requested, this may + // actually invoke the continuation before returning. + ContinueWithCore(continuationFuture, scheduler, continuationOptions); + + return continuationFuture; + } + } + + // Proxy class for better debugging experience + internal class SystemThreadingTasks_FutureDebugView + { + private Task m_task; + + public SystemThreadingTasks_FutureDebugView(Task task) + { + m_task = task; + } + + public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default(TResult); } } + public object AsyncState { get { return m_task.AsyncState; } } + public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } } + public Exception Exception { get { return m_task.Exception; } } + public int Id { get { return m_task.Id; } } + public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } } + public TaskStatus Status { get { return m_task.Status; } } + + + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskScheduler.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskScheduler.cs new file mode 100644 index 000000000..e86f2fc27 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskScheduler.cs @@ -0,0 +1,788 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskScheduler.cs +// +// hyildiz +// +// This file contains the primary interface and management of tasks and queues. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using System.Security; +using System.Collections.Concurrent; +using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System.Threading.Tasks +{ + + /// + /// Represents an abstract scheduler for tasks. + /// + /// + /// + /// TaskScheduler acts as the extension point for all + /// pluggable scheduling logic. This includes mechanisms such as how to schedule a task for execution, and + /// how scheduled tasks should be exposed to debuggers. + /// + /// + /// All members of the abstract type are thread-safe + /// and may be used from multiple threads concurrently. + /// + /// + [DebuggerDisplay("Id={Id}")] + [DebuggerTypeProxy(typeof(SystemThreadingTasks_TaskSchedulerDebugView))] + + + public abstract class TaskScheduler + { + //////////////////////////////////////////////////////////// + // + // User Provided Methods and Properties + // + + /// + /// Queues a Task to the scheduler. + /// + /// + /// + /// A class derived from TaskScheduler + /// implements this method to accept tasks being scheduled on the scheduler. + /// A typical implementation would store the task in an internal data structure, which would + /// be serviced by threads that would execute those tasks at some time in the future. + /// + /// + /// This method is only meant to be called by the .NET Framework and + /// should not be called directly by the derived class. This is necessary + /// for maintaining the consistency of the system. + /// + /// + /// The Task to be queued. + /// The argument is null. + // [SecurityCritical] + protected internal abstract void QueueTask(Task task); + + /// + /// Determines whether the provided Task + /// can be executed synchronously in this call, and if it can, executes it. + /// + /// + /// + /// A class derived from TaskScheduler implements this function to + /// support inline execution of a task on a thread that initiates a wait on that task object. Inline + /// execution is optional, and the request may be rejected by returning false. However, better + /// scalability typically results the more tasks that can be inlined, and in fact a scheduler that + /// inlines too little may be prone to deadlocks. A proper implementation should ensure that a + /// request executing under the policies guaranteed by the scheduler can successfully inline. For + /// example, if a scheduler uses a dedicated thread to execute tasks, any inlining requests from that + /// thread should succeed. + /// + /// + /// If a scheduler decides to perform the inline execution, it should do so by calling to the base + /// TaskScheduler's + /// TryExecuteTask method with the provided task object, propagating + /// the return value. It may also be appropriate for the scheduler to remove an inlined task from its + /// internal data structures if it decides to honor the inlining request. Note, however, that under + /// some circumstances a scheduler may be asked to inline a task that was not previously provided to + /// it with the method. + /// + /// + /// The derived scheduler is responsible for making sure that the calling thread is suitable for + /// executing the given task as far as its own scheduling and execution policies are concerned. + /// + /// + /// The Task to be + /// executed. + /// A Boolean denoting whether or not task has previously been + /// queued. If this parameter is True, then the task may have been previously queued (scheduled); if + /// False, then the task is known not to have been queued, and this call is being made in order to + /// execute the task inline without queueing it. + /// A Boolean value indicating whether the task was executed inline. + /// The argument is + /// null. + /// The was already + /// executed. + // [SecurityCritical] + protected abstract bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued); + + /// + /// Generates an enumerable of Task instances + /// currently queued to the scheduler waiting to be executed. + /// + /// + /// + /// A class derived from implements this method in order to support + /// integration with debuggers. This method will only be invoked by the .NET Framework when the + /// debugger requests access to the data. The enumerable returned will be traversed by debugging + /// utilities to access the tasks currently queued to this scheduler, enabling the debugger to + /// provide a representation of this information in the user interface. + /// + /// + /// It is important to note that, when this method is called, all other threads in the process will + /// be frozen. Therefore, it's important to avoid synchronization with other threads that may lead to + /// blocking. If synchronization is necessary, the method should prefer to throw a + /// than to block, which could cause a debugger to experience delays. Additionally, this method and + /// the enumerable returned must not modify any globally visible state. + /// + /// + /// The returned enumerable should never be null. If there are currently no queued tasks, an empty + /// enumerable should be returned instead. + /// + /// + /// For developers implementing a custom debugger, this method shouldn't be called directly, but + /// rather this functionality should be accessed through the internal wrapper method + /// GetScheduledTasksForDebugger: + /// internal Task[] GetScheduledTasksForDebugger(). This method returns an array of tasks, + /// rather than an enumerable. In order to retrieve a list of active schedulers, a debugger may use + /// another internal method: internal static TaskScheduler[] GetTaskSchedulersForDebugger(). + /// This static method returns an array of all active TaskScheduler instances. + /// GetScheduledTasksForDebugger then may be used on each of these scheduler instances to retrieve + /// the list of scheduled tasks for each. + /// + /// + /// An enumerable that allows traversal of tasks currently queued to this scheduler. + /// + /// + /// This scheduler is unable to generate a list of queued tasks at this time. + /// + // [SecurityCritical] + protected abstract IEnumerable GetScheduledTasks(); + + /// + /// Indicates the maximum concurrency level this + /// is able to support. + /// + public virtual Int32 MaximumConcurrencyLevel + { + get + { + return Int32.MaxValue; + } + } + + + //////////////////////////////////////////////////////////// + // + // Internal overridable methods + // + + /// + /// Retrieves some thread static state that can be cached and passed to multiple + /// TryRunInline calls, avoiding superflous TLS fetches. + /// + /// A bag of TLS state (or null if none exists). + internal virtual object GetThreadStatics() + { + return null; + } + + /// + /// Attempts to execute the target task synchronously. + /// + /// The task to run. + /// True if the task may have been previously queued, + /// false if the task was absolutely not previously queued. + /// The state retrieved from GetThreadStatics + /// True if it ran, false otherwise. + // [SecuritySafeCritical] + internal bool TryRunInline(Task task, bool taskWasPreviouslyQueued, object threadStatics) + { + // Do not inline unstarted tasks (i.e., task.ExecutingTaskScheduler == null). + // Do not inline TaskCompletionSource-style (a.k.a. "promise") tasks. + // No need to attempt inlining if the task body was already run (i.e. either TASK_STATE_DELEGATE_INVOKED or TASK_STATE_CANCELED bits set) + TaskScheduler ets = task.ExecutingTaskScheduler; + + // Delegate cross-scheduler inlining requests to target scheduler + if(ets != this && ets !=null) return ets.TryRunInline(task, taskWasPreviouslyQueued); + + if( (ets == null) || + (task.m_action == null) || + task.IsDelegateInvoked || + task.IsCanceled) + { + return false; + } + + // Task class will still call into TaskScheduler.TryRunInline rather than TryExecuteTaskInline() so that + // 1) we can adjust the return code from TryExecuteTaskInline in case a buggy custom scheduler lies to us + // 2) we maintain a mechanism for the TLS lookup optimization that we used to have for the ConcRT scheduler (will potentially introduce the same for TP) + bool bInlined = TryExecuteTaskInline(task, taskWasPreviouslyQueued); + + // If the custom scheduler returned true, we should either have the TASK_STATE_DELEGATE_INVOKED or TASK_STATE_CANCELED bit set + // Otherwise the scheduler is buggy + if (bInlined && !(task.IsDelegateInvoked || task.IsCanceled)) + { + throw new InvalidOperationException(Strings.TaskScheduler_InconsistentStateAfterTryExecuteTaskInline); + } + + return bInlined; + } + + // [SecuritySafeCritical] + internal bool TryRunInline(Task task, bool taskWasPreviouslyQueued) + { + return TryRunInline(task, taskWasPreviouslyQueued, GetThreadStatics()); + } + + /// + /// Attempts to dequeue a Task that was previously queued to + /// this scheduler. + /// + /// The Task to be dequeued. + /// A Boolean denoting whether the argument was successfully dequeued. + /// The argument is null. + // [SecurityCritical] + protected internal virtual bool TryDequeue(Task task) + { + return false; + } + + /// + /// Notifies the scheduler that a work item has made progress. + /// + internal virtual void NotifyWorkItemProgress() + { + } + + /// + /// Indicates whether this is a custom scheduler, in which case the safe code paths will be taken upon task entry + /// using a CAS to transition from queued state to executing. + /// + internal virtual bool RequiresAtomicStartTransition + { + get { return true; } + } + + + + //////////////////////////////////////////////////////////// + // + // Member variables + // + + // An AppDomain-wide default manager. + private static TaskScheduler s_defaultTaskScheduler = new ThreadPoolTaskScheduler(); + + //static counter used to generate unique TaskScheduler IDs + internal static int s_taskSchedulerIdCounter; + + // this TaskScheduler's unique ID + private int m_taskSchedulerId; + + // We keep a weak reference to ourselves to be uniquely identified in the global + // static collection of active schedulers without being pinned down in memory, as well + // to convert it later to a real TS object when enumerating for the debugger + internal WeakReference m_weakReferenceToSelf; + + // The global container that keeps track of TaskScheduler instances. Lazily initialized + private static ConcurrentDictionary s_activeTaskSchedulers; + + + //////////////////////////////////////////////////////////// + // + // Constructors and public properties + // + + /// + /// Initializes the . + /// + protected TaskScheduler() + { + // Protected constructor. It's here to ensure all user implemented TaskSchedulers will be + // registered in the active schedulers list. + m_weakReferenceToSelf = new WeakReference(this); + RegisterTaskScheduler(this); + } + + /// + /// Frees all resources associated with this scheduler. + /// + ~TaskScheduler() + { + // Finalizer to remove us out of the active schedulers list + UnregisterTaskScheduler(this); + } + + /// + /// Gets the default TaskScheduler instance. + /// + public static TaskScheduler Default + { + get + { + return s_defaultTaskScheduler; + } + } + + /// + /// Gets the TaskScheduler + /// associated with the currently executing task. + /// + /// + /// When not called from within a task, will return the scheduler. + /// + public static TaskScheduler Current + { + get + { + Task currentTask = Task.InternalCurrent; + + if (currentTask != null) + { + return currentTask.ExecutingTaskScheduler; + } + else + { + return TaskScheduler.Default; + } + } + } + + /// + /// Creates a + /// associated with the current . + /// + /// + /// All Task instances queued to + /// the returned scheduler will be executed through a call to the + /// Post method + /// on that context. + /// + /// + /// A associated with + /// the current SynchronizationContext, as + /// determined by SynchronizationContext.Current. + /// + /// + /// The current SynchronizationContext may not be used as a TaskScheduler. + /// + public static TaskScheduler FromCurrentSynchronizationContext() + { + return new SynchronizationContextTaskScheduler(); + } + + /// + /// Gets the unique ID for this . + /// + public Int32 Id + { + get + { + if (m_taskSchedulerId == 0) + { + int newId = 0; + + // We need to repeat if Interlocked.Increment wraps around and returns 0. + // Otherwise next time this scheduler's Id is queried it will get a new value + do + { + newId = Interlocked.Increment(ref s_taskSchedulerIdCounter); + } while (newId == 0); + + Interlocked.CompareExchange(ref m_taskSchedulerId, newId, 0); + } + + return m_taskSchedulerId; + } + } + + /// + /// Attempts to execute the provided Task + /// on this scheduler. + /// + /// + /// + /// Scheduler implementations are provided with Task + /// instances to be executed through either the method or the + /// method. When the scheduler deems it appropriate to run the + /// provided task, should be used to do so. TryExecuteTask handles all + /// aspects of executing a task, including action invocation, exception handling, state management, + /// and lifecycle control. + /// + /// + /// must only be used for tasks provided to this scheduler by the .NET + /// Framework infrastructure. It should not be used to execute arbitrary tasks obtained through + /// custom mechanisms. + /// + /// + /// + /// A Task object to be executed. + /// + /// The is not associated with this scheduler. + /// + /// A Boolean that is true if was successfully executed, false if it + /// was not. A common reason for execution failure is that the task had previously been executed or + /// is in the process of being executed by another thread. + // [SecurityCritical] + protected bool TryExecuteTask(Task task) + { + if (task.ExecutingTaskScheduler != this) + { + throw new InvalidOperationException(Strings.TaskScheduler_ExecuteTask_WrongTaskScheduler); + } + + return task.ExecuteEntry(true); + } + + //////////////////////////////////////////////////////////// + // + // Events + // + + private static event EventHandler _unobservedTaskException; + private static object _unobservedTaskExceptionLockObject = new object(); + + /// + /// Occurs when a faulted 's unobserved exception is about to trigger exception escalation + /// policy, which, by default, would terminate the process. + /// + /// + /// This AppDomain-wide event provides a mechanism to prevent exception + /// escalation policy (which, by default, terminates the process) from triggering. + /// Each handler is passed a + /// instance, which may be used to examine the exception and to mark it as observed. + /// + public static event EventHandler UnobservedTaskException + { + // [System.Security.SecurityCritical] + add + { + if (value != null) + { +//#if !PFX_LEGACY_3_5 +// RuntimeHelpers.PrepareContractedDelegate(value); +//#endif + lock (_unobservedTaskExceptionLockObject) _unobservedTaskException += value; + } + } + + // [System.Security.SecurityCritical] + remove + { + lock (_unobservedTaskExceptionLockObject) _unobservedTaskException -= value; + } + } + + + + + + + //////////////////////////////////////////////////////////// + // + // Internal methods + // + + // This is called by the TaskExceptionHolder finalizer. + internal static void PublishUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs ueea) + { + // Lock this logic to prevent just-unregistered handlers from being called. + lock (_unobservedTaskExceptionLockObject) + { + // Since we are under lock, it is technically no longer necessary + // to make a copy. It is done here for convenience. + EventHandler handler = _unobservedTaskException; + if (handler != null) + { + handler(sender, ueea); + } + } + } + + /// + /// Provides an array of all queued Task instances + /// for the debugger. + /// + /// + /// The returned array is populated through a call to . + /// Note that this function is only meant to be invoked by a debugger remotely. + /// It should not be called by any other codepaths. + /// + /// An array of Task instances. + /// + /// This scheduler is unable to generate a list of queued tasks at this time. + /// + internal Task[] GetScheduledTasksForDebugger() + { + // this can throw InvalidOperationException indicating that they are unable to provide the info + // at the moment. We should let the debugger receive that exception so that it can indicate it in the UI + IEnumerable activeTasksSource = GetScheduledTasks(); + + if (activeTasksSource == null) + return null; + + // If it can be cast to an array, use it directly + Task[] activeTasksArray = activeTasksSource as Task[]; + if (activeTasksArray == null) + { + activeTasksArray = (new List(activeTasksSource)).ToArray(); + } + + // touch all Task.Id fields so that the debugger doesn't need to do a lot of cross-proc calls to generate them + foreach (Task t in activeTasksArray) + { + int tmp = t.Id; + } + + return activeTasksArray; + } + + /// + /// Provides an array of all active TaskScheduler + /// instances for the debugger. + /// + /// + /// This function is only meant to be invoked by a debugger remotely. + /// It should not be called by any other codepaths. + /// + /// An array of TaskScheduler instances. + internal static TaskScheduler[] GetTaskSchedulersForDebugger() + { + // To populate this array we walk the global collection of schedulers (s_activeTaskSchedulers). + + TaskScheduler[] activeSchedulers = new TaskScheduler[s_activeTaskSchedulers.Count]; + + IEnumerator> tsEnumerator = s_activeTaskSchedulers.GetEnumerator(); + + int index = 0; + while (tsEnumerator.MoveNext()) + { + // convert the weak reference to the real TS object + TaskScheduler ts = tsEnumerator.Current.Key.Target as TaskScheduler; + if (ts == null) + continue; + activeSchedulers[index++] = ts; + int tmp = ts.Id; + } + + return activeSchedulers; + } + + /// + /// Registers a new TaskScheduler instance in the global collection of schedulers. + /// + internal static void RegisterTaskScheduler(TaskScheduler ts) + { + LazyInitializer.EnsureInitialized>(ref s_activeTaskSchedulers); + + bool bResult = s_activeTaskSchedulers.TryAdd(ts.m_weakReferenceToSelf, null); + Contract.Assert(bResult); + } + + /// + /// Removes a TaskScheduler instance from the global collection of schedulers. + /// + internal static void UnregisterTaskScheduler(TaskScheduler ts) + { + Contract.Assert(s_activeTaskSchedulers != null); + + object tmpObj; + bool bResult = s_activeTaskSchedulers.TryRemove(ts.m_weakReferenceToSelf, out tmpObj); + + Contract.Assert(bResult); + } + + + /// + /// Nested class that provides debugger view for TaskScheduler + /// + internal sealed class SystemThreadingTasks_TaskSchedulerDebugView + { + private readonly TaskScheduler m_taskScheduler; + public SystemThreadingTasks_TaskSchedulerDebugView(TaskScheduler scheduler) + { + m_taskScheduler = scheduler; + } + + // returns the scheduler’s Id + public Int32 Id + { + get { return m_taskScheduler.Id; } + } + + // returns the scheduler’s GetScheduledTasks + public IEnumerable ScheduledTasks + { + // [SecurityCritical] + get { return m_taskScheduler.GetScheduledTasks(); } + } + } + } + + /// Default thread pool scheduler. + internal sealed class ThreadPoolTaskScheduler : TaskScheduler + { + private WaitCallback m_wcCallback; + private Action m_ptsCallback; + + internal ThreadPoolTaskScheduler() + { + m_wcCallback = state => TryExecuteTask((Task)state); + m_ptsCallback = state => TryExecuteTask((Task)state); + } + + protected internal override void QueueTask(Task task) + { + if ((task.CreationOptions & TaskCreationOptions.LongRunning) != 0) + { + ThreadLightup thread = ThreadLightup.Create(m_ptsCallback); + thread.IsBackground = true; + thread.Start(task); + } + else + { + ThreadPool.QueueUserWorkItem(m_wcCallback, task); + } + } + + protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) + { + return TryExecuteTask(task); + } + + protected override IEnumerable GetScheduledTasks() { return null; } + } + + /// + /// A TaskScheduler implementation that executes all tasks queued to it through a call to + /// on the + /// that its associated with. The default constructor for this class binds to the current + /// + internal sealed class SynchronizationContextTaskScheduler : TaskScheduler + { + private SynchronizationContext m_synchronizationContext; + + /// + /// Constructs a SynchronizationContextTaskScheduler associated with + /// + /// This constructor expects to be set. + internal SynchronizationContextTaskScheduler() + { + SynchronizationContext synContext = SynchronizationContext.Current; + + // make sure we have a synccontext to work with + if (synContext == null) + { + throw new InvalidOperationException(Strings.TaskScheduler_FromCurrentSynchronizationContext_NoCurrent); + } + + m_synchronizationContext = synContext; + + } + + /// + /// Implemetation of for this scheduler class. + /// + /// Simply posts the tasks to be executed on the associated . + /// + /// + // [SecurityCritical] + protected internal override void QueueTask(Task task) + { + m_synchronizationContext.Post(s_postCallback, (object)task); + } + + /// + /// Implementation of for this scheduler class. + /// + /// The task will be executed inline only if the call happens within + /// the associated . + /// + /// + /// + // [SecurityCritical] + protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) + { + if (SynchronizationContext.Current == m_synchronizationContext) + { + return TryExecuteTask(task); + } + else + return false; + } + + // not implemented + // [SecurityCritical] + protected override IEnumerable GetScheduledTasks() + { + return null; + } + + /// + /// Implementes the property for + /// this scheduler class. + /// + /// By default it returns 1, because a based + /// scheduler only supports execution on a single thread. + /// + public override Int32 MaximumConcurrencyLevel + { + get + { + return 1; + } + } + + // preallocated SendOrPostCallback delegate + private static SendOrPostCallback s_postCallback = new SendOrPostCallback(PostCallback); + + // this is where the actual task invocation occures + private static void PostCallback(object obj) + { + Task task = (Task) obj; + + // calling ExecuteEntry with double execute check enabled because a user implemented SynchronizationContext could be buggy + task.ExecuteEntry(true); + } + } + + /// + /// Provides data for the event that is raised when a faulted 's + /// exception goes unobserved. + /// + /// + /// The Exception property is used to examine the exception without marking it + /// as observed, whereas the method is used to mark the exception + /// as observed. Marking the exception as observed prevents it from triggering exception escalation policy + /// which, by default, terminates the process. + /// + public class UnobservedTaskExceptionEventArgs : EventArgs + { + private AggregateException m_exception; + internal bool m_observed = false; + + /// + /// Initializes a new instance of the class + /// with the unobserved exception. + /// + /// The Exception that has gone unobserved. + public UnobservedTaskExceptionEventArgs(AggregateException exception) { m_exception = exception; } + + /// + /// Marks the as "observed," thus preventing it + /// from triggering exception escalation policy which, by default, terminates the process. + /// + public void SetObserved() { m_observed = true; } + + /// + /// Gets whether this exception has been marked as "observed." + /// + public bool Observed { get { return m_observed; } } + + /// + /// The Exception that went unobserved. + /// + public AggregateException Exception { get { return m_exception; } } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskSchedulerException.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskSchedulerException.cs new file mode 100644 index 000000000..2e85c6646 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/Tasks/TaskSchedulerException.cs @@ -0,0 +1,85 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskSchedulerException.cs +// +// hyildiz +// +// An exception for task schedulers. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +namespace System.Threading.Tasks +{ + + /// + /// Represents an exception used to communicate an invalid operation by a + /// . + /// + + public class TaskSchedulerException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public TaskSchedulerException() : base(Strings.TaskSchedulerException_ctor_DefaultMessage) // + { + } + + /// + /// Initializes a new instance of the + /// class with a specified error message. + /// + /// The error message that explains the reason for the exception. + public TaskSchedulerException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the + /// class using the default error message and a reference to the inner exception that is the cause of + /// this exception. + /// + /// The exception that is the cause of the current exception. + public TaskSchedulerException(Exception innerException) + : base(Strings.TaskSchedulerException_ctor_DefaultMessage, innerException) + { + } + + /// + /// Initializes a new instance of the + /// class with a specified error message and a reference to the inner exception that is the cause of + /// this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. + public TaskSchedulerException(string message, Exception innerException) : base(message, innerException) + { + } + +#if SERIALIZATION + /// + /// Initializes a new instance of the + /// class with serialized data. + /// + /// The that holds + /// the serialized object data about the exception being thrown. + /// The that + /// contains contextual information about the source or destination. + protected TaskSchedulerException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#endif + + } + +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadStatic.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadStatic.cs new file mode 100644 index 000000000..4be88a8f9 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadStatic.cs @@ -0,0 +1,41 @@ +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; + +namespace System.Threading +{ + internal sealed class ThreadStatic + { + private readonly ConcurrentDictionary> m_tls = new ConcurrentDictionary>(); + + public T Value + { + get + { + StrongBox sb; + if (m_tls.TryGetValue(Thread.CurrentThread, out sb)) return sb.Value; + return default(T); + } + set + { + var currentThread = Thread.CurrentThread; + StrongBox sb; + if (m_tls.TryGetValue(currentThread, out sb)) + { + sb.Value = value; + } + else + { + // Clean out any stale threads + foreach (var pair in m_tls) + { + ThreadLightup thread = new ThreadLightup(pair.Key); + if (!thread.IsAlive) m_tls.TryRemove(pair.Key, out sb); + } + + // Now add this one + m_tls.TryAdd(currentThread, new StrongBox(value)); + } + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadWrapper.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadWrapper.cs new file mode 100644 index 000000000..ad1aaa18b --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadWrapper.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Threading +{ + internal static class ThreadWrapper + { + + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadingServices.cs b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadingServices.cs new file mode 100644 index 000000000..9907f984c --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v1.5/System/Threading/ThreadingServices.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.Threading +{ + internal static class ThreadingServices + { + public static Type ThreadAbortExceptionType = Type.GetType("System.Threading.ThreadAbortException"); + public static Type AppDomainUnloadedExceptionType = Type.GetType("System.AppDomainUnloadedException"); + + public static bool IsThreadAbort(Exception ex) + { + return ex.GetType() == ThreadAbortExceptionType; + } + } +} diff --git a/Microsoft.Bcl/System.Threading.Tasks.v2.5/Properties/AssemblyInfo.cs b/Microsoft.Bcl/System.Threading.Tasks.v2.5/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..946dff7b3 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v2.5/Properties/AssemblyInfo.cs @@ -0,0 +1,42 @@ +//-------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//-------------------------------------------------------------------------- +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading; +using System.Threading.Tasks; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("System.Threading.Tasks")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("System.Threading.Tasks")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +[assembly: TypeForwardedTo(typeof(AggregateException))] +[assembly: TypeForwardedTo(typeof(OperationCanceledException))] +[assembly: TypeForwardedTo(typeof(CancellationToken))] +[assembly: TypeForwardedTo(typeof(CancellationTokenRegistration))] +[assembly: TypeForwardedTo(typeof(CancellationTokenSource))] +[assembly: TypeForwardedTo(typeof(Task))] +[assembly: TypeForwardedTo(typeof(Task<>))] +[assembly: TypeForwardedTo(typeof(TaskCanceledException))] +[assembly: TypeForwardedTo(typeof(TaskCompletionSource<>))] +[assembly: TypeForwardedTo(typeof(TaskContinuationOptions))] +[assembly: TypeForwardedTo(typeof(TaskCreationOptions))] +[assembly: TypeForwardedTo(typeof(TaskExtensions))] +[assembly: TypeForwardedTo(typeof(TaskFactory))] +[assembly: TypeForwardedTo(typeof(TaskFactory<>))] +[assembly: TypeForwardedTo(typeof(TaskScheduler))] +[assembly: TypeForwardedTo(typeof(TaskSchedulerException))] +[assembly: TypeForwardedTo(typeof(TaskStatus))] +[assembly: TypeForwardedTo(typeof(UnobservedTaskExceptionEventArgs))] diff --git a/Microsoft.Bcl/System.Threading.Tasks.v2.5/System.Threading.Tasks.v2.5.csproj b/Microsoft.Bcl/System.Threading.Tasks.v2.5/System.Threading.Tasks.v2.5.csproj new file mode 100644 index 000000000..c0aff42c9 --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v2.5/System.Threading.Tasks.v2.5.csproj @@ -0,0 +1,109 @@ + + + + + 10.0 + Debug + AnyCPU + {56E3CCC8-C2C4-422F-942D-A8058AA43756} + Library + Properties + System + System.Threading.Tasks + v4.0 + Profile37 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + SAK + SAK + SAK + SAK + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG;VARIANCE + prompt + 4 + bin\Debug\System.Threading.Tasks.xml + SecurityRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE;VARIANCE + prompt + 4 + bin\Release\System.Threading.Tasks.xml + + + true + true + ..\CodePlexKey.snk + + + + + {64a2361b-9b62-4d21-8012-e3317696327e} + System.Runtime.v2.5 + + + + + System\Lightup\ExecutionContextLightup.cs + + + System\Lightup\Lightup.cs + + + System\Lightup\LightupType.cs + + + System\Runtime\CompilerServices\AsyncMethodBuilderCore.cs + + + System\Runtime\CompilerServices\AsyncMethodTaskCacheOfTResult.cs + + + System\Runtime\CompilerServices\AsyncServices.cs + + + System\Runtime\CompilerServices\AsyncTaskMethodBuilder.cs + + + System\Runtime\CompilerServices\AsyncTaskMethodBuilderOfTResult.cs + + + System\Runtime\CompilerServices\AsyncVoidMethodBuilder.cs + + + System\Runtime\CompilerServices\IAsyncMethodBuilder.cs + + + System\Runtime\CompilerServices\IAsyncStateMachine.cs + + + System\Runtime\CompilerServices\ICriticalNotifyCompletion.cs + + + System\Runtime\CompilerServices\INotifyCompletion.cs + + + System\Runtime\CompilerServices\VoidTaskResult.cs + + + + + + + \ No newline at end of file diff --git a/Microsoft.Bcl/System.Threading.Tasks.v2.5/System.Threading.Tasks.v2.5.csproj.vspscc b/Microsoft.Bcl/System.Threading.Tasks.v2.5/System.Threading.Tasks.v2.5.csproj.vspscc new file mode 100644 index 000000000..b6d32892f --- /dev/null +++ b/Microsoft.Bcl/System.Threading.Tasks.v2.5/System.Threading.Tasks.v2.5.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +}