shill: vpn: Implement a ProcessKiller singleton.

This class may be used to terminate and reap child processes
asynchronously and robustly. Also:

- Use ProcessKiller to kill spawned "openvpn" and "l2tpipsec_vpn"
  processes.

- Delete the associated OpenVPN tunnel interfaces cleanly after the
  openvpn process dies.

- Fix a somewhat harmless bug where shill was sending SIGTERM to
  already dead VPN processes from child watch callbacks.

BUG=chromium-os:31535,chromium-os:31571
TEST=unit tests, tested on device

Change-Id: If15f08e76c51dac33a434551ef4ba11ca66d0401
Reviewed-on: https://gerrit.chromium.org/gerrit/24610
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
diff --git a/process_killer.cc b/process_killer.cc
new file mode 100644
index 0000000..4e1383e
--- /dev/null
+++ b/process_killer.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/process_killer.h"
+
+using base::Closure;
+using std::map;
+
+namespace shill {
+
+namespace {
+
+base::LazyInstance<ProcessKiller> g_process_killer = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+ProcessKiller::ProcessKiller() {}
+
+ProcessKiller::~ProcessKiller() {
+  // There's no need to release any GLib child watch sources because this class
+  // is a singleton and will be destroyed when this process exits, i.e., when
+  // GLib is shut down.
+}
+
+// static
+ProcessKiller *ProcessKiller::GetInstance() {
+  return g_process_killer.Pointer();
+}
+
+void ProcessKiller::Kill(int pid, const Closure &callback) {
+  LOG(INFO) << "Killing pid " << pid;
+  if (!callback.is_null()) {
+    callbacks_[pid] = callback;
+  }
+  g_child_watch_add(pid, OnProcessDied, this);
+  // TODO(petkov): Consider sending subsequent periodic signals and raising the
+  // signal to SIGKILL if the process keeps running.
+  kill(pid, SIGTERM);
+}
+
+// static
+void ProcessKiller::OnProcessDied(GPid pid, gint status, gpointer data) {
+  LOG(INFO) << "pid " << pid << " died, status " << status;
+  ProcessKiller *me = reinterpret_cast<ProcessKiller *>(data);
+  map<int, Closure>::iterator callback_it = me->callbacks_.find(pid);
+  if (callback_it == me->callbacks_.end()) {
+    return;
+  }
+  const Closure &callback = callback_it->second;
+  if (!callback.is_null()) {
+    LOG(INFO) << "Running callback for dead pid " << pid;
+    callback.Run();
+  }
+  me->callbacks_.erase(callback_it);
+}
+
+}  // namespace shill