Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // TODO(jamiewalch): Add unit tests for this. | |
| 6 | |
| 7 #include "remoting/host/posix/signal_handler.h" | |
| 8 | |
| 9 #include <list> | |
|
Lambros
2012/09/05 16:35:54
nit: C++ after C headers
And #include <utility> fo
Jamie
2012/09/05 21:15:38
Done.
| |
| 10 | |
| 11 #include <errno.h> | |
| 12 #include <signal.h> | |
| 13 | |
| 14 #include "base/compiler_specific.h" | |
| 15 #include "base/eintr_wrapper.h" | |
| 16 #include "base/message_loop.h" | |
| 17 #include "base/message_pump_libevent.h" | |
| 18 #include "base/threading/platform_thread.h" | |
| 19 | |
| 20 namespace remoting { | |
| 21 namespace { | |
| 22 | |
| 23 class SignalListener : public base::MessagePumpLibevent::Watcher { | |
| 24 public: | |
| 25 SignalListener(); | |
| 26 | |
| 27 void AddSignalHandler(int signal, const SignalHandler& handler); | |
| 28 | |
| 29 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; | |
| 30 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} | |
| 31 | |
| 32 // WatchFileDescriptor needs a controller through which the operation can be | |
| 33 // canceled. We don't use it, but this is as good a place as any to store it. | |
| 34 base::MessagePumpLibevent::FileDescriptorWatcher controller; | |
| 35 | |
| 36 private: | |
| 37 typedef std::pair<int, SignalHandler> SignalAndHandler; | |
| 38 typedef std::list<SignalAndHandler> SignalHandlers; | |
|
Lambros
2012/09/05 16:35:54
std::multimap would make the code slightly shorter
Jamie
2012/09/05 21:15:38
I think I'll stick with list. multimap is not wide
| |
| 39 SignalHandlers signal_handlers_; | |
| 40 }; | |
| 41 | |
| 42 SignalListener::SignalListener() { | |
| 43 } | |
| 44 | |
| 45 void SignalListener::AddSignalHandler(int signal, | |
| 46 const SignalHandler& handler) { | |
| 47 signal_handlers_.push_back(SignalAndHandler(signal, handler)); | |
| 48 } | |
| 49 | |
| 50 void SignalListener::OnFileCanReadWithoutBlocking(int fd) { | |
| 51 char buffer; | |
| 52 int result = HANDLE_EINTR(read(fd, &buffer, sizeof(buffer))); | |
| 53 if (result > 0) { | |
| 54 for (SignalHandlers::const_iterator i = signal_handlers_.begin(); | |
| 55 i != signal_handlers_.end(); | |
| 56 ++i) { | |
| 57 if (i->first == buffer) { | |
| 58 i->second.Run(i->first); | |
| 59 } | |
| 60 } | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 SignalListener* g_signal_listener = NULL; | |
| 65 int g_write_fd = 0; | |
| 66 | |
| 67 void GlobalSignalHandler(int signal) { | |
| 68 char byte = signal; | |
| 69 int r ALLOW_UNUSED = write(g_write_fd, &byte, 1); | |
| 70 } | |
| 71 | |
| 72 } // namespace | |
| 73 | |
| 74 // RegisterSignalHandler registers a signal handler that writes a byte to a | |
| 75 // pipe each time a signal is received. The read end of the pipe is registered | |
| 76 // with the current MessageLoop (which must be of type IO); whenever the pipe | |
| 77 // is readable, it invokes the specified callback. | |
| 78 // | |
| 79 // This arrangement is required because the set of system APIs that are safe to | |
| 80 // call from a signal handler is very limited (but does include write). | |
| 81 bool RegisterSignalHandler(int signum, const SignalHandler& handler) { | |
| 82 CHECK(signum < 256); // Don't want to worry about multi-byte writes. | |
| 83 if (!g_signal_listener) { | |
| 84 g_signal_listener = new SignalListener(); | |
| 85 MessageLoopForIO* message_loop = MessageLoopForIO::current(); | |
| 86 int pipefd[2]; | |
| 87 int result = pipe(pipefd); | |
| 88 if (result < 0) { | |
| 89 LOG(ERROR) << "Could not create signal pipe: " << errno; | |
| 90 return false; | |
| 91 } | |
| 92 g_write_fd = pipefd[1]; | |
| 93 result = message_loop->WatchFileDescriptor( | |
| 94 pipefd[0], true, MessageLoopForIO::WATCH_READ, | |
| 95 &g_signal_listener->controller, g_signal_listener); | |
| 96 if (!result) { | |
| 97 delete g_signal_listener; | |
| 98 g_signal_listener = NULL; | |
| 99 LOG(ERROR) << "Failed to create signal detector task."; | |
| 100 return false; | |
| 101 } | |
| 102 } | |
| 103 if (signal(signum, GlobalSignalHandler) == SIG_ERR) { | |
| 104 LOG(ERROR) << "signal() failed: " << errno; | |
| 105 return false; | |
| 106 } | |
| 107 g_signal_listener->AddSignalHandler(signum, handler); | |
| 108 return true; | |
| 109 } | |
| 110 | |
| 111 } // namespace remoting | |
| OLD | NEW |