code_scanner/common/ipc_util.cpp

419 lines
10 KiB
C++

#include "ipc_util.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#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)");
}