From 088eb4d0d2c826f1b294530b91dc6ea1a5071496 Mon Sep 17 00:00:00 2001 From: Strahinja Val Markovic Date: Mon, 23 Sep 2013 14:33:14 -0700 Subject: [PATCH] Cleaner server shutdown Listening for VimLeave was sub-optimal. popen.terminate() is much cleaner. --- python/ycm/completers/completer.py | 13 +++++---- python/ycm/completers/cs/cs_completer.py | 6 ++-- .../general/general_completer_store.py | 12 ++++---- python/ycm/extra_conf_store.py | 5 +++- python/ycm/server/server.py | 28 +++---------------- python/ycm/server/server_state.py | 11 ++++++++ python/ycm/youcompleteme.py | 13 +++++---- 7 files changed, 44 insertions(+), 44 deletions(-) diff --git a/python/ycm/completers/completer.py b/python/ycm/completers/completer.py index 321c8e1c..84411d95 100644 --- a/python/ycm/completers/completer.py +++ b/python/ycm/completers/completer.py @@ -109,7 +109,10 @@ class Completer( object ): configuration. When the command is called with no arguments you should print a short summary of the supported commands or point the user to the help section where this - information can be found.""" + information can be found. + + Override the Shutdown() member function if your Completer subclass needs to do + custom cleanup logic on server shutdown.""" __metaclass__ = abc.ABCMeta @@ -277,10 +280,6 @@ class Completer( object ): pass - def OnVimLeave( self, request_data ): - pass - - def OnUserCommand( self, arguments, request_data ): raise NotImplementedError( NO_USER_COMMANDS ) @@ -324,6 +323,10 @@ class Completer( object ): return '' + def Shutdown( self ): + pass + + class CompletionsCache( object ): def __init__( self ): self.line = -1 diff --git a/python/ycm/completers/cs/cs_completer.py b/python/ycm/completers/cs/cs_completer.py index 20240ee8..0f902c27 100755 --- a/python/ycm/completers/cs/cs_completer.py +++ b/python/ycm/completers/cs/cs_completer.py @@ -46,11 +46,11 @@ class CsharpCompleter( ThreadedCompleter ): self._omnisharp_port = None self._logger = logging.getLogger( __name__ ) - # if self.user_options[ 'auto_start_csharp_server' ]: - # self._StartServer() + if self.user_options[ 'auto_start_csharp_server' ]: + self._StartServer() - def OnVimLeave( self ): + def Shutdown( self ): if ( self.user_options[ 'auto_start_csharp_server' ] and self._ServerIsRunning() ): self._StopServer() diff --git a/python/ycm/completers/general/general_completer_store.py b/python/ycm/completers/general/general_completer_store.py index 3269bc97..4effcdd4 100644 --- a/python/ycm/completers/general/general_completer_store.py +++ b/python/ycm/completers/general/general_completer_store.py @@ -115,11 +115,6 @@ class GeneralCompleterStore( Completer ): completer.OnInsertLeave( request_data ) - def OnVimLeave( self, request_data ): - for completer in self._all_completers: - completer.OnVimLeave( request_data ) - - def OnCurrentIdentifierFinished( self, request_data ): for completer in self._all_completers: completer.OnCurrentIdentifierFinished( request_data ) @@ -128,3 +123,10 @@ class GeneralCompleterStore( Completer ): def GettingCompletions( self ): for completer in self._all_completers: completer.GettingCompletions() + + + def Shutdown( self ): + for completer in self._all_completers: + completer.Shutdown() + + diff --git a/python/ycm/extra_conf_store.py b/python/ycm/extra_conf_store.py index 15a3f087..277b9d61 100644 --- a/python/ycm/extra_conf_store.py +++ b/python/ycm/extra_conf_store.py @@ -65,8 +65,11 @@ def CallExtraConfYcmCorePreloadIfExists(): _CallExtraConfMethod( 'YcmCorePreload' ) -def OnVimLeave( request_data ): +def Shutdown(): + # VimClose is for the sake of backwards compatibility; it's a no-op when it + # doesn't exist. _CallExtraConfMethod( 'VimClose' ) + _CallExtraConfMethod( 'Shutdown' ) def _CallExtraConfMethod( function_name ): diff --git a/python/ycm/server/server.py b/python/ycm/server/server.py index 5c6cfc8e..df3d8507 100755 --- a/python/ycm/server/server.py +++ b/python/ycm/server/server.py @@ -19,7 +19,7 @@ import sys import os -import threading +import atexit # We want to have the YouCompleteMe/python directory on the Python PATH because # all the code already assumes that it's there. This is a relic from before the @@ -37,9 +37,7 @@ import json import bottle from bottle import run, request, response import server_state -from ycm import extra_conf_store from ycm import user_options_store -from ycm import utils import argparse # num bytes for the request body buffer; request.json only works if the request @@ -68,16 +66,6 @@ def EventNotification(): getattr( SERVER_STATE.GetFiletypeCompleter( filetypes ), event_handler )( request_data ) - try: - if hasattr( extra_conf_store, event_handler ): - getattr( extra_conf_store, event_handler )( request_data ) - except OSError as e: - LOGGER.exception( e ) - - if event_name == 'VimLeave': - _ScheduleServerShutdown() - - @app.post( '/run_completer_command' ) def RunCompleterCommand(): @@ -147,17 +135,9 @@ def _JsonResponse( data ): return json.dumps( data ) -def _ScheduleServerShutdown(): - # The reason why we want to schedule a shutdown in the near future instead of - # just shutting down right now is because we want the current request (the one - # that made us want to shutdown) to complete successfully first. - - def Shutdown(): - # sys.exit() doesn't work because we're not in the main thread. - utils.TerminateProcess( os.getpid() ) - - killer_thread = threading.Timer( 2, Shutdown ) - killer_thread.start() +@atexit.register +def _ServerShutdown(): + SERVER_STATE.Shutdown() def Main(): diff --git a/python/ycm/server/server_state.py b/python/ycm/server/server_state.py index a7f3eaa0..4824732c 100644 --- a/python/ycm/server/server_state.py +++ b/python/ycm/server/server_state.py @@ -19,6 +19,7 @@ import imp import os +from ycm import extra_conf_store from ycm.completers.general.general_completer_store import GeneralCompleterStore @@ -27,6 +28,7 @@ class ServerState( object ): self._user_options = user_options self._filetype_completers = {} self._gencomp = GeneralCompleterStore( self._user_options ) + extra_conf_store.CallExtraConfYcmCorePreloadIfExists() @property @@ -34,6 +36,15 @@ class ServerState( object ): return self._user_options + def Shutdown( self ): + for completer in self._filetype_completers.itervalues(): + completer.Shutdown() + + self._gencomp.Shutdown() + extra_conf_store.Shutdown() + + + def _GetFiletypeCompleterForFiletype( self, filetype ): try: return self._filetype_completers[ filetype ] diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index c8b574c2..b2e0f7ab 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -39,6 +39,7 @@ class YouCompleteMe( object ): self._current_completion_request = None self._server_stdout = None self._server_stderr = None + self._server_popen = None self._SetupServer() @@ -54,7 +55,7 @@ class YouCompleteMe( object ): BaseRequest.server_location = 'http://localhost:' + str( server_port ) if self._user_options[ 'server_use_vim_stdout' ]: - subprocess.Popen( command, shell = True ) + self._server_popen = subprocess.Popen( command, shell = True ) else: filename_format = os.path.join( utils.PathToTempDir(), 'server_{port}_{std}.log' ) @@ -66,10 +67,10 @@ class YouCompleteMe( object ): with open( self._server_stderr, 'w' ) as fstderr: with open( self._server_stdout, 'w' ) as fstdout: - subprocess.Popen( command, - stdout = fstdout, - stderr = fstderr, - shell = True ) + self._server_popen = subprocess.Popen( command, + stdout = fstdout, + stderr = fstderr, + shell = True ) def CreateCompletionRequest( self ): @@ -146,7 +147,7 @@ class YouCompleteMe( object ): def OnVimLeave( self ): - SendEventNotificationAsync( 'VimLeave' ) + self._server_popen.terminate() def OnCurrentIdentifierFinished( self ):