@@ -731,7 +731,7 @@ public override void EnlistTransaction(Transaction? transaction)
731731 /// Releases the connection. If the connection is pooled, it will be returned to the pool and made available for re-use.
732732 /// If it is non-pooled, the physical connection will be closed.
733733 /// </summary>
734- public override void Close ( ) => Close ( async: false ) ;
734+ public override void Close ( ) => Close ( async: false ) . GetAwaiter ( ) . GetResult ( ) ;
735735
736736 /// <summary>
737737 /// Releases the connection. If the connection is pooled, it will be returned to the pool and made available for re-use.
@@ -747,28 +747,34 @@ public override Task CloseAsync()
747747 return Close ( async: true ) ;
748748 }
749749
750+ internal bool TakeCloseLock ( ) => Interlocked . Exchange ( ref _closing , 1 ) == 0 ;
751+
752+ internal void ReleaseCloseLock ( ) => Volatile . Write ( ref _closing , 0 ) ;
753+
750754 internal Task Close ( bool async )
751755 {
752756 // Even though NpgsqlConnection isn't thread safe we'll make sure this part is.
753757 // Because we really don't want double returns to the pool.
754- if ( Interlocked . Exchange ( ref _closing , 1 ) == 1 )
758+ if ( ! TakeCloseLock ( ) )
755759 return Task . CompletedTask ;
756760
757761 switch ( FullState )
758762 {
759763 case ConnectionState . Open :
760764 case ConnectionState . Open | ConnectionState . Executing :
761765 case ConnectionState . Open | ConnectionState . Fetching :
762- case ConnectionState . Broken :
763766 break ;
767+ case ConnectionState . Broken :
768+ FullState = ConnectionState . Closed ;
769+ goto case ConnectionState . Closed ;
764770 case ConnectionState . Closed :
765- Volatile . Write ( ref _closing , 0 ) ;
771+ ReleaseCloseLock ( ) ;
766772 return Task . CompletedTask ;
767773 case ConnectionState . Connecting :
768- Volatile . Write ( ref _closing , 0 ) ;
774+ ReleaseCloseLock ( ) ;
769775 throw new InvalidOperationException ( "Can't close, connection is in state " + FullState ) ;
770776 default :
771- Volatile . Write ( ref _closing , 0 ) ;
777+ ReleaseCloseLock ( ) ;
772778 throw new ArgumentOutOfRangeException ( "Unknown connection state: " + FullState ) ;
773779 }
774780
@@ -779,7 +785,7 @@ internal Task Close(bool async)
779785 // TODO: Consider falling through to the regular reset logic. This adds some unneeded conditions
780786 // and assignment but actual perf impact should be negligible (measure).
781787 Debug . Assert ( Connector == null ) ;
782- Volatile . Write ( ref _closing , 0 ) ;
788+ ReleaseCloseLock ( ) ;
783789
784790 FullState = ConnectionState . Closed ;
785791 Log . Debug ( "Connection closed (multiplexing)" ) ;
@@ -820,14 +826,7 @@ async Task CloseAsync(bool async)
820826 Debug . Assert ( connector . CurrentReader == null ) ;
821827 Debug . Assert ( connector . CurrentCopyOperation == null ) ;
822828
823- if ( connector . IsBroken )
824- {
825- connector . Connection = null ;
826- connector . Return ( ) ;
827-
828- EnlistedTransaction = null ;
829- }
830- else if ( EnlistedTransaction != null )
829+ if ( EnlistedTransaction != null )
831830 {
832831 // A System.Transactions transaction is still in progress
833832
@@ -881,7 +880,7 @@ async Task CloseAsync(bool async)
881880 }
882881 finally
883882 {
884- Volatile . Write ( ref _closing , 0 ) ;
883+ ReleaseCloseLock ( ) ;
885884 }
886885 }
887886
@@ -1768,7 +1767,8 @@ internal T CheckOpenAndRunInTemporaryScope<T>(Func<NpgsqlConnector, T> func)
17681767 /// </remarks>
17691768 internal void EndBindingScope ( ConnectorBindingScope scope )
17701769 {
1771- Debug . Assert ( ConnectorBindingScope != ConnectorBindingScope . None , $ "Ending binding scope { scope } but connection's scope is null") ;
1770+ Debug . Assert ( ConnectorBindingScope != ConnectorBindingScope . None || FullState == ConnectionState . Broken ,
1771+ $ "Ending binding scope { scope } but connection's scope is null") ;
17721772
17731773 if ( scope != ConnectorBindingScope )
17741774 return ;
0 commit comments