#include "hg_ipc.h" #include "../../sdk/hginclude/hg_log.h" #include "huagao/hgscanner_error.h" #ifdef WIN32 #include "scanner_manager.h" #else #include #include #include #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; HG_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; HG_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; } HG_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_; HG_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); HG_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(""); HG_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); HG_VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is not existing and reopen it\n", prev.c_str()); } } else { HG_VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "shmget(0x%x%08x) = %d\n", v[1], v[0], errno); return; } } obj_ = (void*)obj; HG_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); HG_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]) { HG_VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "PID(%lld) name is: %s\n", pid, ret.c_str()); } else { HG_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); }