From 701319a4bd6f331797050b7121a98527c4a93986 Mon Sep 17 00:00:00 2001 From: Alexander Serkov Date: Mon, 10 Mar 2025 23:46:02 +0400 Subject: [PATCH 1/2] Fix file descriptors (sockets) leak --- autoload/youcompleteme.vim | 3 ++- python/ycm/unsafe_thread_pool_executor.py | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index ec8109ea24..78e2a02dac 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -773,6 +773,7 @@ function! s:AbortAutohoverRequest() abort let request = requests[ request_id ] if request.origin == 'autohover' call remove( s:pollers.command.requests, request_id ) + py3 ycm_state.FlushCommandRequest( int( vim.eval( "request_id" ) ) ) call request.callback( '' ) endif endfor @@ -1551,7 +1552,7 @@ function! s:PollCommands( timer_id ) abort " This request is done call remove( s:pollers.command.requests, request_id ) - py3 ycm_state.FlushCommandRequest( vim.eval( "request_id" ) ) + py3 ycm_state.FlushCommandRequest( int( vim.eval( "request_id" ) ) ) call request[ 'callback' ]( result ) endfor diff --git a/python/ycm/unsafe_thread_pool_executor.py b/python/ycm/unsafe_thread_pool_executor.py index 5baa11f2d3..e99e294166 100644 --- a/python/ycm/unsafe_thread_pool_executor.py +++ b/python/ycm/unsafe_thread_pool_executor.py @@ -53,6 +53,10 @@ def _worker( executor_reference, work_queue ): work_item = work_queue.get( block=True ) if work_item is not None: work_item.run() + # Delete references to object, + # whis allow remove object by GC without stuck on work_queue.get() + # on next cycle iteration. See GH-60488 + del work_item continue executor = executor_reference() # Exit if: From 3999cf56740a9a1634fcb8a69b0e438c36953742 Mon Sep 17 00:00:00 2001 From: alxn1 Date: Tue, 30 Dec 2025 13:31:16 +0400 Subject: [PATCH 2/2] Remove WaitForCommandRequestComplete from hover tests, use CheckNoCommandRequest instead --- test/hover.test.vim | 50 ++++++++----------- .../autoload/youcompleteme/test/commands.vim | 15 ------ 2 files changed, 21 insertions(+), 44 deletions(-) diff --git a/test/hover.test.vim b/test/hover.test.vim index e430980540..0e71878122 100644 --- a/test/hover.test.vim +++ b/test/hover.test.vim @@ -1,7 +1,3 @@ -function! s:WaitForCommandRequestComplete() - return youcompleteme#test#commands#WaitForCommandRequestComplete() -endfunction - function! s:CheckNoCommandRequest() return youcompleteme#test#commands#CheckNoCommandRequest() endfunction @@ -19,7 +15,7 @@ function! s:CheckPopupVisibleScreenPos( loc, text, syntax ) " has 'text' (a list of lines) and 'syntax' the &syntax setting " popup found at that location redraw - call s:WaitForCommandRequestComplete() + call s:CheckNoCommandRequest() call WaitForAssert( { -> \ assert_notequal( 0, \ popup_locate( a:loc.row, a:loc.col ), @@ -37,25 +33,21 @@ function! s:CheckPopupVisibleScreenPos( loc, text, syntax ) call assert_equal( a:syntax, getbufvar( winbufnr( popup ), '&syntax' ) ) endfunction -function! s:CheckPopupNotVisible( row, col, with_request=v:true ) +function! s:CheckPopupNotVisible( row, col ) " Takes a buffer position and ensures there is no popup visible at that " position. Like CheckPopupVisible, the position must be valid (i.e. there " must be buffer text at that position). Otherwise, you need to pass the " _screen_ position to CheckPopupNotVisibleScreenPos redraw let loc = screenpos( win_getid(), a:row, a:col ) - return s:CheckPopupNotVisibleScreenPos( loc, a:with_request ) + return s:CheckPopupNotVisibleScreenPos( loc ) endfunction -function! s:CheckPopupNotVisibleScreenPos( loc, with_request=v:true ) +function! s:CheckPopupNotVisibleScreenPos( loc ) " Takes a position dict like the one returned by screenpos() and verifies it " does not have a popup drawn on it. redraw - if a:with_request - call s:WaitForCommandRequestComplete() - else - call s:CheckNoCommandRequest() - endif + call s:CheckNoCommandRequest() call WaitForAssert( { -> \ assert_equal( 0, \ popup_locate( a:loc.row, a:loc.col ) ) @@ -158,7 +150,7 @@ EOPYTHON call setpos( '.', [ 0, 12, 3 ] ) normal \D - call s:CheckPopupNotVisible( 11, 4, v:false ) + call s:CheckPopupNotVisible( 11, 4 ) call popup_clear() endfunction @@ -176,8 +168,8 @@ EOPYTHON call assert_equal( { 'command': 'GetType', 'syntax': 'python' }, b:ycm_hover ) - call s:CheckPopupNotVisible( 2, 1, v:none ) - call s:CheckPopupNotVisible( 2, 2, v:none ) + call s:CheckPopupNotVisible( 2, 1 ) + call s:CheckPopupNotVisible( 2, 2 ) " some doc - autocommand call setpos( '.', [ 0, 12, 3 ] ) @@ -247,7 +239,7 @@ function! Test_AutoHover_Disabled() call setpos( '.', [ 0, 12, 3 ] ) silent! doautocmd CursorHold - call s:CheckPopupNotVisible( 11, 4, v:false ) + call s:CheckPopupNotVisible( 11, 4 ) call assert_equal( messages_before, execute( 'messages' ) ) " Manual hover is still supported @@ -258,7 +250,7 @@ function! Test_AutoHover_Disabled() " Manual close hover is still supported normal \D - call s:CheckPopupNotVisible( 11, 4, v:false ) + call s:CheckPopupNotVisible( 11, 4 ) call assert_equal( messages_before, execute( 'messages' ) ) call popup_clear() @@ -311,11 +303,11 @@ function! Test_Hover_Dismiss() " Dismiss normal \D - call s:CheckPopupNotVisible( 11, 3, v:false ) + call s:CheckPopupNotVisible( 11, 3 ) " Make sure it doesn't come back silent! doautocmd CursorHold - call s:CheckPopupNotVisible( 11, 3, v:false ) + call s:CheckPopupNotVisible( 11, 3 ) " Move the cursor (again this is tricky). I couldn't find any tests in vim's " own code that trigger CursorMoved, so we just cheat. (for the record, just @@ -351,7 +343,7 @@ function! Test_Hover_Custom_Syntax() \ 'cpp' ) normal \D - call s:CheckPopupNotVisibleScreenPos( { 'row': 7, 'col': 9 }, v:false ) + call s:CheckPopupNotVisibleScreenPos( { 'row': 7, 'col': 9 } ) call popup_clear() endfunction @@ -424,10 +416,10 @@ function! Test_Hover_Custom_Popup() \ s:cpp_lifetime.GetDoc, \ 'cpp' ) " Check that popup's width is limited by maxwidth being passed - call s:CheckPopupNotVisibleScreenPos( { 'row': 7, 'col': 20 }, v:false ) + call s:CheckPopupNotVisibleScreenPos( { 'row': 7, 'col': 20 } ) normal \D - call s:CheckPopupNotVisibleScreenPos( { 'row': 7, 'col': 9 }, v:false ) + call s:CheckPopupNotVisibleScreenPos( { 'row': 7, 'col': 9 } ) call popup_clear() endfunction @@ -446,8 +438,8 @@ function! Test_Long_Single_Line() call s:CheckPopupVisible( 36, 1, v:none, '' ) call s:CheckPopupVisible( 36, &columns, v:none, '' ) - call s:CheckPopupNotVisible( 37, 1, v:false ) - call s:CheckPopupNotVisible( 37, &columns, v:false ) + call s:CheckPopupNotVisible( 37, 1 ) + call s:CheckPopupNotVisible( 37, &columns ) " Also wrap is ON so it should cover at least 2 lines + 2 for the header/empty " line @@ -469,16 +461,16 @@ function! Test_Long_Wrapped() call s:CheckPopupVisible( 37, 1, v:none, '' ) call s:CheckPopupVisible( 37, &columns, v:none, '' ) - call s:CheckPopupNotVisible( 38, 1, v:false ) - call s:CheckPopupNotVisible( 38, &columns, v:false ) + call s:CheckPopupNotVisible( 38, 1 ) + call s:CheckPopupNotVisible( 38, &columns ) " Also, wrap is off, so it should be _exactly_ 9 lines + 2 for the signature " and the empty line call s:CheckPopupVisible( 27, 1, v:none, '' ) call s:CheckPopupVisible( 27, &columns, v:none, '' ) - call s:CheckPopupNotVisible( 26, 1, v:false ) - call s:CheckPopupNotVisible( 26, &columns, v:false ) + call s:CheckPopupNotVisible( 26, 1 ) + call s:CheckPopupNotVisible( 26, &columns ) call popup_clear() endfunction diff --git a/test/lib/autoload/youcompleteme/test/commands.vim b/test/lib/autoload/youcompleteme/test/commands.vim index 8576bc25ff..8212e5e524 100644 --- a/test/lib/autoload/youcompleteme/test/commands.vim +++ b/test/lib/autoload/youcompleteme/test/commands.vim @@ -1,18 +1,3 @@ -function! youcompleteme#test#commands#WaitForCommandRequestComplete() abort - call WaitForAssert( { -> - \ assert_true( py3eval( - \ 'ycm_state.GetCommandRequest( ' - \ . ' ycm_state._next_command_request_id - 1 ) is not None and ' - \ . 'ycm_state.GetCommandRequest( ' - \ . ' ycm_state._next_command_request_id - 1 ).Done()' ) ) - \ } ) - - call WaitForAssert( { -> - \ assert_equal( -1, - \ youcompleteme#Test_GetPollers().command.id ) - \ } ) -endfunction - function! youcompleteme#test#commands#CheckNoCommandRequest() abort call WaitForAssert( { -> \ assert_true( py3eval(