public static string ToDebugInfo(this CommandToSend source) { if (source == null) { return(string.Empty); } return("[Channel_" + source.Channel + "] Class " + source.ClassId + " Method " + source.MethodId + " Opt: " + source.OptionalArg + ""); }
// Run on its own thread, and invokes user code from it (task continuations) private void WriteFramesLoop() { if (LogAdapter.IsDebugEnabled) { LogAdapter.LogDebug(LogSource, "WriteFramesLoop starting"); } CommandToSend cmdToSend = null; _writeThreadRunning = true; try { var token = _threadCancelToken; while (!token.IsCancellationRequested) { _commandOutboxEvent.WaitOne(1000); // maybe it's better to _cancellationToken.Register(action) ? if (token.IsCancellationRequested) { break; // perf hit? } while (_commandOutbox.TryDequeue(out cmdToSend)) { FlushCommand(cmdToSend); } } if (LogAdapter.IsErrorEnabled) { LogAdapter.LogError(LogSource, "WriteFramesLoop exiting"); } } catch (ThreadAbortException) { // no-op } catch (Exception ex) { if (LogAdapter.IsErrorEnabled) { LogAdapter.LogError(LogSource, "WriteFramesLoop error. Last command " + cmdToSend.ToDebugInfo(), ex); } this.InitiateAbruptClose(ex).IntentionallyNotAwaited(); } finally { _writeThreadRunning = false; TryTriggerClean(); } }
// [MethodImpl(MethodImplOptions.AggressiveInlining)] private void FlushCommand(CommandToSend cmdToSend) { if (_threadCancelToken.IsCancellationRequested) { if (cmdToSend.Tcs != null) { cmdToSend.Tcs.TrySetCanceled(); } return; } var token = _threadCancelToken; if (!cmdToSend.Immediately) { _waitingServerReply.Wait(token); // Contention sadly required by the server/amqp } // The command will signal that we can send more commands... cmdToSend.Prepare(cmdToSend.ExpectsReply ? _waitingServerReply : null); if (cmdToSend.ExpectsReply) // enqueues as awaiting a reply from the server { _waitingServerReply.Reset(); // cannot send anything else var queue = cmdToSend.Channel == 0 ? _awaitingReplyQueue : _conn.ResolveChannel(cmdToSend.Channel)._awaitingReplyQueue; queue.Enqueue(cmdToSend); } // writes to socket var frameWriter = cmdToSend.OptionalArg as IFrameContentWriter; if (frameWriter != null) { frameWriter.Write(_amqpWriter, cmdToSend.Channel, cmdToSend.ClassId, cmdToSend.MethodId, cmdToSend.OptionalArg); } else { cmdToSend.commandGenerator(_amqpWriter, cmdToSend.Channel, cmdToSend.ClassId, cmdToSend.MethodId, cmdToSend.OptionalArg); } // if writing to socket is enough, set as complete if (!cmdToSend.ExpectsReply) { cmdToSend.RunReplyAction(0, 0, null); } }
internal void SendCommand(ushort channel, ushort classId, ushort methodId, Action <AmqpPrimitivesWriter, ushort, ushort, ushort, object> commandWriter, Action <ushort, int, AmqpError> reply, bool expectsReply, TaskCompletionSource <bool> tcs = null, object optArg = null, Action prepare = null, bool immediately = false) { if (_lastError != null) { // ConnClose and Channel close el al, are allowed to move fwd. var cmdId = (classId << 16) | methodId; if (cmdId != AmqpClassMethodConnectionLevelConstants.ConnectionClose && cmdId != AmqpClassMethodConnectionLevelConstants.ConnectionCloseOk && cmdId != AmqpClassMethodChannelLevelConstants.ChannelClose && cmdId != AmqpClassMethodChannelLevelConstants.ChannelCloseOk) { SetErrorResultIfErrorPending(expectsReply, reply, tcs /*, tcsL*/); return; } } // var cmd = _cmdToSendObjPool.GetObject(); var cmd = new CommandToSend(null); cmd.BeginInit(); cmd.Channel = channel; cmd.ClassId = classId; cmd.MethodId = methodId; cmd.ReplyAction = reply; cmd.commandGenerator = commandWriter; cmd.ExpectsReply = expectsReply; cmd.Tcs = tcs; cmd.OptionalArg = optArg; cmd.PrepareAction = prepare; cmd.Immediately = immediately; _commandOutbox.Enqueue(cmd); _commandOutboxEvent.Set(); }
// Run on its own thread, and invokes user code from it (task continuations) private void WriteFramesLoop() { if (LogAdapter.ExtendedLogEnabled) { LogAdapter.LogDebug("ConnectionIO", "WriteFramesLoop starting"); } CommandToSend cmdToSend = null; try { var token = _threadCancelToken; while (!token.IsCancellationRequested) { _commandOutboxEvent.WaitOne(1000); // maybe it's better to _cancellationToken.Register(action) ? while (_commandOutbox.TryDequeue(out cmdToSend)) { _waitingServerReply.Wait(token); // Contention sadly required by the server/amqp // The command will signal that we can send more commands... cmdToSend.Prepare(cmdToSend.ExpectsReply ? _waitingServerReply : null); if (cmdToSend.ExpectsReply) // enqueues as awaiting a reply from the server { _waitingServerReply.Reset(); // cannot send anything else var queue = cmdToSend.Channel == 0 ? _awaitingReplyQueue : _conn.ResolveChannel(cmdToSend.Channel)._awaitingReplyQueue; queue.Enqueue(cmdToSend); } // writes to socket var frameWriter = cmdToSend.OptionalArg as IFrameContentWriter; if (frameWriter != null) { frameWriter.Write(_amqpWriter, cmdToSend.Channel, cmdToSend.ClassId, cmdToSend.MethodId, cmdToSend.OptionalArg); } else { cmdToSend.commandGenerator(_amqpWriter, cmdToSend.Channel, cmdToSend.ClassId, cmdToSend.MethodId, cmdToSend.OptionalArg); } // if writing to socket is enough, set as complete if (!cmdToSend.ExpectsReply) { cmdToSend.RunReplyAction(0, 0, null).IntentionallyNotAwaited(); } } } LogAdapter.LogError("ConnectionIO", "WriteFramesLoop exiting"); } catch (ThreadAbortException) { // no-op } catch (Exception ex) { LogAdapter.LogError("ConnectionIO", "WriteFramesLoop error. Last command " + cmdToSend.ToDebugInfo(), ex); this.InitiateAbruptClose(ex); } }