@@ -1116,8 +1116,8 @@ def tls_verified?; @tls_verified end
1116
1116
#
1117
1117
# Related: #logout, #logout!
1118
1118
def disconnect
1119
+ in_logout_state = try_state_logout?
1119
1120
return if disconnected?
1120
- state_logout!
1121
1121
begin
1122
1122
begin
1123
1123
# try to call SSL::SSLSocket#io.
@@ -1131,11 +1131,15 @@ def disconnect
1131
1131
rescue Exception => e
1132
1132
@receiver_thread . raise ( e )
1133
1133
end
1134
- @receiver_thread . join
1135
1134
synchronize do
1136
1135
@sock . close
1137
1136
end
1137
+ @receiver_thread . join
1138
1138
raise e if e
1139
+ ensure
1140
+ # Try again after shutting down the receiver thread. With no reciever
1141
+ # left to wait for, any remaining locks should be _very_ brief.
1142
+ state_logout! unless in_logout_state
1139
1143
end
1140
1144
1141
1145
# Returns true if disconnected from the server.
@@ -3062,8 +3066,8 @@ def idle(timeout = nil, &response_handler)
3062
3066
raise @exception || Net ::IMAP ::Error . new ( "connection closed" )
3063
3067
end
3064
3068
ensure
3069
+ remove_response_handler ( response_handler )
3065
3070
unless @receiver_thread_terminating
3066
- remove_response_handler ( response_handler )
3067
3071
put_string ( "DONE#{ CRLF } " )
3068
3072
response = get_tagged_response ( tag , "IDLE" , idle_response_timeout )
3069
3073
end
@@ -3346,8 +3350,6 @@ def start_receiver_thread
3346
3350
rescue Exception => ex
3347
3351
@receiver_thread_exception = ex
3348
3352
# don't exit the thread with an exception
3349
- ensure
3350
- state_logout!
3351
3353
end
3352
3354
end
3353
3355
@@ -3429,6 +3431,8 @@ def receive_responses
3429
3431
@idle_done_cond . signal
3430
3432
end
3431
3433
end
3434
+ ensure
3435
+ state_logout!
3432
3436
end
3433
3437
3434
3438
def get_tagged_response ( tag , cmd , timeout = nil )
@@ -3791,15 +3795,29 @@ def state_selected!
3791
3795
end
3792
3796
3793
3797
def state_unselected!
3794
- state_authenticated! if connection_state . to_sym == :selected
3798
+ synchronize do
3799
+ state_authenticated! if connection_state . to_sym == :selected
3800
+ end
3795
3801
end
3796
3802
3797
3803
def state_logout!
3804
+ return true if connection_state in [ :logout , *]
3798
3805
synchronize do
3806
+ return true if connection_state in [ :logout , *]
3799
3807
@connection_state = ConnectionState ::Logout . new
3800
3808
end
3801
3809
end
3802
3810
3811
+ # don't wait to aqcuire the lock
3812
+ def try_state_logout?
3813
+ return true if connection_state in [ :logout , *]
3814
+ return false unless acquired_lock = mon_try_enter
3815
+ state_logout!
3816
+ true
3817
+ ensure
3818
+ mon_exit if acquired_lock
3819
+ end
3820
+
3803
3821
def sasl_adapter
3804
3822
SASLAdapter . new ( self , &method ( :send_command_with_continuations ) )
3805
3823
end
0 commit comments