@@ -161,17 +161,6 @@ AutoStartLauncher::AutoStartLauncher(const std::vector<std::string>& argv, std::
161
161
mShutdowner(std::move(shutdowner))
162
162
{
163
163
assert (!mArgv .empty ());
164
-
165
- // preventive check: at least one element (executable)
166
- if (!mArgv .empty ())
167
- {
168
- // launch loop thread
169
- startLaunchLoopThread ();
170
- }
171
- else
172
- {
173
- LOG_fatal << " AutoStartLauncher argv is empty" ;
174
- }
175
164
}
176
165
177
166
bool AutoStartLauncher::startUntilSuccess (Process& process)
@@ -201,11 +190,14 @@ bool AutoStartLauncher::startUntilSuccess(Process& process)
201
190
return false ;
202
191
}
203
192
204
- bool AutoStartLauncher::startLaunchLoopThread ()
193
+ bool AutoStartLauncher::start ()
205
194
{
206
- static const milliseconds maxBackoff (400 );
195
+ static const milliseconds maxBackoff (3000 );
207
196
static const milliseconds fastFailureThreshold (1000 );
208
197
198
+ if (mArgv .empty ())
199
+ return false ;
200
+
209
201
// There are permanent startup failure such as missing DLL. This is not likey to happen
210
202
// at customer's side as it will be installed properly. It is more likely during development
211
203
// and testing phases. We want to implement some backOff to reduce CPU usage if it does happen
@@ -222,7 +214,8 @@ bool AutoStartLauncher::startLaunchLoopThread()
222
214
// if less than threshhold, it fails right after startup.
223
215
if ((used < fastFailureThreshold) && !mShuttingDown )
224
216
{
225
- LOG_err << " process existed too fast: " << used.count () << " backoff" << backOff.count () << " ms" ;
217
+ // LOG_verbose << "process existed too fast: " << used.count() << " backoff "
218
+ // << backOff.count() << "ms";
226
219
mSleeper .sleep (backOff);
227
220
backOff = std::min (backOff * 2 , maxBackoff); // double it and maxBackoff at most
228
221
}
@@ -233,19 +226,25 @@ bool AutoStartLauncher::startLaunchLoopThread()
233
226
}
234
227
};
235
228
236
- auto launcher = [this , backoffForFastFailure]() {
229
+ auto launcher = [this , backoffForFastFailure]()
230
+ {
231
+ // Keep a copy, so the object is always live while the code is running
232
+ auto keepRef = shared_from_this ();
233
+
237
234
mThreadIsRunning = true ;
238
235
239
236
backoffForFastFailure ([this ](){
240
237
Process process;
241
238
if (startUntilSuccess (process))
242
239
{
243
240
bool ret = process.wait ();
244
- LOG_debug << " wait: " << ret
245
- << " hasSignal: " << process.hasTerminateBySignal ()
246
- << " " << (process.hasTerminateBySignal () ? std::to_string (process.getTerminatingSignal ()) : " " )
247
- << " hasExited: " << process.hasExited ()
248
- << " " << (process.hasExited () ? std::to_string (process.getExitCode ()) : " " );
241
+ LOG_verbose << " wait: " << ret << " hasSignal: " << process.hasTerminateBySignal ()
242
+ << " "
243
+ << (process.hasTerminateBySignal () ?
244
+ std::to_string (process.getTerminatingSignal ()) :
245
+ " " )
246
+ << " hasExited: " << process.hasExited () << " "
247
+ << (process.hasExited () ? std::to_string (process.getExitCode ()) : " " );
249
248
}
250
249
});
251
250
@@ -262,19 +261,33 @@ bool AutoStartLauncher::startLaunchLoopThread()
262
261
// is just starting. so we'll retry in the loop, but there is no reason it
263
262
// couldn't be shut down in 15 seconds
264
263
//
265
- void AutoStartLauncher::exitLaunchLoopThread ()
264
+ // @return true if thread exits, otherwise false
265
+ bool AutoStartLauncher::exitLaunchLoopThread ()
266
266
{
267
- milliseconds backOff (10 );
268
- while (mThreadIsRunning && backOff < 15s)
267
+ milliseconds interval{10 };
268
+ milliseconds totalWaitTime{0 };
269
+ while (mThreadIsRunning && totalWaitTime < 15s)
269
270
{
271
+ LOG_verbose << " interval " << interval.count () << " totalWaitTime "
272
+ << totalWaitTime.count ();
273
+
270
274
// shutdown the started process
271
275
if (mShutdowner ) mShutdowner ();
272
- std::this_thread::sleep_for (backOff);
273
- backOff += 10ms;
276
+
277
+ // wait
278
+ std::this_thread::sleep_for (interval);
279
+
280
+ // Update total wait time
281
+ totalWaitTime += interval;
282
+
283
+ // backoff
284
+ interval += 10ms;
274
285
}
286
+
287
+ return !mThreadIsRunning ;
275
288
}
276
289
277
- void AutoStartLauncher::shutDownOnce ()
290
+ void AutoStartLauncher::stop ()
278
291
{
279
292
bool wasShuttingdown = mShuttingDown .exchange (true );
280
293
if (wasShuttingdown)
@@ -287,17 +300,23 @@ void AutoStartLauncher::shutDownOnce()
287
300
// cancel sleeper, thread in sleep is woken up if it is
288
301
mSleeper .cancel ();
289
302
290
- exitLaunchLoopThread ();
291
- if (mThread .joinable ()) mThread .join ();
303
+ if (exitLaunchLoopThread ())
304
+ {
305
+ if (mThread .joinable ())
306
+ mThread .join ();
307
+ }
308
+ else
309
+ {
310
+ // Defensive: the thread doesn't exit, detach the thread
311
+ // We had such bug and it is usually a bug
312
+ assert (false && " AutoStartLauncher detaching loop thread" );
313
+ LOG_warn << " AutoStartLauncher detaching loop thread" ;
314
+ mThread .detach ();
315
+ }
292
316
293
317
LOG_info << " AutoStartLauncher is down" ;
294
318
}
295
319
296
- AutoStartLauncher::~AutoStartLauncher ()
297
- {
298
- shutDownOnce ();
299
- }
300
-
301
320
bool CancellableSleeper::sleep (const milliseconds& period)
302
321
{
303
322
std::unique_lock<std::mutex> l (mMutex );
@@ -345,12 +364,22 @@ std::vector<std::string> GfxIsolatedProcess::Params::toArgs() const
345
364
// We divide keepAliveInSeconds by three to set up mBeater so that it allows at least two
346
365
// beats within the keep-alive period.
347
366
GfxIsolatedProcess::GfxIsolatedProcess (const Params& params):
348
- mEndpointName (params.endpointName),
349
- mLauncher (params.toArgs(),
350
- [endpointName = params.endpointName]()
351
- {
352
- shutdown (endpointName);
353
- }),
354
- mBeater (seconds(params.keepAliveInSeconds / 3 ), params.endpointName)
355
- {}
367
+ mEndpointName{
368
+ params.endpointName
369
+ },
370
+ mLauncher {new AutoStartLauncher{params.toArgs (),
371
+ [endpointName = params.endpointName ]()
372
+ {
373
+ shutdown (endpointName);
374
+ }}},
375
+ mBeater {seconds (params.keepAliveInSeconds / 3 ), params.endpointName }
376
+ {
377
+ mLauncher ->start ();
356
378
}
379
+
380
+ GfxIsolatedProcess::~GfxIsolatedProcess ()
381
+ {
382
+ mLauncher ->stop ();
383
+ }
384
+
385
+ } // Namespace
0 commit comments