57
57
catch(std::exception const& e)
59
cerr << "RegistryObject::~RegistryObject: " << e.what() << endl;
63
// wait for scope processes to terminate
64
for (auto& scope_process : scope_processes_)
66
if (!scope_process.second.wait_for_state(ScopeProcess::Stopped, 1000))
68
cerr << "RegistryObject::~RegistryObject: Scope: \"" << scope_process.second.scope_id()
69
<< "\" is taking longer than expected to terminate (This process is likely to close upon"
70
<< " termination of the parent application)." << endl;
59
cerr << "RegistryObject::~RegistryObject(): " << e.what() << endl;
131
120
// If the id is empty, it was sent as empty by the remote client.
132
121
if (scope_id.empty())
134
throw unity::InvalidArgumentException("Registry: Cannot locate scope with empty id");
123
throw unity::InvalidArgumentException("Registry::locate(): Cannot locate scope with empty id");
137
126
auto scope_it = scopes_.find(scope_id);
138
127
if (scope_it == scopes_.end())
140
throw NotFoundException("Tried to locate unknown local scope", scope_id);
129
throw NotFoundException("Registry::locate(): Tried to locate unknown local scope", scope_id);
143
132
auto proc_it = scope_processes_.find(scope_id);
144
133
if (proc_it == scope_processes_.end())
146
throw NotFoundException("Tried to exec unknown local scope", scope_id);
135
throw NotFoundException("Registry::locate(): Tried to exec unknown local scope", scope_id);
149
138
proc_it->second.exec();
163
152
if (scope_id.find('/') != std::string::npos)
165
throw unity::InvalidArgumentException("Registry: Cannot create a scope with a slash in its id");
154
throw unity::InvalidArgumentException("RegistryObject::add_local_scope(): Cannot create a scope with '/' in its id");
168
157
if (scopes_.find(scope_id) != scopes_.end())
224
213
return exec_data_.scope_id;
227
RegistryObject::ScopeProcess::ProcessState RegistryObject::ScopeProcess::state() const
229
std::lock_guard<std::mutex> lock(state_mutex_);
233
216
bool RegistryObject::ScopeProcess::wait_for_state(ProcessState state, int timeout_ms) const
235
std::unique_lock<std::mutex> lock(state_mutex_);
237
// keep track of time left as process can undergo multiple state changes
238
// before reaching the state we want
239
int time_left = timeout_ms;
240
while (state_ != state && time_left > 0)
242
auto start = std::chrono::high_resolution_clock::now();
243
state_change_cond_.wait_for(lock, std::chrono::milliseconds(time_left));
246
time_left -= std::chrono::duration_cast<std::chrono::milliseconds>(
247
std::chrono::high_resolution_clock::now() - start).count();
250
return state_ == state;
218
std::unique_lock<std::mutex> lock(process_mutex_);
219
return in_lock_wait_for_state(lock, state, timeout_ms);
253
222
void RegistryObject::ScopeProcess::exec()
224
std::unique_lock<std::mutex> lock(process_mutex_);
255
226
// 1. check if the scope is running.
256
227
// 1.1. if scope already running, return.
257
if (state() == ScopeProcess::Running)
228
if (state_ == ScopeProcess::Running)
261
232
// 1.2. if scope running but is “stopping”, wait for it to stop / kill it.
262
else if (state() == ScopeProcess::Stopping)
233
else if (state_ == ScopeProcess::Stopping)
264
if (!wait_for_state(ScopeProcess::Stopped, 1000))
235
if (!in_lock_wait_for_state(lock, ScopeProcess::Stopped, 1000))
266
cerr << "RegistryObject::ScopeProcess: Force killing process. Scope: \"" << exec_data_.scope_id
267
<< "\" took too long to stop." << endl;
237
cerr << "RegistryObject::ScopeProcess::exec(): Force killing process. Scope: \""
238
<< exec_data_.scope_id << "\" took too long to stop." << endl;
272
243
// 2. exec the scope.
273
update_state(Starting);
244
in_lock_update_state(Starting);
275
246
const std::string program{exec_data_.scoperunner_path};
276
247
const std::vector<std::string> argv = {exec_data_.runtime_config, exec_data_.scope_config};
285
std::lock_guard<std::mutex> lock(process_mutex_);
286
256
process_ = core::posix::exec(program, argv, env, core::posix::StandardStream::empty);
287
257
if (process_.pid() <= 0)
289
259
process_ = core::posix::ChildProcess::invalid();
290
update_state(Stopped);
291
throw unity::ResourceException("RegistryObject::ScopeProcess: Failed to exec scope via command: \"" +
292
exec_data_.scoperunner_path + " " + exec_data_.runtime_config + " " +
293
exec_data_.scope_config + "\"");
260
in_lock_update_state(Stopped);
261
throw unity::ResourceException("RegistryObject::ScopeProcess::exec(): Failed to exec scope via command: \""
262
+ exec_data_.scoperunner_path + " " + exec_data_.runtime_config + " "
263
+ exec_data_.scope_config + "\"");
297
267
///! TODO: This should not be here. A ready signal from the scope should trigger "running".
298
update_state(Running);
268
in_lock_update_state(Running);
300
270
// 3. wait for scope to be "running".
301
271
// 3.1. when ready, return.
302
272
// 3.2. OR if timeout, kill process and throw.
303
if (!wait_for_state(ScopeProcess::Running, 1000))
273
if (!in_lock_wait_for_state(lock, ScopeProcess::Running, 1000))
306
throw unity::ResourceException("RegistryObject::ScopeProcess: exec() aborted. Scope: \""
276
throw unity::ResourceException("RegistryObject::ScopeProcess::exec(): exec aborted. Scope: \""
307
277
+ exec_data_.scope_id + "\" took too long to start.");
316
286
void RegistryObject::ScopeProcess::kill()
318
// if scope already stopped, return.
319
if (state() == ScopeProcess::Stopped)
326
std::lock_guard<std::mutex> lock(process_mutex_);
327
process_.send_signal_or_throw(core::posix::Signal::sig_kill);
329
catch (std::exception const&)
331
cerr << "RegistryObject::ScopeProcess: Failed to kill scope: \""
332
<< exec_data_.scope_id << "\"" << endl;
288
std::unique_lock<std::mutex> lock(process_mutex_);
337
292
bool RegistryObject::ScopeProcess::on_process_death(pid_t pid)
341
296
// check if this is the process reported to have died
342
297
if (pid == process_.pid())
344
cout << "RegistryObject::ScopeProcess: Process for scope: \"" << exec_data_.scope_id << "\" terminated" << endl;
299
cout << "RegistryObject::ScopeProcess::on_process_death(): Process for scope: \"" << exec_data_.scope_id
300
<< "\" terminated" << endl;
345
301
process_ = core::posix::ChildProcess::invalid();
346
update_state(Stopped);
302
in_lock_update_state(Stopped);
353
void RegistryObject::ScopeProcess::update_state(ProcessState state)
309
void RegistryObject::ScopeProcess::in_lock_update_state(ProcessState state)
355
std::lock_guard<std::mutex> lock(state_mutex_);
357
312
state_change_cond_.notify_all();
315
bool RegistryObject::ScopeProcess::in_lock_wait_for_state(std::unique_lock<std::mutex>& lock,
316
ProcessState state, int timeout_ms) const
318
// keep track of time left as process can undergo multiple state changes
319
// before reaching the state we want
320
int time_left = timeout_ms;
321
while (state_ != state && time_left > 0)
323
auto start = std::chrono::high_resolution_clock::now();
324
state_change_cond_.wait_for(lock, std::chrono::milliseconds(time_left));
327
time_left -= std::chrono::duration_cast<std::chrono::milliseconds>(
328
std::chrono::high_resolution_clock::now() - start).count();
331
return state_ == state;
334
void RegistryObject::ScopeProcess::in_lock_kill(std::unique_lock<std::mutex>& lock)
336
if (state_ == Stopped)
343
process_.send_signal_or_throw(core::posix::Signal::sig_kill);
345
if (!in_lock_wait_for_state(lock, ScopeProcess::Stopped, 1000))
347
throw unity::ResourceException("Scope: \"" + exec_data_.scope_id
348
+ "\" is taking longer than expected to terminate (This process is "
349
+ "likely to close upon termination of the parent application).");
352
catch (std::exception const&)
354
cerr << "RegistryObject::ScopeProcess::in_lock_kill(): Failed to kill scope: \""
355
<< exec_data_.scope_id << "\"" << endl;
360
360
} // namespace internal
362
362
} // namespace scopes