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

    runner_->setErrorHandler(std::bind(&wrap_log_error, this, "parser", std::placeholders::_1));
    runner_->setOptimizationLevel(optimizationLevel);

    if (!runner_->open(filename, settings)) {
        sd_notifyf(0, "ERRNO=%d", errno);
        goto err;
    }

    if (!validateConfig())
        goto err;

    // run setup
    TRACE("run 'setup'");
    if (runner_->invoke(runner_->findHandler("setup")))
        goto err;

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

    {
        bool (*main)(void*);
        main = runner_->getPointerTo(runner_->findHandler("main"));

        if (!main)
            goto err;

        server_->requestHandler = main;
    }

    // {{{ 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("setup: post_config");
    for (auto i: plugins_)
        if (!i->post_config())
            goto err;
    // }}}

    // {{{ run post-check hooks
    TRACE("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("setup: done.");
    return true;

err:
    return false;
}
Exemple #2
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;
}