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; }