Revision b14b975f

b/lib/daemon.py
34 34

  
35 35
  """
36 36
  def __init__(self):
37
    self._io_wait = []
37
    """Constructs a new Mainloop instance.
38

  
39
    """
40
    self._io_wait = {}
41
    self._io_wait_add = []
42
    self._io_wait_remove = []
38 43
    self._signal_wait = []
39
    self.sigchld_handler = None
40
    self.sigterm_handler = None
41
    self.quit = False
42 44

  
43
  def Run(self):
44
    # TODO: Does not yet support adding new event sources while running
45
  def Run(self, handle_sigchld=True, handle_sigterm=True, stop_on_empty=False):
46
    """Runs the mainloop.
47

  
48
    @type handle_sigchld: bool
49
    @param handle_sigchld: Whether to install handler for SIGCHLD
50
    @type handle_sigterm: bool
51
    @param handle_sigterm: Whether to install handler for SIGTERM
52
    @type stop_on_empty: bool
53
    @param stop_on_empty: Whether to stop mainloop once all I/O waiters
54
                          unregistered
55

  
56
    """
45 57
    poller = select.poll()
46
    for (owner, fd, conditions) in self._io_wait:
47
      poller.register(fd, conditions)
48 58

  
49
    self.sigchld_handler = utils.SignalHandler([signal.SIGCHLD])
50
    self.sigterm_handler = utils.SignalHandler([signal.SIGTERM])
59
    # Setup signal handlers
60
    if handle_sigchld:
61
      sigchld_handler = utils.SignalHandler([signal.SIGCHLD])
62
    else:
63
      sigchld_handler = None
51 64
    try:
52
      while not self.quit:
53
        try:
54
          io_events = poller.poll()
55
        except select.error, err:
56
          # EINTR can happen when signals are sent
57
          if err.args and err.args[0] in (errno.EINTR,):
58
            io_events = None
59
          else:
60
            raise
61

  
62
        if io_events:
63
          # Check for I/O events
64
          for (evfd, evcond) in io_events:
65
            for (owner, fd, conditions) in self._io_wait:
66
              if fd == evfd and evcond & conditions:
67
                owner.OnIO(fd, evcond)
68

  
69
        # Check whether signal was raised
70
        if self.sigchld_handler.called:
71
          for owner in self._signal_wait:
72
            owner.OnSignal(signal.SIGCHLD)
73
          self.sigchld_handler.Clear()
74

  
75
        if self.sigterm_handler.called:
76
          self.quit = True
77
          self.sigterm_handler.Clear()
65
      if handle_sigterm:
66
        sigterm_handler = utils.SignalHandler([signal.SIGTERM])
67
      else:
68
        sigterm_handler = None
69

  
70
      try:
71
        running = True
72

  
73
        # Start actual main loop
74
        while running:
75
          # Entries could be added again afterwards, hence removing first
76
          if self._io_wait_remove:
77
            for fd in self._io_wait_remove:
78
              try:
79
                poller.unregister(fd)
80
              except KeyError:
81
                pass
82
              try:
83
                del self._io_wait[fd]
84
              except KeyError:
85
                pass
86
            self._io_wait_remove = []
87

  
88
          # Add new entries
89
          if self._io_wait_add:
90
            for (owner, fd, conditions) in self._io_wait_add:
91
              self._io_wait[fd] = owner
92
              poller.register(fd, conditions)
93
            self._io_wait_add = []
94

  
95
          # Stop if nothing is listening anymore
96
          if stop_on_empty and not self._io_wait:
97
            break
98

  
99
          # Wait for I/O events
100
          try:
101
            io_events = poller.poll()
102
          except select.error, err:
103
            # EINTR can happen when signals are sent
104
            if err.args and err.args[0] in (errno.EINTR,):
105
              io_events = None
106
            else:
107
              raise
108

  
109
          if io_events:
110
            # Check for I/O events
111
            for (evfd, evcond) in io_events:
112
              owner = self._io_wait.get(evfd, None)
113
              if owner:
114
                owner.OnIO(evfd, evcond)
115

  
116
          # Check whether signal was raised
117
          if sigchld_handler and sigchld_handler.called:
118
            self._CallSignalWaiters(signal.SIGCHLD)
119
            sigchld_handler.Clear()
120

  
121
          if sigterm_handler and sigterm_handler.called:
122
            self._CallSignalWaiters(signal.SIGTERM)
123
            running = False
124
            sigterm_handler.Clear()
125
      finally:
126
        # Restore signal handlers
127
        if sigterm_handler:
128
          sigterm_handler.Reset()
78 129
    finally:
79
      self.sigchld_handler.Reset()
80
      self.sigchld_handler = None
81
      self.sigterm_handler.Reset()
82
      self.sigterm_handler = None
130
      if sigchld_handler:
131
        sigchld_handler.Reset()
83 132

  
133
  def _CallSignalWaiters(self, signum):
134
    """Calls all signal waiters for a certain signal.
135

  
136
    @type signum: int
137
    @param signum: Signal number
138

  
139
    """
140
    for owner in self._signal_wait:
141
      owner.OnSignal(signal.SIGCHLD)
84 142

  
85 143
  def RegisterIO(self, owner, fd, condition):
86 144
    """Registers a receiver for I/O notifications
......
96 154
                      (see select module)
97 155

  
98 156
    """
99
    self._io_wait.append((owner, fd, condition))
157
    # select.Poller also supports file() like objects, but we don't.
158
    assert isinstance(fd, (int, long)), \
159
      "Only integers are supported for file descriptors"
160

  
161
    self._io_wait_add.append((owner, fd, condition))
162

  
163
  def UnregisterIO(self, fd):
164
    """Unregister a file descriptor.
165

  
166
    It'll be unregistered the next time the mainloop checks for it.
167

  
168
    @type fd: int
169
    @param fd: File descriptor
170

  
171
    """
172
    # select.Poller also supports file() like objects, but we don't.
173
    assert isinstance(fd, (int, long)), \
174
      "Only integers are supported for file descriptors"
175

  
176
    self._io_wait_remove.append(fd)
100 177

  
101 178
  def RegisterSignal(self, owner):
102 179
    """Registers a receiver for signal notifications

Also available in: Unified diff