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/message_loop/message_loop.h" 17 #include "base/message_loop/message_pump_libevent.h" 18 #include "base/posix/eintr_wrapper.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 base::MessageLoopForIO* message_loop = base::MessageLoopForIO::current(); 95 result = 96 message_loop->WatchFileDescriptor(pipe_fd[0], 97 true, 98 base::MessageLoopForIO::WATCH_READ, 99 &g_signal_listener->controller, 100 g_signal_listener); 101 if (!result) { 102 LOG(ERROR) << "Failed to create signal detector task."; 103 close(pipe_fd[0]); 104 close(pipe_fd[1]); 105 return false; 106 } 107 g_write_fd = pipe_fd[1]; 108 } 109 if (signal(signal_number, GlobalSignalHandler) == SIG_ERR) { 110 LOG(ERROR) << "signal() failed: " << errno; 111 return false; 112 } 113 g_signal_listener->AddSignalHandler(signal_number, handler); 114 return true; 115 } 116 117 } // namespace remoting 118