Beispiel #1
0
bool XzeroDaemon::setup(std::unique_ptr<std::istream>&& settings, const std::string& filename, int optimizationLevel)
{
	TRACE(1, "setup(%s)", filename.c_str());

    FlowParser parser(this);
    parser.importHandler = std::bind(&XzeroDaemon::import, this, std::placeholders::_1, std::placeholders::_2,
            std::placeholders::_3);

    if (!parser.open(filename, std::move(settings))) {
        sd_notifyf(0, "ERRNO=%d", errno);
        fprintf(stderr, "Failed to open file: %s\n", filename.c_str());
        return false;
    }

	unit_ = parser.parse();
    if (!unit_)
        return false;

    if (dumpAST_)
        ASTPrinter::print(unit_.get());

    std::unique_ptr<IRProgram> ir = IRGenerator::generate(unit_.get());
    if (!ir) {
        fprintf(stderr, "IR generation failed. Aborting.\n");
        return false;
    }

    {
        PassManager pm;

        // mandatory passes
        pm.registerPass(std::make_unique<UnusedBlockPass>());

        // optional passes
        if (optimizationLevel >= 1) {
            pm.registerPass(std::make_unique<EmptyBlockElimination>());
            pm.registerPass(std::make_unique<InstructionElimination>());
        }

        pm.run(ir.get());
    }

    if (dumpIR_) {
        ir->dump();
    }

    program_ = TargetCodeGenerator().generate(ir.get());

    ir.reset();

    if (!program_) {
        fprintf(stderr, "Code generation failed. Aborting.\n");
        return false;
    }

    if (!program_->link(this)) {
        fprintf(stderr, "Program linking failed. Aborting.\n");
        return false;
    }

	if (!validateConfig()) {
		return false;
    }

    if (dumpTargetCode_)
        program_->dump();

	// run setup
	TRACE(1, "run 'setup'");
    if (program_->findHandler("setup")->run(nullptr))
        // should not return true
        return false;

	// grap the request handler
	TRACE(1, "get pointer to 'main'");

    {
        auto main = program_->findHandler("main");

        server_->requestHandler = [=](x0::HttpRequest* r) {
            FlowVM::Runner* cx = static_cast<FlowVM::Runner*>(r->setCustomData(r, main->createRunner()));
            cx->setUserData(r);
            bool handled = cx->run();
            if (!cx->isSuspended() && !handled) {
                r->finish();
            }
        };
    }

	// {{{ setup server-tag
	{
#if defined(HAVE_SYS_UTSNAME_H)
		{
			utsname utsname;
			if (uname(&utsname) == 0) {
				addComponent(std::string(utsname.sysname) + "/" + utsname.release);
				addComponent(utsname.machine);
			}
		}
#endif

#if defined(HAVE_BZLIB_H)
		{
			std::string zver("bzip2/");
			zver += BZ2_bzlibVersion();
			zver = zver.substr(0, zver.find(","));
			addComponent(zver);
		}
#endif

#if defined(HAVE_ZLIB_H)
		{
			std::string zver("zlib/");
			zver += zlib_version;
			addComponent(zver);
		}
#endif

		Buffer tagbuf;
		tagbuf.push_back("x0/" VERSION);

		if (!components_.empty())
		{
			tagbuf.push_back(" (");

			for (int i = 0, e = components_.size(); i != e; ++i)
			{
				if (i)
					tagbuf.push_back(", ");

				tagbuf.push_back(components_[i]);
			}

			tagbuf.push_back(")");
		}
		server_->tag = tagbuf.str();
	}
	// }}}

	// {{{ run post-config hooks
	TRACE(1, "setup: post_config");
	for (auto i: plugins_)
		if (!i->post_config())
			goto err;
	// }}}

	// {{{ run post-check hooks
	TRACE(1, "setup: post_check");
	for (auto i: plugins_)
		if (!i->post_check())
			goto err;
	// }}}

	// {{{ check for available TCP listeners
	if (server_->listeners().empty()) {
		log(Severity::error, "No HTTP listeners defined");
		goto err;
	}
	for (auto i: server_->listeners())
		if (!i->isOpen())
			goto err;
	// }}}

	// {{{ check for SO_REUSEPORT feature in TCP listeners
	if (server_->workers().size() == 1) {
		// fast-path scheduling for single-threaded mode
		server_->workers().front()->bind(server_->listeners().front());
	} else {
		std::list<ServerSocket*> dups;
		for (auto listener: server_->listeners()) {
			if (listener->reusePort()) {
				for (auto worker: server_->workers()) {
					if (worker->id() > 0) {
						// clone listener for non-main worker
						listener = listener->clone(worker->loop());
						dups.push_back(listener);
					}
					worker->bind(listener);
				}
			}
		}

		// FIXME: this is not yet well thought.
		// - how to handle configuration file reloads wrt SO_REUSEPORT?
		for (auto dup: dups) {
			server_->listeners().push_back(dup);
		}
	}
	// }}}

	// {{{ x0d: check for superfluous passed file descriptors (and close them)
	for (auto fd: ServerSocket::getInheritedSocketList()) {
		bool found = false;
		for (auto li: server_->listeners()) {
			if (fd == li->handle()) {
				found = true;
				break;
			}
		}
		if (!found) {
			log(Severity::debug, "Closing inherited superfluous listening socket %d.", fd);
			::close(fd);
		}
	}
	// }}}

	// {{{ systemd: check for superfluous passed file descriptors
	if (int count = sd_listen_fds(0)) {
		int maxfd = SD_LISTEN_FDS_START + count;
		count = 0;
		for (int fd = SD_LISTEN_FDS_START; fd < maxfd; ++fd) {
			bool found = false;
			for (auto li: server_->listeners()) {
				if (fd == li->handle()) {
					found = true;
					break;
				}
			}
			if (!found) {
				++count;
			}
		}
		if (count) {
			fprintf(stderr, "superfluous systemd file descriptors: %d\n", count);
			return false;
		}
	}
	// }}}

	// XXX post worker wakeup
	// we do an explicit wakeup of all workers here since there might be already
	// some (configure-time related) events pending, i.e. director's (fcgi) health checker
	// FIXME this is more a workaround than a fix.
	for (auto worker: server_->workers())
		worker->wakeup();

	TRACE(1, "setup: done.");
	return true;

err:
	return false;
}