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