@@ -68,14 +68,11 @@ export async function startDapServer(
6868 } else {
6969 configuration . port = await getPort ( ) ;
7070 }
71- const dlvDapServer = spawnDlvDapServerProcess ( configuration ) ;
72- // Wait to give dlv-dap a chance to start before returning.
73- return await new Promise < { port : number ; host : string ; dlvDapServer : ChildProcessWithoutNullStreams } > ( ( resolve ) =>
74- setTimeout ( ( ) => resolve ( { port : configuration . port , host : configuration . host , dlvDapServer } ) , 500 )
75- ) ;
71+ const dlvDapServer = await spawnDlvDapServerProcess ( configuration ) ;
72+ return { dlvDapServer, port : configuration . port , host : configuration . host } ;
7673}
7774
78- function spawnDlvDapServerProcess ( launchArgs : DebugConfiguration ) {
75+ async function spawnDlvDapServerProcess ( launchArgs : DebugConfiguration ) : Promise < ChildProcess > {
7976 const launchArgsEnv = launchArgs . env || { } ;
8077 const env = Object . assign ( { } , process . env , launchArgsEnv ) ;
8178
@@ -114,30 +111,66 @@ function spawnDlvDapServerProcess(launchArgs: DebugConfiguration) {
114111 appendToDebugConsole ( `Running: ${ dlvPath } ${ dlvArgs . join ( ' ' ) } ` ) ;
115112
116113 const dir = parseProgramArgSync ( launchArgs ) . dirname ;
117- const p = spawn ( dlvPath , dlvArgs , {
118- cwd : dir ,
119- env
120- } ) ;
121114
122- p . stderr . on ( 'data' , ( chunk ) => {
123- appendToDebugConsole ( chunk . toString ( ) ) ;
124- } ) ;
125- p . stdout . on ( 'data' , ( chunk ) => {
126- appendToDebugConsole ( chunk . toString ( ) ) ;
127- } ) ;
128- p . on ( 'close' , ( code ) => {
129- if ( code ) {
130- appendToDebugConsole ( `Process exiting with code: ${ code } signal: ${ p . killed } ` ) ;
131- } else {
132- appendToDebugConsole ( `Process exited normally: ${ p . killed } ` ) ;
133- }
134- } ) ;
135- p . on ( 'error' , ( err ) => {
136- if ( err ) {
137- appendToDebugConsole ( `Error: ${ err } ` ) ;
138- }
115+ return await new Promise < ChildProcess > ( ( resolve , reject ) => {
116+ const p = spawn ( dlvPath , dlvArgs , {
117+ cwd : dir ,
118+ env
119+ } ) ;
120+ let started = false ;
121+ const timeoutToken : NodeJS . Timer = setTimeout (
122+ ( ) => reject ( new Error ( 'timed out while waiting for DAP server to start' ) ) ,
123+ 5_000
124+ ) ;
125+
126+ const stopWaitingForServerToStart = ( err ?: string ) => {
127+ clearTimeout ( timeoutToken ) ;
128+ started = true ;
129+ if ( err ) {
130+ killProcessTree ( p ) ; // We do not need to wait for p to actually be killed.
131+ reject ( new Error ( err ) ) ;
132+ } else {
133+ resolve ( p ) ;
134+ }
135+ } ;
136+
137+ p . stdout . on ( 'data' , ( chunk ) => {
138+ if ( ! started ) {
139+ if ( chunk . toString ( ) . startsWith ( 'DAP server listening at:' ) ) {
140+ stopWaitingForServerToStart ( ) ;
141+ } else {
142+ stopWaitingForServerToStart (
143+ `Expected 'DAP server listening at:' from debug adapter got '${ chunk . toString ( ) } '`
144+ ) ;
145+ }
146+ }
147+ appendToDebugConsole ( chunk . toString ( ) ) ;
148+ } ) ;
149+ p . stderr . on ( 'data' , ( chunk ) => {
150+ if ( ! started ) {
151+ stopWaitingForServerToStart ( `Unexpected error from dlv dap on start: '${ chunk . toString ( ) } '` ) ;
152+ }
153+ appendToDebugConsole ( chunk . toString ( ) ) ;
154+ } ) ;
155+ p . on ( 'close' , ( code ) => {
156+ if ( ! started ) {
157+ stopWaitingForServerToStart ( `dlv dap closed with code: '${ code } ' signal: ${ p . killed } ` ) ;
158+ }
159+ if ( code ) {
160+ appendToDebugConsole ( `Process exiting with code: ${ code } signal: ${ p . killed } ` ) ;
161+ } else {
162+ appendToDebugConsole ( `Process exited normally: ${ p . killed } ` ) ;
163+ }
164+ } ) ;
165+ p . on ( 'error' , ( err ) => {
166+ if ( ! started ) {
167+ stopWaitingForServerToStart ( `Unexpected error from dlv dap on start: '${ err } '` ) ;
168+ }
169+ if ( err ) {
170+ appendToDebugConsole ( `Error: ${ err } ` ) ;
171+ }
172+ } ) ;
139173 } ) ;
140- return p ;
141174}
142175
143176function parseProgramArgSync (
0 commit comments