Author: Roy Shi
Date: 2025-09-23T07:44:50-07:00
New Revision: 6007a4dbed2d8867c75bd571e1eb38e10ae14a27

URL: 
https://github.com/llvm/llvm-project/commit/6007a4dbed2d8867c75bd571e1eb38e10ae14a27
DIFF: 
https://github.com/llvm/llvm-project/commit/6007a4dbed2d8867c75bd571e1eb38e10ae14a27.diff

LOG: [vscode-lldb] Restart server when lldb-dap binary has changed (#159797)

# Motiviation

This helps the development of the lldb-dap binary. For example, when
testing a locally built lldb-dap binary, one probably wants to restart
the server after each build in order to use the latest binary. Not doing
so leads to confusion like "why the new lldb-dap isn't doing what I just
changed?".

This patch adds dependency to the `chokidar` package. The reason is that
we need something to detect changes to the `lldb-dap` binary file and
`chokidar` appears to be the most reliable package to do so. An
alternative solution which doesn't require adding dependencies is
discussed below (solution 1).

# Two different solutions considered

Solution 1: Restart server when lldb-dap binary's modification time
changes. https://github.com/llvm/llvm-project/pull/159481 implements
solution 1.

Solution 2: Restart server when lldb-dap binary has changed (as detected
by a file system watcher). This patch implements solution 2 (using
`chokidar`).

# This patch (solution 2)

If the lldb-dap binary has changed, the next time the user start a debug
session, a dialog box will show up and prompt the user to restart the
server. Depend on what has changed, the dialog box will show different
content (see below)

* When both the lldb-dap binary and the arguments have changed:
<img width="520" height="357" alt="diff_args_and_binary"
src="https://github.com/user-attachments/assets/6580e05f-05c3-4d80-8c1a-9c3abf279218";
/>

* When only the lldb-dap binary has changed:
<img width="260" height="384" alt="diff_binary"
src="https://github.com/user-attachments/assets/933b8987-9c21-44f3-ad68-57b8eeb58525";
/>

* When only the arguments have changed (existing):
<img width="520" height="343" alt="diff_args"
src="https://github.com/user-attachments/assets/c0e6771c-ad32-4fb8-b5df-b34cce48ed1a";
/>

Added: 
    

Modified: 
    lldb/tools/lldb-dap/package-lock.json
    lldb/tools/lldb-dap/package.json
    lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts

Removed: 
    


################################################################################
diff  --git a/lldb/tools/lldb-dap/package-lock.json 
b/lldb/tools/lldb-dap/package-lock.json
index f3ae6b76be6d0..826f29f70106c 100644
--- a/lldb/tools/lldb-dap/package-lock.json
+++ b/lldb/tools/lldb-dap/package-lock.json
@@ -8,6 +8,9 @@
       "name": "lldb-dap",
       "version": "0.2.16",
       "license": "Apache 2.0 License with LLVM exceptions",
+      "dependencies": {
+        "chokidar": "^4.0.3"
+      },
       "devDependencies": {
         "@types/node": "^18.19.41",
         "@types/tabulator-tables": "^6.2.10",
@@ -1301,6 +1304,21 @@
         "url": "https://github.com/sponsors/fb55";
       }
     },
+    "node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/chownr": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz";,
@@ -2746,6 +2764,19 @@
         "node": ">= 6"
       }
     },
+    "node_modules/readdirp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz";,
+      "integrity": 
"sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/safe-buffer": {
       "version": "5.2.1",
       "resolved": 
"https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz";,

diff  --git a/lldb/tools/lldb-dap/package.json 
b/lldb/tools/lldb-dap/package.json
index 6566ba3bdee13..3892535853f56 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -27,6 +27,9 @@
   "categories": [
     "Debuggers"
   ],
+  "dependencies": {
+    "chokidar": "^4.0.3"
+  },
   "devDependencies": {
     "@types/node": "^18.19.41",
     "@types/tabulator-tables": "^6.2.10",

diff  --git a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts 
b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
index 280a11d807f6a..4e348965930d9 100644
--- a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
@@ -1,4 +1,6 @@
+import { FSWatcher, watch as chokidarWatch } from 'chokidar';
 import * as child_process from "node:child_process";
+import * as path from "path";
 import { isDeepStrictEqual } from "util";
 import * as vscode from "vscode";
 
@@ -12,6 +14,10 @@ export class LLDBDapServer implements vscode.Disposable {
   private serverProcess?: child_process.ChildProcessWithoutNullStreams;
   private serverInfo?: Promise<{ host: string; port: number }>;
   private serverSpawnInfo?: string[];
+  // Detects changes to the lldb-dap executable file since the server's 
startup.
+  private serverFileWatcher?: FSWatcher;
+  // Indicates whether the lldb-dap executable file has changed since the 
server's startup.
+  private serverFileChanged?: boolean;
 
   constructor() {
     vscode.commands.registerCommand(
@@ -83,6 +89,11 @@ export class LLDBDapServer implements vscode.Disposable {
       });
       this.serverProcess = process;
       this.serverSpawnInfo = this.getSpawnInfo(dapPath, dapArgs, options?.env);
+      this.serverFileChanged = false;
+      this.serverFileWatcher = chokidarWatch(dapPath);
+      this.serverFileWatcher
+        .on('change', () => this.serverFileChanged = true)
+        .on('unlink', () => this.serverFileChanged = true);
     });
     return this.serverInfo;
   }
@@ -100,21 +111,27 @@ export class LLDBDapServer implements vscode.Disposable {
     args: string[],
     env: NodeJS.ProcessEnv | { [key: string]: string } | undefined,
   ): Promise<boolean> {
-    if (!this.serverProcess || !this.serverInfo || !this.serverSpawnInfo) {
+    if (
+      !this.serverProcess ||
+      !this.serverInfo ||
+      !this.serverSpawnInfo ||
+      !this.serverFileWatcher ||
+      this.serverFileChanged === undefined
+    ) {
       return true;
     }
 
-    const newSpawnInfo = this.getSpawnInfo(dapPath, args, env);
-    if (isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) {
-      return true;
-    }
+    const changeTLDR = [];
+    const changeDetails = [];
 
-    const userInput = await vscode.window.showInformationMessage(
-      "The arguments to lldb-dap have changed. Would you like to restart the 
server?",
-      {
-        modal: true,
-        detail: `An existing lldb-dap server (${this.serverProcess.pid}) is 
running with 
diff erent arguments.
+    if (this.serverFileChanged) {
+      changeTLDR.push("an old binary");
+    }
 
+    const newSpawnInfo = this.getSpawnInfo(dapPath, args, env);
+    if (!isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) {
+      changeTLDR.push("
diff erent arguments");
+      changeDetails.push(`
 The previous lldb-dap server was started with:
 
 ${this.serverSpawnInfo.join(" ")}
@@ -122,7 +139,22 @@ ${this.serverSpawnInfo.join(" ")}
 The new lldb-dap server will be started with:
 
 ${newSpawnInfo.join(" ")}
+`
+      );
+    }
+
+    // If the server hasn't changed, continue startup without killing it.
+    if (changeTLDR.length === 0) {
+      return true;
+    }
 
+    // The server has changed. Prompt the user to restart it.
+    const userInput = await vscode.window.showInformationMessage(
+      "The lldb-dap server has changed. Would you like to restart the server?",
+      {
+        modal: true,
+        detail: `An existing lldb-dap server (${this.serverProcess.pid}) is 
running with ${changeTLDR.map(s => `*${s}*`).join(" and ")}.
+${changeDetails.join("\n")}
 Restarting the server will interrupt any existing debug sessions and start a 
new server.`,
       },
       "Restart",
@@ -130,9 +162,7 @@ Restarting the server will interrupt any existing debug 
sessions and start a new
     );
     switch (userInput) {
       case "Restart":
-        this.serverProcess.kill();
-        this.serverProcess = undefined;
-        this.serverInfo = undefined;
+        this.dispose();
         return true;
       case "Use Existing":
         return true;
@@ -156,6 +186,10 @@ Restarting the server will interrupt any existing debug 
sessions and start a new
     if (this.serverProcess === process) {
       this.serverProcess = undefined;
       this.serverInfo = undefined;
+      this.serverSpawnInfo = undefined;
+      this.serverFileWatcher?.close();
+      this.serverFileWatcher = undefined;
+      this.serverFileChanged = undefined;
     }
   }
 


        
_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to