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 <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(); | |
|
alexeypa (please no reviews)
2012/09/06 18:21:10
nit: This is not thread safe. Consider using lazy
Jamie
2012/09/06 18:52:40
I've clarified that all calls to this function mus
| |
| 86 MessageLoopForIO* message_loop = MessageLoopForIO::current(); | |
| 87 int pipe_fd[2]; | |
| 88 int result = pipe(pipe_fd); | |
| 89 if (result < 0) { | |
| 90 LOG(ERROR) << "Could not create signal pipe: " << errno; | |
| 91 return false; | |
| 92 } | |
| 93 g_write_fd = pipe_fd[1]; | |
| 94 result = message_loop->WatchFileDescriptor( | |
| 95 pipe_fd[0], true, MessageLoopForIO::WATCH_READ, | |
| 96 &g_signal_listener->controller, g_signal_listener); | |
| 97 if (!result) { | |
|
alexeypa (please no reviews)
2012/09/06 18:21:10
nit: Is this a sign of something going very wrong?
Jamie
2012/09/06 18:52:40
TBH, I'm not sure under what circumstances it can
| |
| 98 delete g_signal_listener; | |
| 99 g_signal_listener = NULL; | |
|
alexeypa (please no reviews)
2012/09/06 18:21:10
nit: If WatchFileDescriptor() failed the first tim
Jamie
2012/09/06 18:52:40
Probably no point. I'll get rid of this clean-up c
| |
| 100 LOG(ERROR) << "Failed to create signal detector task."; | |
| 101 return false; | |
| 102 } | |
| 103 } | |
| 104 if (signal(signal_number, GlobalSignalHandler) == SIG_ERR) { | |
| 105 LOG(ERROR) << "signal() failed: " << errno; | |
| 106 return false; | |
| 107 } | |
| 108 g_signal_listener->AddSignalHandler(signal_number, handler); | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 } // namespace remoting | |
| OLD | NEW |