protected AsyncOperation?DequeueFirstAndGetNext(AsyncOperation first) { AsyncOperation?queue = Interlocked.CompareExchange(ref _queue, null, first); Debug.Assert(queue != null); if (object.ReferenceEquals(queue, first) || IsDisposed(queue)) { return(null); } Debug.Assert(IsGate(queue)); lock (queue) { if (queue.Next == first) // we're the last -> single element { Debug.Assert(first.Next == first); // verify we're a single element list queue.Next = null; return(null); } else { AsyncOperation?last = queue.Next; Debug.Assert(last != null); // there is an element Debug.Assert(last.Next == first); // we're first last.Next = first.Next; // skip operation first.Next = first; // point to self return(last.Next); } } }
void IAsyncExecutionResultHandler.HandleAsyncResult(AsyncOperationResult aResult) { AsyncOperation?op = _executingOperation !; AsyncExecutionResult result = op.HandleAsyncResult(aResult); if (result != AsyncExecutionResult.Finished && op.IsCancellationRequested) { result = AsyncExecutionResult.Cancelled; } if (result == AsyncExecutionResult.Executing || result == AsyncExecutionResult.WaitForPoll) { result = op.TryExecuteIOUringAsync(_thread.ExecutionQueue, this, _keyForOperation); Debug.Assert(result == AsyncExecutionResult.Executing); return; } _executingOperation = null; AsyncOperation?next = CompleteOperationAndGetNext(op, result); if (next != null) { ExecuteQueued(next); } }
void IAsyncExecutionResultHandler.HandleAsyncResult(AsyncOperationResult aResult) { AsyncOperation?op = _executingOperation !; AsyncExecutionResult result = op.HandleAsyncResult(aResult); if (result != AsyncExecutionResult.Finished && op.IsCancellationRequested) { result = AsyncExecutionResult.Cancelled; } if (result == AsyncExecutionResult.Executing) { result = op.TryExecuteEpollAsync(triggeredByPoll: false, _thread.ExecutionQueue, this); if (result == AsyncExecutionResult.Executing) { return; } } _executingOperation = null; AsyncOperation?next = CompleteOperationAndGetNext(op, result); if (next != null) { ExecuteQueued(triggeredByPoll: false, next); } }
private AsyncOperation?CompleteOperationAndGetNext(AsyncOperation op, AsyncExecutionResult result) { if (result == AsyncExecutionResult.Finished) { op.Status = OperationStatus.Completed; } else // AsyncExecutionResult.WaitForPoll or Cancelled { if (result == AsyncExecutionResult.WaitForPoll) { OperationStatus previous = op.CompareExchangeStatus(OperationStatus.Queued, OperationStatus.Executing); if (previous == OperationStatus.Executing) { // We've changed from executing to queued. return(null); } Debug.Assert((previous & OperationStatus.CancellationRequested) != 0); } op.Status = (op.Status & ~(OperationStatus.CancellationRequested | OperationStatus.Executing)) | OperationStatus.Cancelled; } AsyncOperation?next = DequeueFirstAndGetNext(op); op.Complete(); return(next); }
public void ExecuteQueued(AsyncOperationResult asyncResult) { AsyncOperation?completedTail = null; lock (Gate) { if (_tail is { } && _tail != AsyncOperation.DisposedSentinel)
static void CompleteOperationsCancelled(ref AsyncOperation?tail) { while (TryQueueTakeFirst(ref tail, out AsyncOperation? op)) { op.CompletionFlags = OperationCompletionFlags.CompletedCanceled; op.Complete(); } }
private AsyncOperation?_operation; // for caching/cancelling. internal AsyncOperation StartReceiveOperation(Socket socket) { StartOperationCommon(socket, SocketAsyncOperation.Receive); var op = (_operation as SaeaReceiveOperation) ?? new SaeaReceiveOperation(this); op.Configure(socket, MemoryBuffer, BufferList); _operation = op; return(op); }
public void ExecuteQueued(bool triggeredByPoll, AsyncOperationResult asyncResult) { AsyncOperation?completedTail = null; lock (Gate) { _eventCounter++; if (_tail is { } && _tail != AsyncOperation.DisposedSentinel)
internal AsyncOperation StartConnectOperation(Socket socket) { StartOperationCommon(socket, SocketAsyncOperation.Connect); var op = (_operation as SaeaConnectOperation) ?? new SaeaConnectOperation(this); op.Configure(socket, RemoteEndPoint !); _operation = op; return(op); }
private void CancelExecuting() { AsyncOperation?operation = Interlocked.Exchange(ref _cancellingOperation, null); if (operation?.IsCancellationRequested == true) { _thread.ExecutionQueue.AddCancel(_context.Handle, _keyForOperation); } }
internal AsyncOperation StartAcceptOperation(Socket socket) { StartOperationCommon(socket, SocketAsyncOperation.Accept); var op = (_operation as SaeaAcceptOperation) ?? new SaeaAcceptOperation(this); op.Configure(socket); _operation = op; return(op); }
internal AsyncOperation StartSendOperation(Socket socket) { StartOperationCommon(socket, SocketAsyncOperation.Send); var op = (_operation as SaeaSendOperation) ?? new SaeaSendOperation(this); Memory <byte> buffer = MemoryBuffer.Slice(_offset, _count); op.Configure(socket, buffer, BufferList); _operation = op; return(op); }
protected void RemoveQueued(AsyncOperation operation) { AsyncOperation?queue = Interlocked.CompareExchange(ref _queue, null, operation); if (object.ReferenceEquals(queue, operation)) { return; } if (queue is object && IsGate(queue)) { lock (queue) { if (queue.Next == operation) // We're the last { if (operation.Next == operation) // We're the only { queue.Next = null; // empty } else { // Find newLast AsyncOperation newLast = operation.Next !; { AsyncOperation newLastNext = newLast.Next !; while (newLastNext != operation) { newLast = newLastNext; } } newLast.Next = operation.Next; // last point to first queue.Next = newLast; // gate points to last operation.Next = operation; // point to self } } AsyncOperation?last = queue.Next; if (last != null) { AsyncOperation it = last; do { AsyncOperation next = it.Next !; if (next == operation) { it.Next = operation.Next; // skip operation operation.Next = operation; // point to self return; } it = next; } while (it != last); } } } }
protected static bool TryQueueTakeFirst(ref AsyncOperation?tail, [NotNullWhen(true)] out AsyncOperation?first) { first = tail?.Next; if (first != null) { QueueRemove(ref tail, first); return(true); } else { return(false); } }
protected static void QueueAdd(ref AsyncOperation?tail, AsyncOperation operation) { Debug.Assert(operation.Next == null); operation.Next = operation; if (tail != null) { operation.Next = tail.Next; tail.Next = operation; } tail = operation; }
protected bool EnqueueAndGetIsFirst(AsyncOperation operation) { Debug.Assert(operation.Next == operation); // non-queued point to self. operation.Status = OperationStatus.Queued; AsyncOperation?queue = Interlocked.CompareExchange(ref _queue, operation, null); if (queue is null) { return(true); } return(EnqueueSlowAndGetIsFirst(operation, queue)); }
public bool Dispose() { AsyncOperation?queue = Interlocked.Exchange(ref _queue, DisposedSentinel); // already disposed if (queue == DisposedSentinel) { return(false); } if (queue != null) { AsyncOperation?gate = queue as AsyncOperationGate; if (gate != null) { // Synchronize with Enqueue. lock (gate) { } AsyncOperation?last = gate.Next; if (last != null) { AsyncOperation op = gate.Next !; do { AsyncOperation next = op.Next !; op.Next = op; // point to self. TryCancelAndComplete(op, OperationStatus.None, wait: true); if (op == last) { break; } op = next; } while (true); } } else { // queue is single operation TryCancelAndComplete(queue, OperationStatus.None, wait: true); } } return(true); }
protected static bool QueueRemove(ref AsyncOperation?tail, AsyncOperation operation) { AsyncOperation?tail_ = tail; if (tail_ == null) { return(false); } if (tail_ == operation) { if (tail_.Next == operation) { tail = null; } else { AsyncOperation newTail = tail_.Next !; AsyncOperation newTailNext = newTail.Next !; while (newTailNext != tail_) { newTail = newTailNext; } tail = newTail; } operation.Next = null; return(true); } else { AsyncOperation it = tail_; do { AsyncOperation next = it.Next !; if (next == operation) { it.Next = next.Next; operation.Next = null; return(true); } it = next; } while (it != tail_); } return(false); }
public void ExecuteQueued(bool triggeredByPoll, AsyncOperation?op = null) { if (triggeredByPoll) { Interlocked.Increment(ref _eventCounter); } op ??= QueueGetFirst(); do { var spin = new SpinWait(); while (true) { if (op is null) { return; } OperationStatus previous = op.CompareExchangeStatus(OperationStatus.Executing, OperationStatus.Queued); if (previous == OperationStatus.Queued) { // We've changed from queued to executing. break; } else if ((previous & OperationStatus.Executing) != 0) // Also set when CancellationRequested. { // Already executing. return; } // Operation was cancelled, but not yet removed from queue. Debug.Assert((previous & OperationStatus.Cancelled) != 0); spin.SpinOnce(); op = QueueGetFirst(); } AsyncExecutionResult result = op.TryExecuteEpollAsync(triggeredByPoll, _thread.ExecutionQueue, this); if (result == AsyncExecutionResult.Executing) { _executingOperation = op; return; } op = CompleteOperationAndGetNext(op, result); } while (op != null); }
// Requests cancellation of a queued operation. // If the operation is not on the queue (because it already completed), NotFound is returned. // If the operation is not executing, it is removed from the queue and Cancelled is returned. // If the operation is executing, it stays on the queue, the operation gets marked as cancellation requested, // and Requested is returned. protected CancellationRequestResult RequestCancellationAsync(AsyncOperation operation, OperationCompletionFlags flags) { CancellationRequestResult result = CancellationRequestResult.NotFound; if (_tail == operation) // We're the last operation { result = operation.RequestCancellationAsync(flags); if (result == CancellationRequestResult.Cancelled) { if (operation.Next == operation) // We're the only operation. { _tail = null; } else { // Update tail do { _tail = _tail.Next; } while (_tail !.Next != operation); // Update head _tail.Next = operation.Next; } operation.Next = null; } } else if (_tail != null) // The list is multiple operations and we're not the last { ref AsyncOperation nextOperation = ref _tail.Next !; do { if (nextOperation == operation) { result = operation.RequestCancellationAsync(flags); if (result == CancellationRequestResult.Cancelled) { nextOperation = operation.Next !; operation.Next = null; } break; } nextOperation = ref nextOperation.Next !; } while (nextOperation != _tail); }
public void RunWorkerAsync(object?argument) { if (_isRunning) { throw new InvalidOperationException(SR.BackgroundWorker_WorkerAlreadyRunning); } _isRunning = true; _cancellationPending = false; _asyncOperation = AsyncOperationManager.CreateOperation(null); Task.Factory.StartNew( WorkerThreadStart, argument, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default ); }
private AsyncOperation?CompleteOperationAndGetNext(AsyncOperation op, AsyncExecutionResult result) { if (result == AsyncExecutionResult.Finished) { op.Status = OperationStatus.Completed; } else // Cancelled { op.Status = (op.Status & ~(OperationStatus.CancellationRequested | OperationStatus.Executing)) | OperationStatus.Cancelled; } Volatile.Write(ref _cancellingOperation, null); AsyncOperation?next = DequeueFirstAndGetNext(op); op.Complete(); return(next); }
protected AsyncOperation?QueueGetFirst() { AsyncOperation?queue = Volatile.Read(ref _queue); if (queue is null || IsDisposed(queue)) { return(null); } if (IsGate(queue)) { lock (queue) { return(queue.Next?.Next); } } else { return(queue); } }
internal void Complete(OperationStatus status) { bool cancelled = (status & OperationStatus.Cancelled) != 0; bool completedAsync = (status & OperationStatus.Sync) == 0; if (cancelled) { SocketError = SocketError.OperationAborted; // We don't re-use operations that were cancelled async, // because cancellation is detected via StatusFlags. if (completedAsync) { _operation = null; } } // Reset state. ExecutionContext?context = _context; _context = null; CurrentSocket = null; CurrentOperation = System.Net.Sockets.SocketAsyncOperation.None; // Call OnCompleted only when completed async. if (completedAsync) { if (context == null) { OnCompleted(this); } else { ExecutionContext.Run(context, s_executionCallback, this); } } }
protected static AsyncOperation?QueueGetFirst(AsyncOperation?tail) => tail?.Next;
internal AsyncOperation(AsyncOperation?preceeding, IAsyncOperator op) { Operator = op; State = AsyncOperationState.Initial; _preceedingOperation = preceeding; }
protected bool EnqueueSlowAndGetIsFirst(AsyncOperation operation, AsyncOperation?queue) { Debug.Assert(queue != null); SpinWait spin = new SpinWait(); while (true) { if (IsDisposed(queue)) { operation.Status = OperationStatus.None; ThrowHelper.ThrowObjectDisposedException <AsyncContext>(); } else { // Install a gate. if (!IsGate(queue)) { AsyncOperation singleOperation = queue; Debug.Assert(singleOperation.Next == singleOperation); AsyncOperation gate = new AsyncOperationGate(); gate.Next = singleOperation; queue = Interlocked.CompareExchange(ref _queue, gate, singleOperation); if (queue != singleOperation) { if (queue is null) { queue = Interlocked.CompareExchange(ref _queue, operation, null); if (queue is null) { return(true); } } spin.SpinOnce(); continue; } queue = gate; } lock (queue) { if (object.ReferenceEquals(_queue, DisposedSentinel)) { continue; } AsyncOperation?last = queue.Next; if (last == null) // empty queue { queue.Next = operation; return(true); } else { queue.Next = operation; // gate points to new last operation.Next = last.Next; // new last points to first last.Next = operation; // previous last points to new last return(false); } } } } }
public void SendAsync(MailMessage message, object?userToken) { ObjectDisposedException.ThrowIf(_disposed, this); try { if (InCall) { throw new InvalidOperationException(SR.net_inasync); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (DeliveryMethod == SmtpDeliveryMethod.Network) { CheckHostAndPort(); } _recipients = new MailAddressCollection(); if (message.From == null) { throw new InvalidOperationException(SR.SmtpFromRequired); } if (message.To != null) { foreach (MailAddress address in message.To) { _recipients.Add(address); } } if (message.Bcc != null) { foreach (MailAddress address in message.Bcc) { _recipients.Add(address); } } if (message.CC != null) { foreach (MailAddress address in message.CC) { _recipients.Add(address); } } if (_recipients.Count == 0) { throw new InvalidOperationException(SR.SmtpRecipientRequired); } InCall = true; _cancelled = false; _message = message; string?pickupDirectory = PickupDirectoryLocation; CredentialCache?cache; // Skip token capturing if no credentials are used or they don't include a default one. // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be. _transport.IdentityRequired = Credentials != null && (ReferenceEquals(Credentials, CredentialCache.DefaultNetworkCredentials) || (cache = Credentials as CredentialCache) == null || IsSystemNetworkCredentialInCache(cache)); _asyncOp = AsyncOperationManager.CreateOperation(userToken); switch (DeliveryMethod) { case SmtpDeliveryMethod.PickupDirectoryFromIis: throw new NotSupportedException(SR.SmtpGetIisPickupDirectoryNotSupported); case SmtpDeliveryMethod.SpecifiedPickupDirectory: { if (EnableSsl) { throw new SmtpException(SR.SmtpPickupDirectoryDoesnotSupportSsl); } _writer = GetFileMailWriter(pickupDirectory); bool allowUnicode = IsUnicodeSupported(); ValidateUnicodeRequirement(message, _recipients, allowUnicode); message.Send(_writer, true, allowUnicode); if (_writer != null) { _writer.Close(); } AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, _asyncOp.UserSuppliedState); InCall = false; _asyncOp.PostOperationCompleted(_onSendCompletedDelegate, eventArgs); break; } case SmtpDeliveryMethod.Network: default: _operationCompletedResult = new ContextAwareResult(_transport.IdentityRequired, true, null, this, s_contextSafeCompleteCallback); lock (_operationCompletedResult.StartPostingAsyncOp()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"Calling BeginConnect. Transport: {_transport}"); } _transport.BeginGetConnection(_operationCompletedResult, ConnectCallback, _operationCompletedResult, Host !, Port); _operationCompletedResult.FinishPostingAsyncOp(); } break; } } catch (Exception e) { InCall = false; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(this, e); } if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) { throw; } Abort(); if (e is SecurityException || e is AuthenticationException || e is SmtpException) { throw; } throw new SmtpException(SR.SmtpSendMailFailure, e); } }