void io_stream_t::run() const { proto.run(name); if(multiaccept) { size_t bq_n = scheduler.bq_n(); char const *fmt = log::number_fmt(bq_n); for(size_t i = 0; i < bq_n; ++i) { try { string_t _name = string_t::ctor_t(5).print(i, fmt); log::handler_t handler(_name); int _fd = ::dup(fd); if(_fd < 0) throw exception_sys_t(log::error, errno, "dup: %m"); fd_guard_t _fd_guard(_fd); bq_job(&io_stream_t::loop)(*this, _fd, false)->run(scheduler.bq_thr(i)); _fd_guard.relax(); } catch(exception_t const &) { } } } else { int _fd = ::dup(fd); if(_fd < 0) throw exception_sys_t(log::error, errno, "dup: %m"); loop(_fd, true); } }
void io_stream_t::init() { netaddr_t const &netaddr = bind_addr(); fd = socket(netaddr.sa->sa_family, SOCK_STREAM, 0); if(fd < 0) throw exception_sys_t(log::error, errno, "socket: %m"); try { bq_fd_setup(fd); fd_setup(fd); if(reuse_addr) { int i = 1; if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) throw exception_sys_t(log::error, errno, "setsockopt, SO_REUSEADDR, 1: %m"); } if(::bind(fd, netaddr.sa, netaddr.sa_len) < 0) throw exception_sys_t(log::error, errno, "bind: %m"); if(::listen(fd, listen_backlog) < 0) throw exception_sys_t(log::error, errno, "listen: %m"); } catch(...) { ::close(fd); fd = -1; throw; } stat.init(); proto.init(name); }
bq_thr_t::impl_t::impl_t( size_t _maxevs, interval_t _timeout, bq_cont_count_t &_cont_count, bq_post_activate_t *_post_activate ) : cont_count(_cont_count), post_activate(_post_activate), thread(0), tid(0), maxevs(_maxevs), timeout(_timeout), stat(), entry() { efd = epoll_create(maxevs); if(efd < 0) throw exception_sys_t(log::error, errno, "bq_thr_t::impl_t::impl_t, epoll_create: %m"); if(::pipe(sig_fds) < 0) throw exception_sys_t(log::error, errno, "bq_thr_t::impl_t::impl_t, pipe: %m"); bq_fd_setup(sig_fds[0]); bq_fd_setup(sig_fds[1]); epoll_event ev; ev.events = POLLIN; ev.data.ptr = NULL; if(epoll_ctl(efd, EPOLL_CTL_ADD, sig_fds[0], &ev) < 0) throw exception_sys_t(log::error, errno, "bq_thr_t::impl_t::impl_t, epoll_ctl, add: %m"); }
file_t::file_t(char const *name, string_t const &header) : ref_cnt(0), fd(-1), used(false), id() { if(config::check) return; fd = ::open(name, O_WRONLY | O_APPEND | O_CREAT, 0644); if(fd < 0) throw exception_sys_t(log::error, errno, "open (%s): %m", name); fd_guard_t guard(fd); id = id_t(fd, used); if(!id) throw exception_sys_t(log::error, errno, "fstat (%s): %m", name); if(::flock(fd, LOCK_SH | LOCK_NB) < 0) throw exception_sys_t(log::error, errno, "flock (%s): %m", name); if(header) { if(::write(fd, header.ptr(), header.size()) < 0) throw exception_sys_t(log::error, errno, "write (%s): %m", name); } guard.relax(); }
void link_t::loop() { timeval_t last_conn = timeval_long_ago; while(true) { try { { timeval_t now = timeval_current(); interval_t to_sleep = conn_timeout - (timeval_current() - last_conn); if(to_sleep > interval_zero && bq_sleep(&to_sleep) < 0) throw exception_sys_t(log::error, errno, "bq_sleep: %m"); } last_conn = timeval_current(); netaddr_t const &netaddr = remote_netaddr(); int fd = socket(netaddr.sa->sa_family, SOCK_STREAM, 0); if(fd < 0) throw exception_sys_t(remote_errors, errno, "socket: %m"); fd_guard_t fd_guard(fd); bq_fd_setup(fd); interval_t timeout = conn_timeout; if(bq_connect(fd, netaddr.sa, netaddr.sa_len, &timeout) < 0) throw exception_sys_t(remote_errors, errno, "connect: %m"); log_debug("connected"); bq_conn_fd_t conn(fd, ctl(), remote_errors, /* dup = */ true); proto_instance->proc(conn); } catch(exception_sys_t const &ex) { if(ex.errno_val == ECANCELED) throw; ex.log(); } catch(exception_t const &ex) { ex.log(); } } }
void bq_job_base_t::__create(pthread_t *pthread, pthread_attr_t *attr) { int err = pthread_create(pthread, attr, &__run_thr, this); if(err) { delete this; throw exception_sys_t(log::error, err, "pthread_create: %m"); } }
int method_datagram_t::connect_fd() { const netaddr_t& addr = target_addr(); int fd = socket(addr.sa->sa_family, SOCK_DGRAM, 0); if(fd < 0) { throw exception_sys_t(log::error, errno, "socket: %m"); } bq_fd_setup(fd); if(bq_connect(fd, addr.sa, addr.sa_len, NULL) < 0) { throw exception_sys_t(log::error, errno, "connect: %m"); } return fd; }
void scheduler_t::init() { sched_param sp = { priority }; size_t i = 0; try { char const *fmt = log::number_fmt(threads); for(; i < threads; ++i) { string_t name = string_t::ctor_t(5).print(i, fmt); log::handler_t handler(name); bq_thrs[i].init( event_buf_size, timeout_prec, cont_count, tname, post_activate() ); if(need_set_priority) if(sched_setscheduler(bq_thrs[i].get_tid(), policy, &sp) < 0) throw exception_sys_t(log::error, errno, "sched_setscheduler: %m"); } } catch(...) { bq_thr_t::stop(); bq_thrs[i].fini(); while(i) bq_thrs[--i].fini(); throw; } init_ext(); }
size_t in_fd_t::readv(iovec *iov, size_t cnt) { ssize_t res = ::readv(fd, iov, cnt); if(res < 0) throw exception_sys_t(get_log_level(), errno, "readv: %m"); return res; }
void io_zcluster_status_test_t::run() { int c = 0; while(true) { string_t status = string_t::ctor_t(16).print(c++); cluster_status_.update(status); interval_t to_sleep = (random_U() % 10) * interval_second; if(bq_sleep(&to_sleep) < 0) { throw exception_sys_t(log::error, errno, "bq_sleep: %m"); } } }
void io_logger_file_t::run() const { while(true) { interval_t t = check_interval; log_debug("tick"); if(bq_sleep(&t) < 0) throw exception_sys_t(log::error, errno, "bq_sleep: %m"); check(); } }
ref_t<pi_ext_t> wait_pool_t::data_t::wait(interval_t* timeout) { bq_cond_guard_t guard(cond_); while(!reply_) { if(!bq_success(cond_.wait(timeout))) { if(errno != ETIMEDOUT) { throw exception_sys_t(log::error, errno, "wait_pool::data_t.wait: %m"); } return reply_; } } return reply_; }
inline char *alloc() { { spinlock_guard_t guard(spinlock); ++wnum; if(num) { item_t *item = pool; pool = item->next; --num; return item->stack(); } } thr::tstate_t *tstate = thr::tstate; thr::state_t old_state; if(tstate) old_state = tstate->set(thr::mmap); char *stack = (char *)mmap( NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ); if(stack == MAP_FAILED) throw exception_sys_t(log::error, errno, "mmap: %m"); if (mprotect(stack, PAGE_SIZE, 0) < 0) throw exception_sys_t(log::error, errno, "mprotect: %m"); if(tstate) tstate->set(old_state); return stack; }
void io_stream_t::loop(int afd, bool conswitch) const { fd_guard_t fd_guard(afd); timeval_t last_poll = timeval::current(); while(true) { bool poll_before = false; if(force_poll.is_real()) { timeval_t now = timeval::current(); if(now - last_poll > force_poll) { poll_before = true; last_poll = now; } } netaddr_t *netaddr = new_netaddr(); int nfd = bq_accept(afd, netaddr->sa, &netaddr->sa_len, NULL, poll_before); if(nfd < 0) { delete netaddr; throw exception_sys_t(log::error, errno, "accept: %m"); } try { string_t _name = string_t::ctor_t(netaddr->print_len()).print(*netaddr); ++stat.conns(); bq_thr_t *thr = aux_scheduler ? aux_scheduler->bq_thr() : (conswitch ? scheduler.bq_thr() : bq_thr_get()) ; log::handler_t handler(_name); bq_job(&io_stream_t::conn_proc)(*this, nfd, netaddr)->run(thr); } catch(exception_t const &ex) { ::close(nfd); delete netaddr; } catch(...) { ::close(nfd); delete netaddr; throw; } } }
inline setup_caps_t(string_t const &, config_t const &config) { if(config::check) return; #if LINUX_CAPS uint32_t caps_keep = config.keep.value; if(caps_keep) { if(prctl(PR_SET_KEEPCAPS, 1) < 0) throw exception_sys_t(log::error, errno, "prctl(PR_SET_KEEPCAPS, 1): %m"); } #endif for(config::list_t<rlimit_t>::ptr_t rptr = config.rlimits; rptr; ++rptr) { rlimit_t const &rlim = rptr.val(); struct rlimit r; r.rlim_cur = r.rlim_max = rlim.val < sizeval_unlimited ? (rlim_t)rlim.val : RLIM_INFINITY; if(setrlimit(rlim.id, &r) < 0) throw exception_sys_t(log::error, errno, "setrlimit: %m"); } gid_t gid = config.group.id; if(gid) { if(setgroups(1, &gid) < 0) throw exception_sys_t(log::error, errno, "setgroups: %m"); if(setregid(gid, gid) < 0) throw exception_sys_t(log::error, errno, "setregid: %m"); } uid_t uid = config.user.id; if(uid) { if(setreuid(uid, uid) < 0) throw exception_sys_t(log::error, errno, "setreuid: %m"); } #if LINUX_CAPS if(caps_keep) { __user_cap_header_struct hdr; __user_cap_data_struct data; hdr.version = _LINUX_CAPABILITY_VERSION; hdr.pid = 0; data.effective = data.permitted = caps_keep; data.inheritable = 0; if(::capset(&hdr, &data) < 0) throw exception_sys_t(log::error, errno, "capset: %m"); if(prctl(PR_SET_KEEPCAPS, 0) < 0) throw exception_sys_t(log::error, errno, "prctl(PR_SET_KEEPCAPS, 0): %m"); if(prctl(PR_SET_DUMPABLE, 1) < 0) throw exception_sys_t(log::error, errno, "prctl(PR_SET_DUMPABLE, 1): %m"); } #endif }
void bq_thr_t::impl_t::loop() { tid = thr::id; current = this; thr::tstate = &stat.tstate(); epoll_event evs[maxevs]; int timeoit_msec = timeout / interval::millisecond; struct heaps_t { bq_heap_t common, ready; inline heaps_t() : common(), ready() { } inline void insert(bq_heap_t::item_t *item) { bq_heap_t *heap = item->heap; if(heap) { if(item->ready) { if(heap == &ready) return; } else { if(heap == &common) return; } heap->remove(item); } (item->ready ? ready : common).insert(item); } inline void remove(bq_heap_t::item_t *item) { bq_heap_t *heap = item->heap; if(heap) heap->remove(item); } inline bq_heap_t::item_t *head(timeval_t const &now, bool work) { bq_heap_t::item_t *citem = common.head(); bq_heap_t::item_t *ritem = ready.head(); if(work) { if(citem && citem->time_to >= now) citem = NULL; if(ritem) { if(!citem || citem->time_to >= ritem->time_to) return ritem; } } else { if(ritem) return ritem; } return citem; } } heaps; while(work || bq_cont_count()) { int n = epoll_wait(efd, evs, maxevs, timeoit_msec); if(n < 0) { if(errno != EINTR) throw exception_sys_t(log::error, errno, "bq_thr_t::impl_t::loop, epoll_wait: %m"); n = 0; } stat.tstate().set(thr::run); for(int i = 0; i < n; ++i) { void *ptr = evs[i].data.ptr; if(ptr) { poll_item_t *item = (poll_item_t *)ptr; item->events = evs[i].events & ~(EPOLLET | EPOLLONESHOT); // may be "item->ready = true; heaps.insert(item);" entry.set_ready(item); } else { char buf[1024]; if(::read(sig_fds[0], buf, sizeof(buf)) < 0) { if(errno != EAGAIN) log_error("bq_thr_t::impl_t::clear: %m"); } } } while(true) { bq_heap_t::item_t *item = NULL; while((item = entry.remove())) heaps.insert(item); timeval_t time = timeval::current(); if(!(item = heaps.head(time, work))) break; heaps.remove(item); ++stat.acts(); if(item->ready) { if(item->timeout) *item->timeout = item->time_to > time ? item->time_to - time : interval::zero; item->err = bq_ok; } else { if(item->timeout) *item->timeout = interval::zero; item->err = work ? bq_timeout : bq_not_available; } bq_cont_activate(item->cont); } stat.tstate().set(thr::idle); } thr::tstate = NULL; current = NULL; tid = 0; }
void bq_job_base_t::__create(bq_thr_t *bq_thr) { if(!bq_success(bq_cont_create(bq_thr, &__run_bq, this))) { delete this; throw exception_sys_t(log::error, errno, "bq_cont_create: %m"); } }