protected function shutdown($hard = false)
    {
        $error = error_get_last();
        if ($error) {
            if ($error['type'] === E_ERROR) {
                Daemon::log('W#' . $this->pid . ' crashed by error \'' . $error['message'] . '\' at ' . $error['file'] . ':' . $error['line']);
            }
        }

        if (Daemon::$config->throwexceptiononshutdown->value) {
            throw new \Exception('event shutdown');
        }

        @ob_flush();

        if ($this->terminated === true) {
            if ($hard) {
                exit(0);
            }

            return;
        }

        $this->terminated = true;

        if ($hard) {
            $this->setState(Daemon::WSTATE_SHUTDOWN);
            exit(0);
        }

        $this->reloadReady = $this->appInstancesReloadReady();
        Timer::remove('breakMainLoopCheck');

        Timer::add(function ($event) {
            $self = Daemon::$process;

            $self->reloadReady = $self->appInstancesReloadReady();

            if ($self->reload === true) {
                $self->reloadReady = $self->reloadReady && (microtime(true) > $self->reloadTime);
            }
            if (!$self->reloadReady) {
                $event->timeout();
            } else {
                EventLoop::$instance->stop();
            }
        }, 1e6, 'checkReloadReady');
        while (!$this->reloadReady) {
            EventLoop::$instance->run();
        }
        FileSystem::waitAllEvents(); // ensure that all I/O events completed before suicide
        posix_kill(getmypid(), SIGKILL);
        exit(0); // R.I.P.
    }