code_device/hgdriver/hgdev/hg_ipc.cpp

343 lines
7.5 KiB
C++

#include "hg_ipc.h"
#include "../wrapper/hg_log.h"
#include "huagao/hgscanner_error.h"
#ifdef WIN32
#include "scanner_manager.h"
#else
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// windows event ...
#ifdef WIN32
int __stdcall sem_init(sem_t* handle, int, int)
{
if (!handle)
{
errno = EINVAL;
return -1;
}
*handle = CreateEvent(NULL, TRUE, FALSE, NULL);
if (*handle)
return 0;
else
{
errno = GetLastError();
return -1;
}
}
void __stdcall sem_destroy(sem_t* handle)
{
if (*handle)
{
CloseHandle(*handle);
*handle = NULL;
}
}
int __stdcall sem_trywait(sem_t* handle)
{
return WaitForSingleObject(*handle, 1) == WAIT_TIMEOUT ? -1 : 0;
}
void __stdcall sem_wait(sem_t* handle)
{
if(WaitForSingleObject(*handle, INFINITE) == WAIT_OBJECT_0)
ResetEvent(*handle);
}
int __stdcall sem_timedwait(sem_t* handle, struct timespec* to)
{
DWORD elapse = to->tv_sec * 1000;
elapse += to->tv_nsec / (1000 * 1000);
int ret = WaitForSingleObject(*handle, elapse) == WAIT_TIMEOUT ? -1 : 0;
if(ret == 0)
ResetEvent(*handle);
return ret;
}
void __stdcall sem_post(sem_t* handle)
{
SetEvent(*handle);
}
#define pid_t int
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// platform_event (base on semaphore)
platform_event::platform_event() : waiting_(false), dbg_info_("")
{
int err = sem_init(&sem_, 0, 0);
if (err == -1)
{
err = errno;
VLOG_MINI_2(LOG_LEVEL_FATAL, "(%s)sem_init failed: %d\n", hg_log::format_ptr(this).c_str(), err);
}
}
platform_event::~platform_event()
{
sem_destroy(&sem_);
}
bool platform_event::try_wait(void)
{
return sem_trywait(&sem_) == 0;
}
bool platform_event::wait(unsigned timeout)
{
bool waited = true;
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "platform_event(%s - %s) --> waiting...\n", hg_log::format_ptr(this).c_str(), dbg_info_.c_str());
waiting_ = true;
if (timeout == USB_TIMEOUT_INFINITE)
sem_wait(&sem_);
else
{
struct timespec to;
to.tv_sec = timeout / 1000;
to.tv_nsec = (long)((timeout % 1000) * 1000 * 1000);
waited = sem_timedwait(&sem_, &to) == 0;
}
VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "platform_event(%s - %s) --> %s.\n", hg_log::format_ptr(this).c_str(), dbg_info_.c_str(), waited ? "waited" : "wait timeout");
waiting_ = false;
return waited;
}
void platform_event::notify(void)
{
sem_post(&sem_);
}
bool platform_event::is_waiting(void)
{
return waiting_;
}
void platform_event::set_debug_info(const char* info)
{
dbg_info_ = info ? info : "";
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// shared_memory
shared_memory::shared_memory(unsigned long long key, size_t size) : key_(key), obj_((void*)-1), first_(true), bytes_(size), len_(0)
{
unsigned int* ptr = (unsigned int*)&key_;
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "shared memory key = 0x%x%08x\n", ptr[1], ptr[0]);
init();
}
shared_memory::~shared_memory()
{
clear();
}
void shared_memory::init(void)
{
#ifdef WIN32
char name[40] = { 0 };
DWORD* key = (DWORD*)&key_;
HANDLE h = NULL;
sprintf(name, "scanner_0x%08x-%08x", key[1], key[0]);
h = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, bytes_, name);
if (h == NULL)
return;
first_ = !(GetLastError() == ERROR_ALREADY_EXISTS);
obj_ = (void*)h;
#else
int obj = shmget(key_, bytes_, IPC_EXCL | IPC_CREAT | 0600);
if (obj < 0)
{
unsigned int* v = (unsigned int*)&key_;
if (errno == EEXIST)
{
first_ = false;
obj = shmget(key_, bytes_, 0600);
if(obj == -1)
obj = shmget(key_, bytes_, 0);
VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "open existing: shmget(0x%x%08x) = %d\n", v[1], v[0], obj);
obj_ = (void*)obj;
std::string prev(read()), proc("");
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "shared memory content: %s\n", prev.c_str());
if(prev.length())
{
proc = prev;
size_t pos = proc.find("pid: ");
if (pos != std::string::npos)
proc.erase(0, pos + 5);
pos = proc.find(")");
if (pos != std::string::npos)
proc.erase(pos);
proc = shared_memory::get_proc_name_by_pid(atoi(proc.c_str()));
if (proc.length())
{
pos = prev.find("(");
if (pos == std::string::npos)
pos = prev.length();
if (strcasecmp(proc.c_str(), prev.substr(0, pos).c_str()))
proc = "";
}
}
if (proc.empty())
{
first_ = true;
clear();
obj = shmget(key_, bytes_, IPC_EXCL | IPC_CREAT | 0600);
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is not existing and reopen it\n", prev.c_str());
}
}
else
{
VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "shmget(0x%x%08x) = %d\n", v[1], v[0], errno);
return;
}
}
obj_ = (void*)obj;
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "shared memory id = %d[%s], \n", obj, first_ ? "created" : "opened");
#endif
if(first_)
{
pid_t pid = getpid();
std::string me("");
char buf[40] = { 0 };
unsigned int* pn = (unsigned int*)&pid;
if (sizeof(pid) > 4 && pn[1])
sprintf(buf, "(pid: 0x%x%08x)", pn[1], pn[0]);
else
sprintf(buf, "(pid: %u)", pn[0]);
hg_log::pe_path(&me);
me += buf;
write(me.c_str(), me.length());
}
}
void shared_memory::clear(void)
{
if (obj_ != (void*)-1)
#ifdef WIN32
CloseHandle((HANDLE)obj_);
#else
{
if (first_)
{
struct shmid_ds ds = { 0 };
int* h = (int*)&obj_;
shmctl(*h, IPC_RMID, &ds);
}
}
#endif
obj_ = (void*)-1;
}
char* shared_memory::get_buf(void)
{
#ifdef WIN32
char* buf = (char*)MapViewOfFile((HANDLE)obj_, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (!buf)
buf = (char*)-1;
#else
int* h = (int*)&obj_;
char* buf = (char*)shmat(*h, 0, 0);
VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "shared memory %d buffer = %s, error = %d\n", *h, hg_log::format_ptr(buf).c_str(), errno);
#endif
return buf;
}
void shared_memory::release_buf(void* buf)
{
#ifdef WIN32
UnmapViewOfFile(buf);
#else
shmdt(buf);
#endif
}
#ifndef WIN32
std::string shared_memory::get_proc_name_by_pid(pid_t pid)
{
char path[512] = { 0 };
unsigned int* v = (unsigned int*)&pid;
std::string ret("");
if (sizeof(pid) > 4 && v[1])
sprintf(path, "/proc/%lld/status", pid);
else
sprintf(path, "/proc/%u/status", pid);
FILE* src = fopen(path, "rb");
if (src)
{
char val[512] = { 0 };
memset(path, 0, sizeof(path));
fgets(path, sizeof(path) - 1, src);
fclose(src);
sscanf(path, "%*s %s", val);
ret = val;
}
if (sizeof(pid) > 4 && v[1])
{
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "PID(%lld) name is: %s\n", pid, ret.c_str());
}
else
{
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "PID(%u) name is: %s\n", pid, ret.c_str());
}
return ret;
}
#endif
bool shared_memory::is_ok(void)
{
return obj_ != nullptr;
}
bool shared_memory::is_first(void)
{
return is_ok() && first_;
}
std::string shared_memory::read(void)
{
if (obj_ == (void*)-1)
return "";
char* buf = get_buf();
if (buf == (char*)-1)
return "";
std::string ret("");
size_t len = 0;
int off = sizeof(size_t);
memcpy(&len, buf, off);
ret = std::string(buf + off, len);
release_buf(buf);
return ret;
}
int shared_memory::write(const char* data, size_t len)
{
if (len > bytes_)
return SCANNER_ERR_INSUFFICIENT_MEMORY;
char* buf = get_buf();
int off = sizeof(len);
if (buf == (char*)-1)
return errno;
memcpy(buf, &len, off);
memcpy(buf + off, data, len);
len_ = len;
release_buf(buf);
}