Skip to content

Commit

Permalink
Server shutdown in case the client process has exited unexpectedly. (#64
Browse files Browse the repository at this point in the history
)

Monitor the client process ID, received in the initialize request and shutdown
the server in case the client process is found to be dead. This fixes the
remaining nimlangserver processes after an IDE crash, or in case of broken IDE
and/or plugin not sending the proper shutdown and exit commands to the server.
  • Loading branch information
nickysn authored Dec 1, 2023
1 parent c8c6844 commit 3a537e5
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
7 changes: 6 additions & 1 deletion nimlangserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import macros, strformat, faststreams/async_backend,
faststreams/asynctools_adapters, faststreams/inputs, faststreams/outputs,
json_rpc/streamconnection, os, sugar, sequtils, hashes, osproc,
suggestapi, protocol/enums, protocol/types, with, tables, strutils, sets,
./utils, ./pipes, chronicles, std/re, uri, "$nim/compiler/pathutils"
./utils, ./pipes, chronicles, std/re, uri, "$nim/compiler/pathutils",
procmonitor

const
RESTART_COMMAND = "nimlangserver.restart"
Expand Down Expand Up @@ -159,6 +160,10 @@ proc getCharacter(ls: LanguageServer, uri: string, line: int, character: int): i
proc initialize(ls: LanguageServer, params: InitializeParams):
Future[InitializeResult] {.async.} =
debug "Initialize received..."
if params.processId.isSome:
let pid = params.processId.get
if pid.kind == JInt:
hookProcMonitor(int(pid.num))
ls.initializeParams = params
result = InitializeResult(
capabilities: ServerCapabilities(
Expand Down
34 changes: 34 additions & 0 deletions procmonitor.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Monitor a client process and shutdown the current process, if the client
# process is found to be dead

import os

when defined(posix):
import posix_utils
import posix

when defined(windows):
import winlean

when defined(posix):
proc monitorClientProcessIdThreadProc(pid: int) {.thread.} =
while true:
sleep(1000)
try:
sendSignal(Pid(pid), 0)
except:
discard kill(Pid(getCurrentProcessId()), cint(SIGTERM))

when defined(windows):
proc monitorClientProcessIdThreadProc(pid: int) {.thread.} =
var process = openProcess(SYNCHRONIZE, 0, DWORD(pid))
if process != 0:
discard waitForSingleObject(process, INFINITE)
discard closeHandle(process)
quit(0)

var tid: Thread[int]

proc hookProcMonitor*(pid: int) =
when defined(posix) or defined(windows):
createThread(tid, monitorClientProcessIdThreadProc, pid)

0 comments on commit 3a537e5

Please sign in to comment.