| 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 <errno.h> |
| 10 #include <signal.h> |
| 11 |
| 12 #include <list> |
| 13 #include <utility> |
| 14 |
| 15 #include "base/compiler_specific.h" |
| 16 #include "base/eintr_wrapper.h" |
| 17 #include "base/message_loop.h" |
| 18 #include "base/message_pump_libevent.h" |
| 19 #include "base/threading/platform_thread.h" |
| 20 |
| 21 namespace remoting { |
| 22 namespace { |
| 23 |
| 24 class SignalListener : public base::MessagePumpLibevent::Watcher { |
| 25 public: |
| 26 SignalListener(); |
| 27 |
| 28 void AddSignalHandler(int signal, const SignalHandler& handler); |
| 29 |
| 30 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; |
| 31 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} |
| 32 |
| 33 // WatchFileDescriptor needs a controller through which the operation can be |
| 34 // canceled. We don't use it, but this is as good a place as any to store it. |
| 35 base::MessagePumpLibevent::FileDescriptorWatcher controller; |
| 36 |
| 37 private: |
| 38 typedef std::pair<int, SignalHandler> SignalAndHandler; |
| 39 typedef std::list<SignalAndHandler> SignalHandlers; |
| 40 SignalHandlers signal_handlers_; |
| 41 }; |
| 42 |
| 43 SignalListener::SignalListener() { |
| 44 } |
| 45 |
| 46 void SignalListener::AddSignalHandler(int signal, |
| 47 const SignalHandler& handler) { |
| 48 signal_handlers_.push_back(SignalAndHandler(signal, handler)); |
| 49 } |
| 50 |
| 51 void SignalListener::OnFileCanReadWithoutBlocking(int fd) { |
| 52 char buffer; |
| 53 int result = HANDLE_EINTR(read(fd, &buffer, sizeof(buffer))); |
| 54 if (result > 0) { |
| 55 for (SignalHandlers::const_iterator i = signal_handlers_.begin(); |
| 56 i != signal_handlers_.end(); |
| 57 ++i) { |
| 58 if (i->first == buffer) { |
| 59 i->second.Run(i->first); |
| 60 } |
| 61 } |
| 62 } |
| 63 } |
| 64 |
| 65 SignalListener* g_signal_listener = NULL; |
| 66 int g_write_fd = 0; |
| 67 |
| 68 void GlobalSignalHandler(int signal) { |
| 69 char byte = signal; |
| 70 int r ALLOW_UNUSED = write(g_write_fd, &byte, 1); |
| 71 } |
| 72 |
| 73 } // namespace |
| 74 |
| 75 // RegisterSignalHandler registers a signal handler that writes a byte to a |
| 76 // pipe each time a signal is received. The read end of the pipe is registered |
| 77 // with the current MessageLoop (which must be of type IO); whenever the pipe |
| 78 // is readable, it invokes the specified callback. |
| 79 // |
| 80 // This arrangement is required because the set of system APIs that are safe to |
| 81 // call from a signal handler is very limited (but does include write). |
| 82 bool RegisterSignalHandler(int signal_number, const SignalHandler& handler) { |
| 83 CHECK(signal_number < 256); // Don't want to worry about multi-byte writes. |
| 84 if (!g_signal_listener) { |
| 85 g_signal_listener = new SignalListener(); |
| 86 } |
| 87 if (!g_write_fd) { |
| 88 int pipe_fd[2]; |
| 89 int result = pipe(pipe_fd); |
| 90 if (result < 0) { |
| 91 LOG(ERROR) << "Could not create signal pipe: " << errno; |
| 92 return false; |
| 93 } |
| 94 MessageLoopForIO* message_loop = MessageLoopForIO::current(); |
| 95 result = message_loop->WatchFileDescriptor( |
| 96 pipe_fd[0], true, MessageLoopForIO::WATCH_READ, |
| 97 &g_signal_listener->controller, g_signal_listener); |
| 98 if (!result) { |
| 99 LOG(ERROR) << "Failed to create signal detector task."; |
| 100 close(pipe_fd[0]); |
| 101 close(pipe_fd[1]); |
| 102 return false; |
| 103 } |
| 104 g_write_fd = pipe_fd[1]; |
| 105 } |
| 106 if (signal(signal_number, GlobalSignalHandler) == SIG_ERR) { |
| 107 LOG(ERROR) << "signal() failed: " << errno; |
| 108 return false; |
| 109 } |
| 110 g_signal_listener->AddSignalHandler(signal_number, handler); |
| 111 return true; |
| 112 } |
| 113 |
| 114 } // namespace remoting |
| OLD | NEW |