4242using RabbitMQ . Client . Events ;
4343using RabbitMQ . Client . Exceptions ;
4444using RabbitMQ . Client . Framing . Impl ;
45- using RabbitMQ . Util ;
4645
4746namespace RabbitMQ . Client . Impl
4847{
@@ -57,7 +56,6 @@ internal abstract class ChannelBase : IChannel, IRecoverable
5756 private readonly RpcContinuationQueue _continuationQueue = new RpcContinuationQueue ( ) ;
5857 private readonly ManualResetEventSlim _flowControlBlock = new ManualResetEventSlim ( true ) ;
5958
60- private readonly object _rpcLock = new object ( ) ;
6159 private readonly object _confirmLock = new object ( ) ;
6260 private readonly LinkedList < ulong > _pendingDeliveryTags = new LinkedList < ulong > ( ) ;
6361
@@ -328,7 +326,8 @@ private void HandleCommand(in IncomingCommand cmd)
328326 {
329327 if ( ! DispatchAsynchronous ( in cmd ) ) // Was asynchronous. Already processed. No need to process further.
330328 {
331- _continuationQueue . Next ( ) . HandleCommand ( in cmd ) ;
329+ IRpcContinuation c = _continuationQueue . Next ( ) ;
330+ c . HandleCommand ( in cmd ) ;
332331 }
333332 }
334333
@@ -337,12 +336,17 @@ protected void ChannelRpc<TMethod>(in TMethod method, ProtocolCommandId returnCo
337336 {
338337 var k = new SimpleBlockingRpcContinuation ( ) ;
339338 IncomingCommand reply ;
340- lock ( _rpcLock )
339+ _rpcSemaphore . Wait ( ) ;
340+ try
341341 {
342342 Enqueue ( k ) ;
343343 Session . Transmit ( in method ) ;
344344 k . GetReply ( ContinuationTimeout , out reply ) ;
345345 }
346+ finally
347+ {
348+ _rpcSemaphore . Release ( ) ;
349+ }
346350
347351 reply . ReturnMethodBuffer ( ) ;
348352
@@ -358,12 +362,17 @@ protected TReturn ChannelRpc<TMethod, TReturn>(in TMethod method, ProtocolComman
358362 var k = new SimpleBlockingRpcContinuation ( ) ;
359363 IncomingCommand reply ;
360364
361- lock ( _rpcLock )
365+ _rpcSemaphore . Wait ( ) ;
366+ try
362367 {
363368 Enqueue ( k ) ;
364369 Session . Transmit ( in method ) ;
365370 k . GetReply ( ContinuationTimeout , out reply ) ;
366371 }
372+ finally
373+ {
374+ _rpcSemaphore . Release ( ) ;
375+ }
367376
368377 if ( reply . CommandId != returnCommandId )
369378 {
@@ -783,13 +792,21 @@ protected void HandleConnectionUnblocked()
783792 Session . Connection . HandleConnectionUnblocked ( ) ;
784793 }
785794
786- protected void HandleQueueDeclareOk ( in IncomingCommand cmd )
795+ protected bool HandleQueueDeclareOk ( in IncomingCommand cmd )
787796 {
788- var method = new Client . Framing . Impl . QueueDeclareOk ( cmd . MethodBytes . Span ) ;
789- cmd . ReturnMethodBuffer ( ) ;
790- var k = ( QueueDeclareRpcContinuation ) _continuationQueue . Next ( ) ;
791- k . m_result = new QueueDeclareOk ( method . _queue , method . _messageCount , method . _consumerCount ) ;
792- k . HandleCommand ( IncomingCommand . Empty ) ; // release the continuation.
797+ if ( _continuationQueue . TryPeek < QueueDeclareRpcContinuation > ( out var k ) )
798+ {
799+ _continuationQueue . Next ( ) ;
800+ var method = new Client . Framing . Impl . QueueDeclareOk ( cmd . MethodBytes . Span ) ;
801+ cmd . ReturnMethodBuffer ( ) ;
802+ k . m_result = new QueueDeclareOk ( method . _queue , method . _messageCount , method . _consumerCount ) ;
803+ k . HandleCommand ( IncomingCommand . Empty ) ; // release the continuation.
804+ return true ;
805+ }
806+ else
807+ {
808+ return false ;
809+ }
793810 }
794811
795812 public abstract void _Private_BasicCancel ( string consumerTag , bool nowait ) ;
@@ -844,12 +861,17 @@ public void BasicCancel(string consumerTag)
844861 {
845862 var k = new BasicConsumerRpcContinuation { m_consumerTag = consumerTag } ;
846863
847- lock ( _rpcLock )
864+ _rpcSemaphore . Wait ( ) ;
865+ try
848866 {
849867 Enqueue ( k ) ;
850868 _Private_BasicCancel ( consumerTag , false ) ;
851869 k . GetReply ( ContinuationTimeout ) ;
852870 }
871+ finally
872+ {
873+ _rpcSemaphore . Release ( ) ;
874+ }
853875 }
854876
855877 public void BasicCancelNoWait ( string consumerTag )
@@ -872,7 +894,8 @@ public string BasicConsume(string queue, bool autoAck, string consumerTag, bool
872894
873895 var k = new BasicConsumerRpcContinuation { m_consumer = consumer } ;
874896
875- lock ( _rpcLock )
897+ _rpcSemaphore . Wait ( ) ;
898+ try
876899 {
877900 Enqueue ( k ) ;
878901 // Non-nowait. We have an unconventional means of getting
@@ -881,6 +904,11 @@ public string BasicConsume(string queue, bool autoAck, string consumerTag, bool
881904 /*nowait:*/ false , arguments ) ;
882905 k . GetReply ( ContinuationTimeout ) ;
883906 }
907+ finally
908+ {
909+ _rpcSemaphore . Release ( ) ;
910+ }
911+
884912 string actualConsumerTag = k . m_consumerTag ;
885913
886914 return actualConsumerTag ;
@@ -889,12 +917,18 @@ public string BasicConsume(string queue, bool autoAck, string consumerTag, bool
889917 public BasicGetResult BasicGet ( string queue , bool autoAck )
890918 {
891919 var k = new BasicGetRpcContinuation ( ) ;
892- lock ( _rpcLock )
920+
921+ _rpcSemaphore . Wait ( ) ;
922+ try
893923 {
894924 Enqueue ( k ) ;
895925 _Private_BasicGet ( queue , autoAck ) ;
896926 k . GetReply ( ContinuationTimeout ) ;
897927 }
928+ finally
929+ {
930+ _rpcSemaphore . Release ( ) ;
931+ }
898932
899933 return k . m_result ;
900934 }
@@ -982,12 +1016,17 @@ public void BasicRecover(bool requeue)
9821016 {
9831017 var k = new SimpleBlockingRpcContinuation ( ) ;
9841018
985- lock ( _rpcLock )
1019+ _rpcSemaphore . Wait ( ) ;
1020+ try
9861021 {
9871022 Enqueue ( k ) ;
9881023 _Private_BasicRecover ( requeue ) ;
9891024 k . GetReply ( ContinuationTimeout ) ;
9901025 }
1026+ finally
1027+ {
1028+ _rpcSemaphore . Release ( ) ;
1029+ }
9911030 }
9921031
9931032 public abstract void BasicRecoverAsync ( bool requeue ) ;
@@ -1065,6 +1104,11 @@ public QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, b
10651104 return QueueDeclare ( queue , false , durable , exclusive , autoDelete , arguments ) ;
10661105 }
10671106
1107+ public ValueTask < QueueDeclareOk > QueueDeclareAsync ( string queue , bool durable , bool exclusive , bool autoDelete , IDictionary < string , object > arguments )
1108+ {
1109+ return QueueDeclareAsync ( queue , false , durable , exclusive , autoDelete , arguments ) ;
1110+ }
1111+
10681112 public void QueueDeclareNoWait ( string queue , bool durable , bool exclusive , bool autoDelete , IDictionary < string , object > arguments )
10691113 {
10701114 _Private_QueueDeclare ( queue , false , durable , exclusive , autoDelete , true , arguments ) ;
@@ -1196,17 +1240,44 @@ await CloseAsync(new ShutdownEventArgs(ShutdownInitiator.Library,
11961240 private QueueDeclareOk QueueDeclare ( string queue , bool passive , bool durable , bool exclusive , bool autoDelete , IDictionary < string , object > arguments )
11971241 {
11981242 var k = new QueueDeclareRpcContinuation ( ) ;
1199- lock ( _rpcLock )
1243+
1244+ _rpcSemaphore . Wait ( ) ;
1245+ try
12001246 {
12011247 Enqueue ( k ) ;
12021248 _Private_QueueDeclare ( queue , passive , durable , exclusive , autoDelete , false , arguments ) ;
12031249 k . GetReply ( ContinuationTimeout ) ;
12041250 }
1251+ finally
1252+ {
1253+ _rpcSemaphore . Release ( ) ;
1254+ }
1255+
12051256 QueueDeclareOk result = k . m_result ;
12061257 CurrentQueue = result . QueueName ;
12071258 return result ;
12081259 }
12091260
1261+ private async ValueTask < QueueDeclareOk > QueueDeclareAsync ( string queue , bool passive , bool durable , bool exclusive , bool autoDelete , IDictionary < string , object > arguments )
1262+ {
1263+ var k = new QueueDeclareAsyncRpcContinuation ( ) ;
1264+ await _rpcSemaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
1265+ try
1266+ {
1267+ Enqueue ( k ) ;
1268+
1269+ var method = new QueueDeclare ( queue , passive , durable , exclusive , autoDelete , false , arguments ) ;
1270+ await ModelSendAsync ( method ) . ConfigureAwait ( false ) ;
1271+
1272+ QueueDeclareOk result = await k ;
1273+ CurrentQueue = result . QueueName ;
1274+ return result ;
1275+ }
1276+ finally
1277+ {
1278+ _rpcSemaphore . Release ( ) ;
1279+ }
1280+ }
12101281
12111282 public class BasicConsumerRpcContinuation : SimpleBlockingRpcContinuation
12121283 {
@@ -1228,5 +1299,29 @@ public class QueueDeclareRpcContinuation : SimpleBlockingRpcContinuation
12281299 {
12291300 public QueueDeclareOk m_result ;
12301301 }
1302+
1303+ public class QueueDeclareAsyncRpcContinuation : AsyncRpcContinuation < QueueDeclareOk >
1304+ {
1305+ public override void HandleCommand ( in IncomingCommand cmd )
1306+ {
1307+ try
1308+ {
1309+ var method = new Client . Framing . Impl . QueueDeclareOk ( cmd . MethodBytes . Span ) ;
1310+ var result = new QueueDeclareOk ( method . _queue , method . _messageCount , method . _consumerCount ) ;
1311+ if ( cmd . CommandId == ProtocolCommandId . QueueDeclareOk )
1312+ {
1313+ _tcs . TrySetResult ( result ) ;
1314+ }
1315+ else
1316+ {
1317+ _tcs . SetException ( new InvalidOperationException ( $ "Received unexpected command of type { cmd . CommandId } !") ) ;
1318+ }
1319+ }
1320+ finally
1321+ {
1322+ cmd . ReturnMethodBuffer ( ) ;
1323+ }
1324+ }
1325+ }
12311326 }
12321327}
0 commit comments