diff --git a/private/lib/windows/x86_64/rktwebview.dll b/private/lib/windows/x86_64/rktwebview.dll new file mode 100644 index 0000000..21a44db Binary files /dev/null and b/private/lib/windows/x86_64/rktwebview.dll differ diff --git a/private/lib/windows/x86_64/rktwebview_prg.exe b/private/lib/windows/x86_64/rktwebview_prg.exe new file mode 100644 index 0000000..9ac1f7b Binary files /dev/null and b/private/lib/windows/x86_64/rktwebview_prg.exe differ diff --git a/private/lib/windows/x86_64/rktwebview_qt.dll b/private/lib/windows/x86_64/rktwebview_qt.dll deleted file mode 100644 index 8676948..0000000 Binary files a/private/lib/windows/x86_64/rktwebview_qt.dll and /dev/null differ diff --git a/private/lib/windows/x86_64/rktwebview_qt_test.exe b/private/lib/windows/x86_64/rktwebview_qt_test.exe deleted file mode 100644 index 0337098..0000000 Binary files a/private/lib/windows/x86_64/rktwebview_qt_test.exe and /dev/null differ diff --git a/private/lib/windows/x86_64/rktwebview_test.exe b/private/lib/windows/x86_64/rktwebview_test.exe new file mode 100644 index 0000000..2a1ab41 Binary files /dev/null and b/private/lib/windows/x86_64/rktwebview_test.exe differ diff --git a/private/racket-webview-qt.rkt b/private/racket-webview-qt.rkt index ad997fb..be8fbc2 100644 --- a/private/racket-webview-qt.rkt +++ b/private/racket-webview-qt.rkt @@ -142,7 +142,12 @@ (putenv "QTWEBENGINE_LOCALES_PATH" (path->string (build-path os-lib-dir "translations" "qtwebengine_locales"))) (putenv "RKT_WEBVIEW_PRG" + (let ((p (path->string (build-path os-lib-dir rktwebview-prg))) + ) + (displayln p) + p + )) (when (eq? os 'linux) (putenv "QT_QPA_PLATFORM" "xcb") (putenv "LD_LIBRARY_PATH" @@ -222,8 +227,19 @@ eval_js_failed = 3 no_devtools_on_platform = 4 no_delegate_for_context = 5 + webview_missing_dependency = 6 + webview_canceled = 7 + webview_invalid_state = 8 + webview_invalid_argument = 9 + webview_unspecified = 10 + webview_dispatch_failed = 11 move_failed = 12 resize_failed = 13 + choose_dir_failed = 14 + open_file_failed = 15 + save_file_failed = 16 + failed = 17 + invalid_handle = 18 ) ) ) diff --git a/rktwebview_qt/CMakeLists.txt b/rktwebview_qt/CMakeLists.txt index 26adecf..48bc0b1 100644 --- a/rktwebview_qt/CMakeLists.txt +++ b/rktwebview_qt/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(rktwebview SHARED rkt_protocol.h rktwebview_types.h json.cpp json.h + utils.h ) add_executable(rktwebview_prg diff --git a/rktwebview_qt/main.cpp b/rktwebview_qt/main.cpp index 1b96cc4..ebf7a7c 100644 --- a/rktwebview_qt/main.cpp +++ b/rktwebview_qt/main.cpp @@ -62,8 +62,10 @@ int main(int argc, char *argv[]) { const char *me = argv[0]; + fprintf(stderr, "%s runs\n", argv[0]);fflush(stderr); + if (argc < 6) { - fprintf(stderr, "%s: wrong number of arguments\n", me); + fprintf(stderr, "%s: wrong number of arguments\n", me);fflush(stderr); exit(1); } @@ -78,11 +80,11 @@ int main(int argc, char *argv[]) int res_slot = atoi(res_slot_str); int evt_slot = atoi(evt_slot_str); - fprintf(stderr, "%s %s %s %s %s %s\n", me, shm_name, shm_size_str, cmd_slot_str, res_slot_str, evt_slot_str); - fprintf(stderr, "%s %s %ld %d %d %d\n", me, shm_name, shm_size, cmd_slot, res_slot, evt_slot); + fprintf(stderr, "%s %s %s %s %s %s\n", me, shm_name, shm_size_str, cmd_slot_str, res_slot_str, evt_slot_str);fflush(stderr); + fprintf(stderr, "%s %s %ld %d %d %d\n", me, shm_name, shm_size, cmd_slot, res_slot, evt_slot);fflush(stderr); if (!(shm_size > 0 && cmd_slot > 0 && res_slot > 0 && evt_slot > 0)) { - fprintf(stderr, "%s: Invalid shm size or slots\n", me); + fprintf(stderr, "%s: Invalid shm size or slots\n", me);fflush(stderr); exit(2); } @@ -98,10 +100,10 @@ int main(int argc, char *argv[]) handler->webview_handler->initApp(); handler->webview_handler->execApp(); - fprintf(stderr, "waiting for thread to end\n"); + fprintf(stderr, "waiting for thread to end\n");fflush(stderr); handler->wait(); - fprintf(stderr, "cleaning up shm\n"); + fprintf(stderr, "cleaning up shm\n");fflush(stderr); delete handler->webview_handler; delete handler->command_queue; @@ -318,7 +320,7 @@ void Handler::run() } break; default: { - fprintf(stderr, "Unknown command: %d\n", cmd); + fprintf(stderr, "Unknown command: %d\n", cmd);fflush(stderr); } } } diff --git a/rktwebview_qt/rktwebview.cpp b/rktwebview_qt/rktwebview.cpp index 3e6d10a..3bba070 100644 --- a/rktwebview_qt/rktwebview.cpp +++ b/rktwebview_qt/rktwebview.cpp @@ -2,13 +2,19 @@ #include #include #include +#ifdef _WIN32 +#include +#include +#else #include +#include +#endif #include #include "rktwebview.h" #include "rkt_protocol.h" -#include #include "shmqueue.h" #include "json.h" +#include "utils.h" #define SHM_SIZE (10 * 1024 * 1024) // 10MB #define COMMAND_SLOT 1 @@ -28,14 +34,26 @@ typedef struct { ShmQueue *command_queue; ShmQueue *command_result_queue; ShmQueue *event_queue; +#ifdef _WIN32 + HANDLE rkt_webview_prg_pid; +#else pid_t rkt_webview_prg_pid; +#endif + bool rkt_webview_prg_started; + bool valid; } Handle_t; Handle_t *handler = nullptr; static bool fileExists(const char *filename) { +#ifdef _WIN32 + DWORD dwAttrib = GetFileAttributes(filename); + return (dwAttrib != INVALID_FILE_ATTRIBUTES && + !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +#else return access(filename, X_OK) != -1; +#endif } uint64_t current_ms() { @@ -45,29 +63,62 @@ uint64_t current_ms() { bool runRktWebview(Handle_t *handler) { - // run rktwebview_prg using the environment variable RKT_WEBVIEW_PRG -#ifdef _WIN32 -#else char *rkt_webview_prg_path = getenv("RKT_WEBVIEW_PRG"); if (rkt_webview_prg_path == nullptr) { - fprintf(stderr, "RKT_WEBVIEW_PRG environment variable not set, cannot start webview program\n"); + fprintf(stderr, "RKT_WEBVIEW_PRG environment variable not set, cannot start webview program\n");fflush(stderr); return false; } if (!fileExists(rkt_webview_prg_path)) { - fprintf(stderr, "%s does not exist or is not executable\n", rkt_webview_prg_path); + fprintf(stderr, "%s does not exist or is not executable\n", rkt_webview_prg_path);fflush(stderr); return false; } + std::string path = basedir(rkt_webview_prg_path); + char shm_size_str[30]; char command_slot[10]; char command_result_slot[10]; char event_slot[10]; - sprintf(shm_size_str, "%ld", handler->shm_size); + sprintf(shm_size_str, "%d", static_cast(handler->shm_size)); sprintf(command_slot, "%d", COMMAND_SLOT); sprintf(command_result_slot, "%d", COMMAND_RESULT_SLOT); sprintf(event_slot, "%d", EVENT_SLOT); + // run rktwebview_prg using the environment variable RKT_WEBVIEW_PRG +#ifdef _WIN32 + + //STARTUPINFO si; + //PROCESS_INFORMATION pi; + //ZeroMemory( &si, sizeof(si) ); + //si.cb = sizeof(si); + //ZeroMemory( &pi, sizeof(pi) ); + + std::string cmdargs = std::string("") + handler->name + " " + shm_size_str + " " + command_slot + " " + command_result_slot + " " + event_slot; + std::string exe = std::string(rkt_webview_prg_path); + + const char *td = getenv("TEMP"); + if (td == nullptr) { td = "C:\\"; } + std::string tmpdir = td; + std::string logfile = tmpdir + "\\" + "rktwebview.log"; //handler->name + ".log"; + std::string errfile = tmpdir + "\\" + "rktwebview.err"; + std::string redirect = " ^>" + logfile + " 2^>" + errfile; + std::string cmdline = "start /b \"\" cmd /c \"" + exe + " " + cmdargs + " " + /*redirect*/ + "\"" + redirect; + + char *cmdline_str = const_cast(cmdline.c_str()); + + auto cwd = std::filesystem::current_path(); + std::filesystem::current_path(path); + int r = system(cmdline_str); + std::filesystem::current_path(cwd); + + //CreateProcessA(NULL, cmdline_str, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, path.c_str(), &si, &pi); + handler->rkt_webview_prg_pid = 0; + if (r != 0) { + fprintf(stderr, "Cannot create process '%s' (error = %ld)\n", cmdline_str, GetLastError());fflush(stderr); + } + return (r == 0); +#else char *argv[] = { rkt_webview_prg_path, const_cast(handler->name.c_str()), shm_size_str, command_slot, command_result_slot, event_slot, nullptr }; int r = posix_spawn(&handler->rkt_webview_prg_pid, rkt_webview_prg_path, nullptr, nullptr, argv, environ); @@ -108,18 +159,21 @@ void rkt_webview_cleanup() handler = nullptr; } */ - fprintf(stderr, "Sending quit message\n"); - handler->command_queue->enqueue(CMD_QUIT); - fprintf(stderr, "Message sent\n"); - bool stopped = false; - while(!stopped) { - int cmd; - std::string s; - fprintf(stderr, "Getting result of quit message\n"); - handler->command_result_queue->dequeue(cmd, s, true); - fprintf(stderr, "got %d\n", cmd); - if (cmd == RESULT_QUIT) { - stopped = true; + + if (handler->valid) { + fprintf(stderr, "Sending quit message\n");fflush(stderr); + handler->command_queue->enqueue(CMD_QUIT); + fprintf(stderr, "Message sent\n");fflush(stderr); + bool stopped = false; + while(!stopped) { + int cmd; + std::string s; + fprintf(stderr, "Getting result of quit message\n");fflush(stderr); + handler->command_result_queue->dequeue(cmd, s, true); + fprintf(stderr, "got %d\n", cmd);fflush(stderr); + if (cmd == RESULT_QUIT) { + stopped = true; + } } } @@ -140,16 +194,23 @@ void rkt_webview_init() char buf[1024]; #ifdef DEBUG sprintf(buf, "rktwebview-dbg"); +#else +#ifdef _WIN32 + DWORD p = GetCurrentProcessId(); + sprintf(buf, "rktwebview-%ld", p); #else pid_t p = getpid(); sprintf(buf, "rktwebview-%x", p); +#endif #endif handler = new Handle_t; + handler->valid = true; handler->name = buf; handler->shm_size = SHM_SIZE; handler->shm = new Shm(handler->name.data(), handler->shm_size, true); + if (!handler->shm->isValid()) { handler->valid = false; } handler->command_queue = new ShmQueue(handler->shm, COMMAND_SLOT, true); handler->command_result_queue = new ShmQueue(handler->shm, COMMAND_RESULT_SLOT, true); handler->event_queue = new ShmQueue(handler->shm, EVENT_SLOT, true); @@ -157,6 +218,7 @@ void rkt_webview_init() // Start rktwebview_prg application with the right information #ifndef DEBUG handler->rkt_webview_prg_started = runRktWebview(handler); + if (!handler->rkt_webview_prg_started) { handler->valid = false; } #endif } } @@ -164,7 +226,7 @@ void rkt_webview_init() bool rkt_webview_valid(rktwebview_t wv) { rkt_webview_init(); - if (handler != nullptr && handler->rkt_webview_prg_started) { + if (handler != nullptr && handler->valid) { handler->command_queue->enqueue(CMD_HANDLE_IS_VALID); int result; std::string json_result; @@ -175,9 +237,21 @@ bool rkt_webview_valid(rktwebview_t wv) } } +static inline bool validHandle() +{ + return (handler != nullptr) && handler->valid; +} + +#define FAIL_HANDLE if (!validHandle()) { return result_t::invalid_handle; } +#define FAIL_CONTEXT if (!validHandle()) { return 0; } +#define FAIL_WV if (!validHandle()) { return 0; } +#define NOOP_HANDLE if (!validHandle()) { return; } +#define FAIL_CALL_JS if (!validHandle()) { return nullptr; } + rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js, const char *optional_server_cert_pem) { rkt_webview_init(); + FAIL_CONTEXT JSON j; @@ -200,6 +274,8 @@ rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js, const char int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent) { rkt_webview_init(); + FAIL_WV + JSON j; j["context"] = context; j["parent"] = parent; @@ -216,6 +292,7 @@ int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent) void rkt_webview_close(rktwebview_t wv) { rkt_webview_init(); + NOOP_HANDLE JSON j; j["wv"] = wv; @@ -224,6 +301,7 @@ void rkt_webview_close(rktwebview_t wv) #define CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, key4, val4) \ rkt_webview_init(); \ + FAIL_HANDLE \ JSON j; \ j["wv"] = wv; \ j[key] = val; \ @@ -268,6 +346,7 @@ result_t rkt_webview_run_js(rktwebview_t wv, const char *js) rkt_data_t *rkt_webview_call_js(rktwebview_t wv, const char *js) { rkt_webview_init(); + FAIL_CALL_JS JSON j; j["wv"] = wv; @@ -380,6 +459,7 @@ result_t rkt_webview_file_save(rktwebview_t w, const char *title, const char *ba void rkt_webview_set_ou_token(rktwebview_t wv, const char *token) { rkt_webview_init(); + NOOP_HANDLE JSON j; j["wv"] = wv; @@ -401,7 +481,7 @@ void rkt_webview_free_data(rkt_data_t *d) free(d->data.js_result.value); free(d); } else { - fprintf(stderr, "UNEXPECTED: data kind %d cannot be freed\n", d->kind); + fprintf(stderr, "UNEXPECTED: data kind %d cannot be freed\n", d->kind);fflush(stderr); } } @@ -440,7 +520,7 @@ rkt_data_t *rkt_webview_get_event() memcpy(d->data.event.event, data.c_str(), ds); d->data.event.event[ds] = '\0'; d->data.event.wv = wv; - fprintf(stderr, "event: %d - '%s'\n", d->data.event.wv, d->data.event.event); + //fprintf(stderr, "event: %d - '%s'\n", d->data.event.wv, d->data.event.event);fflush(stderr); return d; } else { return nullptr; diff --git a/rktwebview_qt/rktwebview_qt.cpp b/rktwebview_qt/rktwebview_qt.cpp index 31d9afc..dd99de1 100644 --- a/rktwebview_qt/rktwebview_qt.cpp +++ b/rktwebview_qt/rktwebview_qt.cpp @@ -31,6 +31,7 @@ void Rktwebview_qt::processCommand(Command *cmd) switch(cmd->cmd) { case COMMAND_QUIT: { // Quit application _app->quit(); + cmd->done = true; } break; case COMMAND_NEW_CONTEXT: { @@ -640,6 +641,8 @@ void Rktwebview_qt::rktQuit() { Command c(COMMAND_QUIT); postCommand(&c); + + while(!c.done) { doEvents(); } } result_t Rktwebview_qt::fileDlg(rktwebview_t w, const char *title, const char *base, const char *filters,QFileDialog::FileMode mode, QFileDialog::AcceptMode am, QString evt_ok, QString evt_cancel) diff --git a/rktwebview_qt/rktwebview_test.cpp b/rktwebview_qt/rktwebview_test.cpp index eca74bb..9075755 100644 --- a/rktwebview_qt/rktwebview_test.cpp +++ b/rktwebview_qt/rktwebview_test.cpp @@ -1,16 +1,34 @@ #include "rktwebview.h" #include + +#ifdef _WIN32 +#include +#else #include +#endif +#include "utils.h" int main(int argc, char *argv[]) -{std::string me = argv[0]; - int idx = me.rfind("/"); +{ + std::string me = argv[0]; - std::string loc = me.substr(0, idx); + std::string loc = basedir(me); +#ifdef _WIN32 + std::string prg = loc + "\\rktwebview_prg.exe"; + SetDllDirectoryA("C:\\Qt\\6.10.2\\msvc2022_64\\bin"); +#else std::string prg = loc + "/rktwebview_prg"; +#endif +#ifdef _WIN32 + { + std::string e = std::string("RKT_WEBVIEW_PRG=") + prg; + _putenv(e.c_str()); + } +#else setenv("RKT_WEBVIEW_PRG", prg.c_str(), true); setenv("LD_LIBRARY_PATH", loc.c_str(), true); +#endif int context = rkt_webview_new_context("", nullptr); @@ -24,9 +42,13 @@ int main(int argc, char *argv[]) rkt_data_t *d = rkt_webview_get_event(); rkt_webview_free_data(d); } +#ifdef _WIN32 + Sleep(10); +#else sleep(10); +#endif rkt_webview_close(wv); rkt_webview_cleanup(); -} \ No newline at end of file +} diff --git a/rktwebview_qt/rktwebview_types.h b/rktwebview_qt/rktwebview_types.h index 51dcaea..e0b1e19 100644 --- a/rktwebview_qt/rktwebview_types.h +++ b/rktwebview_qt/rktwebview_types.h @@ -30,7 +30,8 @@ typedef enum { choose_dir_failed = 14, open_file_failed = 15, save_file_failed = 16, - failed = 17 + failed = 17, + invalid_handle = 18 } result_t; typedef struct { diff --git a/rktwebview_qt/shm.cpp b/rktwebview_qt/shm.cpp index e2b4b59..1a506a2 100644 --- a/rktwebview_qt/shm.cpp +++ b/rktwebview_qt/shm.cpp @@ -1,17 +1,6 @@ #include "shm.h" - -#ifdef __linux - -#include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include typedef struct __shm_item__ { @@ -22,35 +11,26 @@ typedef struct __shm_item__ { } ShmItem; -class ShmApi +class ShmApiBase { -private: - int _shm_fd; - size_t _size; - bool _owner; - void *_mem; - sem_t *_sem; +protected: + char *_mem; - char *_mem_name; - char *_sem_name; - - size_t *_used; + int *_used; ShmPlace *_slots; ShmPlace *_first; ShmPlace *_free_list; + char *_mem_name; + char *_sem_name; + int _in_critical; - -private: - void cleanup() { - // We don't need to do anything here. - - } + size_t _size; + bool _owner; public: - ShmSem *makeSem(const char *name, bool owner) { - return new ShmSem(name, owner); - } + virtual void enterCritical() = 0; + virtual void leaveCritical() = 0; public: int slot(int s) { @@ -71,7 +51,7 @@ public: if (place == SHM_NULL) { *p = nullptr; } else { - *p = reinterpret_cast(reinterpret_cast(_mem) + place); + *p = reinterpret_cast(_mem + place); } } @@ -81,7 +61,7 @@ public: return nullptr; } - return reinterpret_cast(_mem) + place; + return _mem + place; } public: @@ -125,7 +105,7 @@ public: } else { ShmPlace p_i = *_used; i = reinterpret_cast(reinterpret_cast(_mem) + p_i); - size_t u = *_used + sizeof(ShmItem) + bytes; + int u = static_cast(*_used + sizeof(ShmItem) + bytes); if (u >= _size) { place = SHM_NULL; @@ -185,6 +165,66 @@ public: leaveCritical(); } +public: + ShmSem *makeSem(const char *name, bool owner) { + return new ShmSem(name, owner); + } + +public: + ShmApiBase(const char *name, size_t size, bool owner) { + char *buf = reinterpret_cast(malloc(strlen(name) + 50)); + sprintf(buf, "sem_%s", name); + _sem_name = _strdup(buf); + _mem_name = _strdup(name); + ::free(buf); + + _owner = owner; + + _size = size; + + _used = nullptr; + _slots = nullptr; + _first = nullptr; + _free_list = nullptr; + _mem = nullptr; + + _in_critical = 0; + } + + virtual ~ShmApiBase() + { + ::free(_sem_name); + ::free(_mem_name); + } +}; + +#ifdef __linux + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class ShmApi : public ShmApiBase +{ +private: + int _shm_fd; + sem_t *_sem; + +private: + void cleanup() { + // We don't need to do anything here. + + } + +public: void enterCritical() { if (_in_critical > 0) { _in_critical++; @@ -204,19 +244,17 @@ public: } public: - ShmApi(const char *name, size_t size, bool owner) { - - { - char buf[strlen(name) + 50]; - sprintf(buf, "sem_%s", name); - _sem_name = strdup(buf); - _mem_name = strdup(name); - } + bool isValid() { + return true; + } +public: + ShmApi(const char *name, size_t size, bool owner) : ShmApiBase(name, size, owner) + { size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS; size += slots_size; - if (owner) { + if (_owner) { _sem = sem_open(_sem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0); _shm_fd = shm_open(name, O_CREAT | O_RDWR, 0600); ftruncate(_shm_fd, size); @@ -224,21 +262,18 @@ public: _sem = sem_open(_sem_name, O_RDWR, S_IRUSR | S_IWUSR, 0); _shm_fd = shm_open(name, O_RDWR, 0600); } - _size = size; _mem = mmap(nullptr, _size, PROT_READ|PROT_WRITE, MAP_SHARED, _shm_fd, 0); - _slots = reinterpret_cast (reinterpret_cast(_mem) + sizeof(size_t) + sizeof(ShmPlace) + sizeof(ShmPlace)); - _used = reinterpret_cast(_mem); + _slots = reinterpret_cast (_mem + sizeof(int) + sizeof(ShmPlace) + sizeof(ShmPlace)); + _used = reinterpret_cast(_mem); - _first = reinterpret_cast(reinterpret_cast(_mem) + sizeof(size_t)); - _free_list = reinterpret_cast(reinterpret_cast(_mem) + sizeof(size_t) + sizeof(ShmPlace)); - - _owner = owner; + _first = reinterpret_cast(_mem + sizeof(int)); + _free_list = reinterpret_cast(_mem + sizeof(int) + sizeof(ShmPlace)); if (_owner) { *_first = SHM_NULL; *_free_list = SHM_NULL; - *_used = sizeof(size_t) + sizeof(ShmItem *) + sizeof(ShmItem *) + slots_size; + *_used = sizeof(int) + sizeof(ShmItem *) + sizeof(ShmItem *) + slots_size; sem_post(_sem); } @@ -254,44 +289,241 @@ public: shm_unlink(_mem_name); sem_unlink(_sem_name); } - ::free(_mem_name); - ::free(_sem_name); } }; + +class ShmSemApi { + private: + sem_t *_sem; + char *_name; + bool _owner; + + public: + void post() { + sem_post(_sem); + } + + void wait() { + int r = sem_wait(_sem); + if (r != 0) { + fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno)); + } + } + + bool trywait() { + int r = sem_trywait(reinterpret_cast(_sem)); + if (r != 0 && r != EAGAIN) { + fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno)); + } + + return (r == 0); + } + + public: + ShmSemApi(const char *n, bool owner) { + _name = strdup(n); + + sem_t *s; + if (owner) { + s = sem_open(n, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0); + } else { + s = sem_open(n, O_RDWR, S_IRUSR | S_IWUSR, 0); + } + _sem = s; + _owner = owner; + } + + virtual ~ShmSemApi() { + sem_close(_sem); + if (_owner) { + sem_unlink(_name); + } + free(_name); + } + }; +}; + +public: +}; #endif #ifdef _WIN32 -class ShmApi +#include + +class ShmApi : public ShmApiBase { +private: + HANDLE _shm_handle; + HANDLE _sem_handle; + bool _valid; + public: - ShmApi(const char *name, size_t size, bool owner) + ShmApi(const char *name, size_t size, bool owner) : ShmApiBase(name, size, owner) { + size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS; + size += slots_size; + + _valid = true; + if (_owner) { + _shm_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + static_cast(size), // size must be smaller < 2GB + name); + + if (_shm_handle == NULL) { + fprintf(stderr, "Cannot create shared memory with name %s and size %lld\n", name, size); + _valid = false; + } + } else { + _shm_handle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, + FALSE, + name); + if (_shm_handle == NULL) { + fprintf(stderr, "Cannot open shared memory with name %s\n", name); + _valid = false; + } + } + + if (_valid) { + _mem = static_cast(MapViewOfFile(_shm_handle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + size)); + if (_mem == NULL) { + fprintf(stderr, "Cannot map shared memory, errorcode = %ld\n", GetLastError()); + _valid = false; + CloseHandle(_shm_handle); + } + } + + if (_valid) { + if (_owner) { + _sem_handle = CreateSemaphoreA(NULL, + 1, + 10000, + _sem_name + ); + } else { + _sem_handle = OpenSemaphoreA(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, FALSE, _sem_name); + } + if (_sem_handle == NULL) { + fprintf(stderr, "Cannot create or open semaphore with name '%s' (%ld)\n", _sem_name, GetLastError()); + UnmapViewOfFile(_mem); + CloseHandle(_shm_handle); + _valid = false; + } + } + + if (_valid) { + _slots = reinterpret_cast (_mem + sizeof(int) + sizeof(ShmPlace) + sizeof(ShmPlace)); + _used = reinterpret_cast(_mem); + + _first = reinterpret_cast(_mem + sizeof(int)); + _free_list = reinterpret_cast(_mem + sizeof(int) + sizeof(ShmPlace)); + + if (_owner) { + *_first = SHM_NULL; + *_free_list = SHM_NULL; + *_used = sizeof(int) + sizeof(ShmItem *) + sizeof(ShmItem *) + slots_size; + } + } } ~ShmApi() { + if (_valid) { + UnmapViewOfFile(_mem); + CloseHandle(_shm_handle); + CloseHandle(_sem_handle); + } + } + + bool isValid() { + return _valid; } void enterCritical() { - + if (_in_critical > 0) { + _in_critical++; + } else { + WaitForSingleObject(_sem_handle, INFINITE); + _in_critical = 1; + } } void leaveCritical() { - + if (_in_critical > 1) { + _in_critical--; + } else { + _in_critical = 0; + ReleaseSemaphore(_sem_handle, 1, NULL); + } } - void *alloc(size_t bytes) + ShmSem *sem(const char *name, bool owner) { - return malloc(bytes); + return nullptr; + } +}; + + +class ShmSemApi { +private: + HANDLE _sem; + char *_name; + bool _owner; + +public: + void post() { + ReleaseSemaphore(_sem, 1, NULL); } - void free(void *mem) - { - free(mem); + void wait() { + DWORD r = WaitForSingleObject(_sem, INFINITE); + if (r != WAIT_OBJECT_0) { + fprintf(stderr, "sem_wait error: %ld\n", r); + } } -} + + bool trywait() { + DWORD r = WaitForSingleObject(_sem , 0); + if (r != WAIT_OBJECT_0 && r != WAIT_TIMEOUT) { + fprintf(stderr, "sem_wait error: %ld\n", r); + } + return r == WAIT_OBJECT_0; + } + +public: + ShmSemApi(const char *n, bool owner) { + _name = _strdup(n); + + if (owner) { + _sem = CreateSemaphoreA(NULL, + 0, + 10000, + _name); + } else { + _sem = OpenSemaphoreA(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, FALSE, _name); + } + + if (_sem == NULL) { + fprintf(stderr, "Cannot create or open semaphore with name '%s'\n", _name); + } + _owner = owner; + } + + virtual ~ShmSemApi() { + if (_sem != NULL) { + CloseHandle(_sem); + } + } +}; + #endif @@ -326,6 +558,11 @@ ShmSem *Shm::sem(const char *name, bool owner) return _shm_api->makeSem(name, owner); } +bool Shm::isValid() +{ + return _shm_api->isValid(); +} + const char *Shm::name() { return _shm_api->name(); @@ -352,44 +589,22 @@ Shm::~Shm() } - void ShmSem::post() { - sem_post(reinterpret_cast(_sem)); + _api->post(); } void ShmSem::wait() { - int r = sem_wait(reinterpret_cast(_sem)); - if (r != 0) { - fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno)); - } + _api->wait(); } bool ShmSem::trywait() { - int r = sem_trywait(reinterpret_cast(_sem)); - if (r != 0 && r != EAGAIN) { - fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno)); - } - - return (r == 0); + return _api->trywait(); } ShmSem::ShmSem(const char *n, bool owner) { - _name = strdup(n); - - sem_t *s; - if (owner) { - s = sem_open(n, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0); - } else { - s = sem_open(n, O_RDWR, S_IRUSR | S_IWUSR, 0); - } - _sem = reinterpret_cast(s); - _owner = owner; + _api = new ShmSemApi(n, owner); } ShmSem::~ShmSem() { - sem_close(reinterpret_cast(_sem)); - if (_owner) { - sem_unlink(_name); - } - free(_name); + delete _api; } diff --git a/rktwebview_qt/shm.h b/rktwebview_qt/shm.h index 1b567df..8de1d08 100644 --- a/rktwebview_qt/shm.h +++ b/rktwebview_qt/shm.h @@ -4,6 +4,7 @@ #include class ShmApi; +class ShmSemApi; typedef int ShmPlace; typedef int ShmSlot; @@ -12,9 +13,7 @@ typedef int ShmSlot; class ShmSem { private: - void *_sem; - char *_name; - bool _owner; + ShmSemApi *_api; public: void post(); @@ -44,6 +43,9 @@ public: public: ShmSem *sem(const char *name, bool owner); +public: + bool isValid(); + public: const char *name(); diff --git a/rktwebview_qt/utils.h b/rktwebview_qt/utils.h new file mode 100644 index 0000000..b8284c3 --- /dev/null +++ b/rktwebview_qt/utils.h @@ -0,0 +1,29 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +inline std::string basedir(const std::string &path) +{ + int idx1 = path.rfind("/"); + int idx2 = path.rfind("\\"); + std::string r; + if (idx1 == std::string::npos && idx2 == std::string::npos) { + r = ""; + } else { + int idx; + if (idx1 == std::string::npos) { + idx = idx2; + } else if (idx2 == std::string::npos) { + idx = idx1; + } else if (idx1 < idx2) { + idx = idx2; + } else { + idx = idx1; + } + r = path.substr(0, idx); + } + return r; +} + +#endif // UTILS_H