aboutsummaryrefslogtreecommitdiff
path: root/chromeos/asynchronous_signal_handler.h
blob: 8da4a993eefad2311184ea36879b3b396bdd4b60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef LIBCHROMEOS_CHROMEOS_ASYNCHRONOUS_SIGNAL_HANDLER_H_
#define LIBCHROMEOS_CHROMEOS_ASYNCHRONOUS_SIGNAL_HANDLER_H_

#include <signal.h>
#include <sys/signalfd.h>

#include <map>

#include <base/callback.h>
#include <base/compiler_specific.h>
#include <base/macros.h>
#include <base/memory/scoped_ptr.h>
#include <base/message_loop/message_loop.h>
#include <chromeos/chromeos_export.h>

namespace chromeos {
// Sets up signal handlers for registered signals, and converts signal receipt
// into a write on a pipe. Watches that pipe for data and, when some appears,
// execute the associated callback.
class CHROMEOS_EXPORT AsynchronousSignalHandler
    : public base::MessageLoopForIO::Watcher {
 public:
  AsynchronousSignalHandler();
  ~AsynchronousSignalHandler() override;

  // The callback called when a signal is received.
  typedef base::Callback<bool(const struct signalfd_siginfo&)> SignalHandler;

  // Initialize the handler.
  void Init();

  // Register a new handler for the given |signal|, replacing any previously
  // registered handler. |callback| will be called on the thread the
  // |AsynchronousSignalHandler| is bound to when a signal is received. The
  // received |signalfd_siginfo| will be passed to |callback|. |callback| must
  // returns |true| if the signal handler must be unregistered, and |false|
  // otherwise. Due to an implementation detail, you cannot set any sigaction
  // flags you might be accustomed to using. This might matter if you hoped to
  // use SA_NOCLDSTOP to avoid getting a SIGCHLD when a child process receives a
  // SIGSTOP.
  void RegisterHandler(int signal, const SignalHandler& callback);

  // Unregister a previously registered handler for the given |signal|.
  void UnregisterHandler(int signal);

  // Implementation of base::MessageLoopForIO::Watcher
  void OnFileCanReadWithoutBlocking(int fd) override;
  void OnFileCanWriteWithoutBlocking(int fd) override;

 private:
  // Controller used to manage watching of signalling pipe.
  scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> fd_watcher_;

  // The registered callbacks.
  typedef std::map<int, SignalHandler> Callbacks;
  Callbacks registered_callbacks_;

  // File descriptor for accepting signals indicated by |signal_mask_|.
  int descriptor_;

  // A set of signals to be handled after the dispatcher is running.
  sigset_t signal_mask_;

  // A copy of the signal mask before the dispatcher starts, which will be
  // used to restore to the original state when the dispatcher stops.
  sigset_t saved_signal_mask_;

  // Resets the given signal to its default behavior. Doesn't touch
  // |registered_callbacks_|.
  CHROMEOS_PRIVATE void ResetSignal(int signal);

  // Updates the set of signals that this handler listens to.
  CHROMEOS_PRIVATE void UpdateSignals();

  DISALLOW_COPY_AND_ASSIGN(AsynchronousSignalHandler);
};

}  // namespace chromeos

#endif  // LIBCHROMEOS_CHROMEOS_ASYNCHRONOUS_SIGNAL_HANDLER_H_