#include "ipc_util.h" #include #include #include #include #include #include #include "log_util.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // linux_event unsigned long linux_event::to_abs_time_us = 0; linux_event::linux_event(const char* desc) : waiting_(false), sem_(nullptr), desc_(desc ? desc : ""), first_(true), multi_proc_(false) { log_cls::log(LOG_LEVEL_ALL, "+linux_event(%p) unamed for '%s' constructing ...\n", this, desc_.c_str()); err_ = sem_init(&local_sem_, 0, 0); if (err_ == -1) { err_ = errno; log_cls::log(LOG_LEVEL_FATAL, " %p: sem_init = %s\n", this, strerror(err_)); } else { sem_ = &local_sem_; } } linux_event::linux_event(const char* name, const char* desc) : waiting_(false), sem_(nullptr), desc_(desc ? desc : ""), first_(true), multi_proc_(true) { log_cls::log(LOG_LEVEL_ALL, "+linux_event(%p) of named '%s' for '%s' constructing ...\n", this, name, desc_.c_str()); sem_ = sem_open(name, O_CREAT | O_EXCL, 0777, 0); if (sem_ == (sem_t*)SEM_FAILED) { sem_ = nullptr; err_ = errno; log_cls::log(LOG_LEVEL_FATAL, " %p: sem_open(O_CREAT | O_EXCL) = %s\n", this, strerror(err_)); if(err_ = EEXIST) { sem_ = sem_open(name, 0666); if (sem_ == (sem_t*)SEM_FAILED) { err_ = errno; sem_ = nullptr; log_cls::log(LOG_LEVEL_FATAL, " %p: sem_open = %s\n", this, strerror(err_)); } else { err_ = 0; first_ = false; } } } else { name_ = name; log_cls::log(LOG_LEVEL_DEBUG, " %p: created named sem OK.\n", this); err_ = sem_init(sem_, 1, 0); // this is used to initialize the event count, whether named or unamed if (err_ == -1) { err_ = errno; log_cls::log(LOG_LEVEL_FATAL, " %p: sem_init = %s\n", this, strerror(err_)); sem_close(sem_); sem_ = nullptr; sem_unlink(name); } } } linux_event::linux_event(sem_t* mem_sem, bool first, const char* desc) : waiting_(false), sem_(mem_sem), desc_(desc ? desc : ""), first_(first), multi_proc_(true) { log_cls::log(LOG_LEVEL_ALL, "+linux_event(%p) at mem(%p) for '%s' constructing ...\n", this, mem_sem, desc_.c_str()); if(first) { err_ = sem_init(sem_, 1, 0); if (err_ == -1) { err_ = errno; log_cls::log(LOG_LEVEL_FATAL, " %p: sem_init = %s\n", this, strerror(err_)); } } } linux_event::~linux_event() { if (sem_) { char ptr[40] = {0}; std::string tips(""); sprintf(ptr, " ~%p: ", this); tips = ptr; if(sem_ == &local_sem_ || (first_ && name_.empty())) { err_ = log_cls::log_when_err(sem_destroy(sem_), (tips + "sem_destroy").c_str()); } else { err_ = log_cls::log_when_err(sem_close(sem_), (tips + "sem_close").c_str()); // else // why not else ? we should ensure delete the kernel object when unused. if(!name_.empty()) // i am the named object owner ! { err_ = log_cls::log_when_err(sem_unlink(name_.c_str()), (tips + "sem_unlink").c_str(), LOG_LEVEL_FATAL); // This will cause previously opened objects to never receive events, even if you reopen it. } } } log_cls::log(LOG_LEVEL_ALL, "-linux_event(%p) destroyed.\n", this); } int32_t linux_event::clear_named_event(const char* name) { sem_t* sem = sem_open(name, O_CREAT | O_EXCL, 0777, 0); int32_t err = 0; if(sem == (sem_t*)SEM_FAILED) { if(errno == EEXIST) { err = sem_unlink(name); if(err == -1) err = errno; } else { return 0; } } else { sem_close(sem); sem_unlink(name); } return err; } void linux_event::reset_calc_abs_time(unsigned us) { if(us == -1) { struct timeval now = {0}, after = {0}; struct timespec abst = {0}; linux_event::to_abs_time_us = 10; if(chronograph::now(&now)) { abst.tv_sec = now.tv_sec; abst.tv_nsec = USEC_2_NS(now.tv_usec); abst.tv_nsec += MSEC_2_NS(1) + linux_event::to_abs_time_us; // overflow ... abst.tv_sec += abst.tv_nsec / SEC_2_NS(1); abst.tv_nsec %= SEC_2_NS(1); if(chronograph::now(&after)) { if(after.tv_usec > now.tv_usec) linux_event::to_abs_time_us = after.tv_usec - now.tv_usec; else linux_event::to_abs_time_us = SEC_2_US(1) + after.tv_usec - now.tv_usec; } } } else { linux_event::to_abs_time_us = us; } } bool linux_event::abs_time_after(struct timespec* abstm, unsigned ms) { struct timeval now = {0}; if(!chronograph::now(&now)) { log_cls::log(LOG_LEVEL_FATAL, "gettimeofday faied: %s\n!", strerror(errno)); time(&now.tv_sec); } abstm->tv_sec = now.tv_sec; abstm->tv_nsec = USEC_2_NS(now.tv_usec); abstm->tv_nsec += MSEC_2_NS(ms) + USEC_2_NS(linux_event::to_abs_time_us); // overflow ... abstm->tv_sec += abstm->tv_nsec / SEC_2_NS(1); abstm->tv_nsec %= SEC_2_NS(1); return true; } bool linux_event::is_ready(void) { return sem_ != nullptr; } bool linux_event::is_named_first(void) { return !name_.empty(); } bool linux_event::wait_try(void) { return sem_trywait(sem_) == 0; } bool linux_event::wait(unsigned timeout) { bool waited = true; log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): waiting(%u) ...\n", this, timeout); waiting_ = true; if (timeout == WAIT_INFINITE) { sem_wait(sem_); } else { struct timespec to = {0}; linux_event::abs_time_after(&to, timeout); waited = sem_timedwait(sem_, &to) == 0; } waiting_ = false; log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): waited(%u) = %d\n", this, timeout, waited); return waited; } void linux_event::trigger(void) { err_ = sem_post(sem_); if(err_) err_ = errno; log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): trigger = %s\n", this, err_ == 0 ? "OK" : strerror(errno)); } void linux_event::reset(void) { err_ = sem_init(sem_, multi_proc_, 0); if(err_) err_ = errno; log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): reset = %s\n", this, err_ == 0 ? "OK" : strerror(errno)); } bool linux_event::is_waiting(void) { return waiting_; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // shared_mem uint64_t shared_mem::mem_total_ = 0; uint64_t shared_mem::page_unit_ = 0; uint64_t shared_mem::huge_page_unit_ = 0; shared_mem::shared_mem() : name_(""), id_(0), size_(0), shm_buf_(shared_mem::invalid_map_addr()), first_(false), shm_id_(-1) { if (shared_mem::page_unit_ == 0) shared_mem::init_page_info(); log_cls::log(LOG_LEVEL_ALL, "+shared_mem(%p) constructed, page size = %ld\n", this, page_unit_); } shared_mem::~shared_mem() { close(); log_cls::log(LOG_LEVEL_ALL, "-shared_mem(%p) destroyed.\n", this); } void shared_mem::init_page_info(void) { shared_mem::page_unit_ = sys_util::get_page_size(); // Hugepagesize: 2048 kB if(sys_util::get_inf_file_data("/proc/meminfo", 80, "MemTotal: %ld", &shared_mem::mem_total_)) shared_mem::mem_total_ *= 1024; if(sys_util::get_inf_file_data("/proc/meminfo", 80, "Hugepagesize: %ld", &shared_mem::huge_page_unit_)) shared_mem::huge_page_unit_ *= 1024; log_cls::log(LOG_LEVEL_DEBUG, "TotalMemory: %s, system page size: %s, huge page size %s\n" , sys_util::format_readable_bytes(shared_mem::mem_total_).c_str() , sys_util::format_readable_bytes(shared_mem::page_unit_).c_str() , sys_util::format_readable_bytes(shared_mem::huge_page_unit_).c_str()); } char* shared_mem::invalid_map_addr(void) { return (char*)-1; } int32_t shared_mem::open(int32_t id, size_t* bytes, const char* name) { key_t key = (key_t)-1; // ftok(name, id); int32_t ret = close(); size_t size = bytes ? *bytes : 0; std::string pe(""); if (ret) return ret; if(!name || *name == 0) { pe = sys_util::get_module_path(); name = pe.c_str(); } key = ftok(name, id); if (key == (key_t)-1) { log_cls::log(LOG_LEVEL_FATAL, "shared_memory(%p): ftok('%s', %d) = %s\n", this, name, id, strerror(errno)); return errno; } log_cls::log(LOG_LEVEL_DEBUG, "shared memory key: %p\n", key); size = ALIGN_INT(size, shared_mem::page_unit_); if (!bytes || *bytes != size) { log_cls::log(LOG_LEVEL_DEBUG, "add %ld upto multiple of page size: %ld\n", bytes ? *bytes : 0, size); if (bytes) *bytes = size; } shm_id_ = shmget(key, size, IPC_EXCL | IPC_CREAT | 0600); if (shm_id_ == -1) { ret = errno; log_cls::log(LOG_LEVEL_WARNING, "%p: create shared memory('%s', %d) failed: %s\n", this, name, id, strerror(ret)); if (ret == EEXIST) { shm_id_ = shmget(key, size, 0600); if (shm_id_ == -1) { ret = errno; log_cls::log(LOG_LEVEL_WARNING, "%p: open shared memory('%s', %d) failed: %s\n", this, name, id, strerror(ret)); } else { ret = 0; first_ = false; } } } else // i created the shared memory ... { first_ = true; } if (ret == 0) { shm_buf_ = (char*)shmat(shm_id_, nullptr, 0); if (shm_buf_ == shared_mem::invalid_map_addr()) { ret = errno; log_cls::log(LOG_LEVEL_WARNING, "%p: shmat failed: %s\n", this, strerror(ret)); close(); } else { log_cls::log(LOG_LEVEL_DEBUG, "%p: %s shared memory('%s', %d) at %p(+%s) OK.\n", this, first_ ? "create" : "open", name, id, shm_buf_, sys_util::format_readable_bytes(size).c_str()); name_ = name; id_ = id; size_ = size; } } return ret; } int32_t shared_mem::close(void) { int32_t ret = 0; if (shm_buf_ != shared_mem::invalid_map_addr()) { ret = log_cls::log_when_err(shmdt(shm_buf_), "shmdt"); if (ret) return ret; shm_buf_ = shared_mem::invalid_map_addr(); } if (first_ && shm_id_ >= 0) { ret = log_cls::log_when_err(shmctl(shm_id_, IPC_RMID, nullptr), "shmctrl(IPC_RMID)"); if (ret && ret != ENOENT) { // re-map buffer ... shm_buf_ = (char*)shmat(shm_id_, nullptr, 0); return ret; } shm_id_ = -1; } name_ = ""; id_ = 0; first_ = false; size_ = 0; return ret; } char* shared_mem::get_mem(size_t* size) { if (size) *size = size_; return shm_buf_ == shared_mem::invalid_map_addr() ? nullptr : shm_buf_; } bool shared_mem::is_first(void) { return first_; } void shared_mem::clear_kernel_object(void) { log_cls::log_when_err(shmctl(shm_id_, IPC_RMID, nullptr), "shmctrl(IPC_RMID)"); }