def main(self, installsignal = True, sendinit = True):
        '''
        Start main loop
        '''
        if installsignal:
            sigterm = signal(SIGTERM, self._quitsignal)
            sigint = signal(SIGINT, self._quitsignal)
            try:
                from signal import SIGUSR1
                sigusr1 = signal(SIGUSR1, self._tracesignal)
            except Exception:
                pass
        try:
            if sendinit:
                self.queue.append(SystemControlEvent(SystemControlEvent.INIT), True)
            def processSyscall():
                while self.syscallfunc is not None:
                    r = getattr(self, 'syscallrunnable', None)
                    if r is None:
                        self.syscallfunc = None
                        break
                    try:
                        try:
                            retvalue = self.syscallfunc(self, processEvent)
                        except Exception:
                            (t, v, tr) = sys.exc_info()
                            self.syscallfunc = None
                            self.syscallrunnable = None
                            r.send((SyscallReturnEvent(exception=(t, v, tr)), self.syscallmatcher))
                        else:
                            self.syscallfunc = None
                            self.syscallrunnable = None
                            r.send((SyscallReturnEvent(retvalue=retvalue), self.syscallmatcher))
                    except StopIteration:
                        self.unregisterall(r)
                    except QuitException:
                        self.unregisterall(r)
                    except Exception:
                        self.logger.exception('processing syscall failed with exception')
                        self.unregisterall(r)

            def processEvent(event, emptys = ()):
                if self.debugging:
                    self.logger.debug('Processing event %s', repr(event))
                runnables = self.matchtree.matchesWithMatchers(event)
                for r, m in runnables:
                    try:
                        self.syscallfunc = None
                        self.syscallrunnable = None
                        if self.debugging:
                            self.logger.debug('Send event to %r, matched with %r', r, m)
                        r.send((event, m))
                    except StopIteration:
                        self.unregisterall(r)
                    except QuitException:
                        self.unregisterall(r)
                    except Exception:
                        self.logger.exception('processing event %s failed with exception', repr(event))
                        self.unregisterall(r)
                    processSyscall()
                if not event.canignore and not event.canignorenow():
                    self.eventtree.insert(event)
                    self.queue.block(event, emptys)
                else:
                    for e in emptys:
                        processEvent(e)

            def processQueueEvent(event):
                """
                Optimized with queue events
                """
                if self.debugging:
                    self.logger.debug('Processing event %s', repr(event))
                is_valid = event.is_valid()
                if is_valid is None:
                    processEvent(event)
                else:
                    while event.is_valid():
                        result = self.matchtree.matchfirstwithmatcher(event)
                        if result is None:
                            break
                        r, m = result
                        try:
                            self.syscallfunc = None
                            self.syscallrunnable = None
                            if self.debugging:
                                self.logger.debug('Send event to %r, matched with %r', r, m)
                            r.send((event, m))
                        except StopIteration:
                            self.unregisterall(r)
                        except QuitException:
                            self.unregisterall(r)
                        except Exception:
                            self.logger.exception('processing event %s failed with exception', repr(event))
                            self.unregisterall(r)
                        processSyscall()
            
            def processYields():
                while self._pending_runnables:
                    i = 0
                    while i < len(self._pending_runnables):
                        r = self._pending_runnables[i]
                        try:
                            next(r)
                        except StopIteration:
                            self.unregisterall(r)
                        except QuitException:
                            self.unregisterall(r)
                        except Exception:
                            self.logger.exception('Resuming %r failed with exception', r)
                            self.unregisterall(r)
                        processSyscall()
                        i += 1
                    del self._pending_runnables[:i]
            canquit = False
            self.logger.info('Main loop started')
            current_time = self.current_time = time()
            processYields()
            quitMatcher = SystemControlEvent.createMatcher(type=SystemControlEvent.QUIT)
            while len(self.registerIndex) > len(self.daemons):
                if self.debugging:
                    self.logger.debug('Blocked events: %d', len(self.queue.blockEvents))
                    self.logger.debug('Blocked events list: %r', list(self.queue.blockEvents.keys()))
                    if self.quitting:
                        self.logger.debug('Routines still not quit: %r', list(self.registerIndex.keys()))
                if self.quitsignal:
                    self.quit()
                if canquit and not self.queue.canPop() and not self.timers:
                    if self.quitting:
                        break
                    else:
                        self.quit(True)
                self.queue.append(SystemControlLowPriorityEvent(SystemControlLowPriorityEvent.LOOP), True)
                processedEvents = 0
                while self.queue.canPop() and (self.processevents is None or processedEvents < self.processevents):
                    e, qes, emptys = self.queue.pop()
                    # Queue events will not enqueue again
                    if not e.canignore and not e.canignorenow():
                        # The event might block, must process it first
                        processEvent(e, emptys)
                        for qe in qes:
                            processQueueEvent(qe)
                    else:
                        for qe in qes:
                            processQueueEvent(qe)
                        processEvent(e, emptys)
                    processYields()
                    if quitMatcher.isMatch(e):
                        if e.daemononly:
                            runnables = list(self.daemons)
                        else:
                            runnables = list(self.registerIndex.keys())
                        for r in runnables:
                            try:
                                r.throw(QuitException)
                            except StopIteration:
                                self.unregisterall(r)
                            except QuitException:
                                self.unregisterall(r)
                            except Exception:
                                self.logger.exception('Runnable quit failed with exception')
                                self.unregisterall(r)
                            processSyscall()
                        processYields()
                    if self.quitsignal:
                        self.quit()
                    processedEvents += 1
                if len(self.registerIndex) <= len(self.daemons):
                    break
                end_time = time()
                if end_time - current_time > 1:
                    self.logger.warning("An iteration takes %r seconds to process", end_time - current_time)
                if self.generatecontinue or self.queue.canPop():
                    wait = 0
                elif not self.timers:
                    wait = None
                else:
                    wait = self.timers.top().timestamp - end_time
                    if wait < 0:
                        wait = 0
                events, canquit = self.polling.pollEvents(wait)
                for e in events:
                    self.queue.append(e, True)
                current_time = self.current_time = time()
                now = current_time + 0.1
                while self.timers and self.timers.topPriority() < now:
                    t = self.timers.top()
                    if t.interval is not None:
                        t.timestamp += t.interval
                        self.timers.setpriority(t, t.timestamp)
                    else:
                        self.timers.pop()
                    self.queue.append(TimerEvent(t), True)
                if self.generatecontinue:
                    self.queue.append(SystemControlEvent(SystemControlEvent.CONTINUE), True)
                    self.generatecontinue = False
            if self.registerIndex:
                if len(self.registerIndex) > len(self.daemons):
                    self.logger.warning('Some runnables are not quit, doing cleanup')
                    self.logger.warning('Runnables list: %r', set(self.registerIndex.keys()).difference(self.daemons))
                for r in list(self.registerIndex.keys()):
                    try:
                        r.close()
                    except Exception:
                        self.logger.exception('Runnable quit failed with exception')
                    finally:
                        self.unregisterall(r)
            self.logger.info('Main loop quit normally')
        finally:
            if installsignal:
                signal(SIGTERM, sigterm)
                signal(SIGINT, sigint)
                try:
                    signal(SIGUSR1, sigusr1)
                except Exception:
                    pass