Chromium Code Reviews| Index: remoting/host/win/worker_process_launcher.cc | 
| diff --git a/remoting/host/win/worker_process_launcher.cc b/remoting/host/win/worker_process_launcher.cc | 
| index 6ca563cf8939e86084b4f42474b1eae250510f3b..c2ea19e46e23cb01cdd0878c9405d53f4bfa33d0 100644 | 
| --- a/remoting/host/win/worker_process_launcher.cc | 
| +++ b/remoting/host/win/worker_process_launcher.cc | 
| @@ -4,6 +4,7 @@ | 
| #include "remoting/host/win/worker_process_launcher.h" | 
| +#include "base/location.h" | 
| #include "base/logging.h" | 
| #include "base/single_thread_task_runner.h" | 
| #include "base/time.h" | 
| @@ -13,6 +14,7 @@ | 
| #include "ipc/ipc_listener.h" | 
| #include "ipc/ipc_message.h" | 
| #include "net/base/backoff_entry.h" | 
| +#include "remoting/host/chromoting_messages.h" | 
| #include "remoting/host/worker_process_ipc_delegate.h" | 
| using base::TimeDelta; | 
| @@ -44,6 +46,7 @@ const net::BackoffEntry::Policy kDefaultBackoffPolicy = { | 
| false, | 
| }; | 
| +const int kDelayTimeoutSeconds = 5; | 
| 
 
Wez
2013/03/07 01:54:35
nit: Naming.  e.g. kCrashRequestTimeoutSeconds?
 
Wez
2013/03/07 01:54:35
5s is probably too short for many systems, BTW.
 
alexeypa (please no reviews)
2013/03/07 21:28:30
Done.
 
alexeypa (please no reviews)
2013/03/07 21:28:30
It is enough because the timeout is, strictly spea
 
Wez
2013/03/08 01:45:15
Right, but if the timeout is short then on slower,
 
 | 
| namespace remoting { | 
| @@ -52,7 +55,7 @@ namespace remoting { | 
| // method. In case of error the channel is closed and the worker process is | 
| // terminated. | 
| class WorkerProcessLauncher::Core | 
| - : public base::RefCountedThreadSafe<WorkerProcessLauncher::Core>, | 
| + : public base::RefCountedThreadSafe<Core, Core>, | 
| public base::win::ObjectWatcher::Delegate, | 
| public IPC::Listener { | 
| public: | 
| @@ -75,9 +78,10 @@ class WorkerProcessLauncher::Core | 
| // to |this| as soon as Stop() returns. | 
| void Stop(); | 
| - // Sends an IPC message to the worker process. The message will be silently | 
| - // dropped if Send() is called before Start() or after stutdown has been | 
| - // initiated. | 
| + // See WorkerProcessLauncher::Crash(). | 
| + void Crash(const tracked_objects::Location& location); | 
| + | 
| + // See WorkerProcessLauncher::Send(). | 
| void Send(IPC::Message* message); | 
| // base::win::ObjectWatcher::Delegate implementation. | 
| @@ -88,8 +92,13 @@ class WorkerProcessLauncher::Core | 
| virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; | 
| virtual void OnChannelError() OVERRIDE; | 
| + // Destroys |Core| instances on the |caller_task_runner_| thread. This is | 
| + // needed because base::OneShotTimer instances must be destroyed on the same | 
| + // thread they were created on. | 
| + static void Destruct(const Core* core); | 
| 
 
Wez
2013/03/07 01:54:35
We use an explicit separate struct e.g. CoreTraits
 
alexeypa (please no reviews)
2013/03/07 21:28:30
WorkerProcessLauncher::Core is a private class dec
 
Wez
2013/03/08 01:45:15
Surely the friend declaration would be in the Core
 
alexeypa (please no reviews)
2013/03/08 17:43:19
No, there will be one in WorkerProcessLauncher and
 
 | 
| + | 
| private: | 
| - friend class base::RefCountedThreadSafe<Core>; | 
| + friend class base::DeleteHelper<Core>; | 
| virtual ~Core(); | 
| // Attempts to launch the worker process. Schedules next launch attempt if | 
| @@ -116,21 +125,21 @@ class WorkerProcessLauncher::Core | 
| typedef BOOL (WINAPI * GetNamedPipeClientProcessIdFn)(HANDLE, DWORD*); | 
| GetNamedPipeClientProcessIdFn get_named_pipe_client_pid_; | 
| + // The timer used to delay termination of the worker process when an IPC error | 
| + // occured or when Crash() request is pending | 
| + base::OneShotTimer<Core> delay_timer_; | 
| 
 
Wez
2013/03/07 01:54:35
nit: Naming.
 
alexeypa (please no reviews)
2013/03/07 21:28:30
Done.
 
 | 
| + | 
| // True if IPC messages should be passed to |worker_delegate_|. | 
| bool ipc_enabled_; | 
| - // The timer used to delay termination of the process in the case of an IPC | 
| - // error. | 
| - scoped_ptr<base::OneShotTimer<Core> > ipc_error_timer_; | 
| - | 
| // Launch backoff state. | 
| net::BackoffEntry launch_backoff_; | 
| // Timer used to delay recording a successfull launch. | 
| - scoped_ptr<base::OneShotTimer<Core> > launch_success_timer_; | 
| + base::OneShotTimer<Core> launch_success_timer_; | 
| // Timer used to schedule the next attempt to launch the process. | 
| - scoped_ptr<base::OneShotTimer<Core> > launch_timer_; | 
| + base::OneShotTimer<Core> launch_timer_; | 
| // Used to determine when the launched process terminates. | 
| base::win::ObjectWatcher process_watcher_; | 
| @@ -160,11 +169,6 @@ WorkerProcessLauncher::Core::Core( | 
| launch_backoff_(&kDefaultBackoffPolicy), | 
| stopping_(false) { | 
| DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 
| - | 
| - // base::OneShotTimer must be destroyed on the same thread it was created on. | 
| - ipc_error_timer_.reset(new base::OneShotTimer<Core>()); | 
| - launch_success_timer_.reset(new base::OneShotTimer<Core>()); | 
| - launch_timer_.reset(new base::OneShotTimer<Core>()); | 
| } | 
| void WorkerProcessLauncher::Core::Start() { | 
| @@ -184,6 +188,29 @@ void WorkerProcessLauncher::Core::Stop() { | 
| } | 
| } | 
| +void WorkerProcessLauncher::Core::Crash( | 
| + const tracked_objects::Location& location) { | 
| + DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 
| + | 
| + // Ask the worker process to crash voluntarily if it is still connected. | 
| + if (ipc_enabled_) { | 
| + Send(new ChromotingDaemonMsg_Crash(location.function_name(), | 
| + location.file_name(), | 
| + location.line_number())); | 
| + } | 
| + | 
| + // Close the channel and ignore any not yet processed messages. | 
| + launcher_delegate_->CloseChannel(); | 
| + ipc_enabled_ = false; | 
| + | 
| + // Give the worker process some time to crash. | 
| + if (!delay_timer_.IsRunning()) { | 
| + delay_timer_.Start(FROM_HERE, | 
| + base::TimeDelta::FromSeconds(kDelayTimeoutSeconds), this, | 
| + &Core::StopWorker); | 
| 
 
Wez
2013/03/07 01:54:35
StopWorker "stops the worker asynchronously". Is i
 
alexeypa (please no reviews)
2013/03/07 21:28:30
It is tougher than Chuck Norris (as long as we are
 
 | 
| + } | 
| +} | 
| + | 
| void WorkerProcessLauncher::Core::Send(IPC::Message* message) { | 
| DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 
| @@ -241,19 +268,28 @@ void WorkerProcessLauncher::Core::OnChannelError() { | 
| // here allows the worker to exit completely and so, notify | 
| // |process_watcher_|. As the result KillProcess() will not be called and | 
| // the original exit code reported by the worker process will be retrieved. | 
| - ipc_error_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(5), | 
| - this, &Core::StopWorker); | 
| + if (!delay_timer_.IsRunning()) { | 
| + delay_timer_.Start(FROM_HERE, | 
| + base::TimeDelta::FromSeconds(kDelayTimeoutSeconds), this, | 
| + &Core::StopWorker); | 
| + } | 
| +} | 
| + | 
| +// static | 
| +void WorkerProcessLauncher::Core::Destruct(const Core* core) { | 
| + core->caller_task_runner_->DeleteSoon(FROM_HERE, core); | 
| } | 
| WorkerProcessLauncher::Core::~Core() { | 
| + DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 
| DCHECK(stopping_); | 
| } | 
| void WorkerProcessLauncher::Core::LaunchWorker() { | 
| DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 
| DCHECK(!ipc_enabled_); | 
| - DCHECK(!launch_success_timer_->IsRunning()); | 
| - DCHECK(!launch_timer_->IsRunning()); | 
| + DCHECK(!launch_success_timer_.IsRunning()); | 
| + DCHECK(!launch_timer_.IsRunning()); | 
| DCHECK(!process_exit_event_.IsValid()); | 
| DCHECK(process_watcher_.GetWatchedObject() == NULL); | 
| @@ -264,8 +300,8 @@ void WorkerProcessLauncher::Core::LaunchWorker() { | 
| ipc_enabled_ = true; | 
| // Record a successful launch once the process has been running for at | 
| // least two seconds. | 
| - launch_success_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(2), | 
| - this, &Core::RecordSuccessfulLaunch); | 
| + launch_success_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(2), | 
| + this, &Core::RecordSuccessfulLaunch); | 
| return; | 
| } | 
| @@ -289,8 +325,8 @@ void WorkerProcessLauncher::Core::StopWorker() { | 
| scoped_refptr<Core> self = this; | 
| // Record a launch failure if the process exited too soon. | 
| - if (launch_success_timer_->IsRunning()) { | 
| - launch_success_timer_->Stop(); | 
| + if (launch_success_timer_.IsRunning()) { | 
| + launch_success_timer_.Stop(); | 
| launch_backoff_.InformOfRequest(false); | 
| } | 
| @@ -310,23 +346,20 @@ void WorkerProcessLauncher::Core::StopWorker() { | 
| process_watcher_.StopWatching(); | 
| } | 
| - ipc_error_timer_->Stop(); | 
| + delay_timer_.Stop(); | 
| process_exit_event_.Close(); | 
| // Do not relaunch the worker process if the caller has asked us to stop. | 
| - if (stopping_) { | 
| - ipc_error_timer_.reset(); | 
| - launch_timer_.reset(); | 
| + if (stopping_) | 
| return; | 
| - } | 
| if (launcher_delegate_->IsPermanentError(launch_backoff_.failure_count())) { | 
| if (!stopping_) | 
| worker_delegate_->OnPermanentError(); | 
| } else { | 
| // Schedule the next attempt to launch the worker process. | 
| - launch_timer_->Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(), | 
| - this, &Core::LaunchWorker); | 
| + launch_timer_.Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(), this, | 
| + &Core::LaunchWorker); | 
| } | 
| } | 
| @@ -344,6 +377,10 @@ WorkerProcessLauncher::~WorkerProcessLauncher() { | 
| core_ = NULL; | 
| } | 
| +void WorkerProcessLauncher::Crash(const tracked_objects::Location& location) { | 
| + core_->Crash(location); | 
| +} | 
| + | 
| void WorkerProcessLauncher::Send(IPC::Message* message) { | 
| core_->Send(message); | 
| } |