windows....sigh

This commit is contained in:
2026-03-26 12:08:55 +01:00
parent 8fe7e726a4
commit b23365b05f
15 changed files with 499 additions and 128 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+16
View File
@@ -142,7 +142,12 @@
(putenv "QTWEBENGINE_LOCALES_PATH" (putenv "QTWEBENGINE_LOCALES_PATH"
(path->string (build-path os-lib-dir "translations" "qtwebengine_locales"))) (path->string (build-path os-lib-dir "translations" "qtwebengine_locales")))
(putenv "RKT_WEBVIEW_PRG" (putenv "RKT_WEBVIEW_PRG"
(let ((p
(path->string (build-path os-lib-dir rktwebview-prg))) (path->string (build-path os-lib-dir rktwebview-prg)))
)
(displayln p)
p
))
(when (eq? os 'linux) (when (eq? os 'linux)
(putenv "QT_QPA_PLATFORM" "xcb") (putenv "QT_QPA_PLATFORM" "xcb")
(putenv "LD_LIBRARY_PATH" (putenv "LD_LIBRARY_PATH"
@@ -222,8 +227,19 @@
eval_js_failed = 3 eval_js_failed = 3
no_devtools_on_platform = 4 no_devtools_on_platform = 4
no_delegate_for_context = 5 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 move_failed = 12
resize_failed = 13 resize_failed = 13
choose_dir_failed = 14
open_file_failed = 15
save_file_failed = 16
failed = 17
invalid_handle = 18
) )
) )
) )
+1
View File
@@ -21,6 +21,7 @@ add_library(rktwebview SHARED
rkt_protocol.h rkt_protocol.h
rktwebview_types.h rktwebview_types.h
json.cpp json.h json.cpp json.h
utils.h
) )
add_executable(rktwebview_prg add_executable(rktwebview_prg
+9 -7
View File
@@ -62,8 +62,10 @@ int main(int argc, char *argv[])
{ {
const char *me = argv[0]; const char *me = argv[0];
fprintf(stderr, "%s runs\n", argv[0]);fflush(stderr);
if (argc < 6) { 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); exit(1);
} }
@@ -78,11 +80,11 @@ int main(int argc, char *argv[])
int res_slot = atoi(res_slot_str); int res_slot = atoi(res_slot_str);
int evt_slot = atoi(evt_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 %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); 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)) { 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); exit(2);
} }
@@ -98,10 +100,10 @@ int main(int argc, char *argv[])
handler->webview_handler->initApp(); handler->webview_handler->initApp();
handler->webview_handler->execApp(); handler->webview_handler->execApp();
fprintf(stderr, "waiting for thread to end\n"); fprintf(stderr, "waiting for thread to end\n");fflush(stderr);
handler->wait(); handler->wait();
fprintf(stderr, "cleaning up shm\n"); fprintf(stderr, "cleaning up shm\n");fflush(stderr);
delete handler->webview_handler; delete handler->webview_handler;
delete handler->command_queue; delete handler->command_queue;
@@ -318,7 +320,7 @@ void Handler::run()
} }
break; break;
default: { default: {
fprintf(stderr, "Unknown command: %d\n", cmd); fprintf(stderr, "Unknown command: %d\n", cmd);fflush(stderr);
} }
} }
} }
+94 -14
View File
@@ -2,13 +2,19 @@
#include <chrono> #include <chrono>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <filesystem>
#else
#include <unistd.h> #include <unistd.h>
#include <spawn.h>
#endif
#include <fcntl.h> #include <fcntl.h>
#include "rktwebview.h" #include "rktwebview.h"
#include "rkt_protocol.h" #include "rkt_protocol.h"
#include <spawn.h>
#include "shmqueue.h" #include "shmqueue.h"
#include "json.h" #include "json.h"
#include "utils.h"
#define SHM_SIZE (10 * 1024 * 1024) // 10MB #define SHM_SIZE (10 * 1024 * 1024) // 10MB
#define COMMAND_SLOT 1 #define COMMAND_SLOT 1
@@ -28,14 +34,26 @@ typedef struct {
ShmQueue *command_queue; ShmQueue *command_queue;
ShmQueue *command_result_queue; ShmQueue *command_result_queue;
ShmQueue *event_queue; ShmQueue *event_queue;
#ifdef _WIN32
HANDLE rkt_webview_prg_pid;
#else
pid_t rkt_webview_prg_pid; pid_t rkt_webview_prg_pid;
#endif
bool rkt_webview_prg_started; bool rkt_webview_prg_started;
bool valid;
} Handle_t; } Handle_t;
Handle_t *handler = nullptr; Handle_t *handler = nullptr;
static bool fileExists(const char *filename) { 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; return access(filename, X_OK) != -1;
#endif
} }
uint64_t current_ms() { uint64_t current_ms() {
@@ -45,29 +63,62 @@ uint64_t current_ms() {
bool runRktWebview(Handle_t *handler) 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"); char *rkt_webview_prg_path = getenv("RKT_WEBVIEW_PRG");
if (rkt_webview_prg_path == nullptr) { 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; return false;
} }
if (!fileExists(rkt_webview_prg_path)) { 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; return false;
} }
std::string path = basedir(rkt_webview_prg_path);
char shm_size_str[30]; char shm_size_str[30];
char command_slot[10]; char command_slot[10];
char command_result_slot[10]; char command_result_slot[10];
char event_slot[10]; char event_slot[10];
sprintf(shm_size_str, "%ld", handler->shm_size); sprintf(shm_size_str, "%d", static_cast<int>(handler->shm_size));
sprintf(command_slot, "%d", COMMAND_SLOT); sprintf(command_slot, "%d", COMMAND_SLOT);
sprintf(command_result_slot, "%d", COMMAND_RESULT_SLOT); sprintf(command_result_slot, "%d", COMMAND_RESULT_SLOT);
sprintf(event_slot, "%d", EVENT_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<char *>(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<char *>(handler->name.c_str()), shm_size_str, command_slot, command_result_slot, event_slot, nullptr }; char *argv[] = { rkt_webview_prg_path, const_cast<char *>(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); int r = posix_spawn(&handler->rkt_webview_prg_pid, rkt_webview_prg_path, nullptr, nullptr, argv, environ);
@@ -108,20 +159,23 @@ void rkt_webview_cleanup()
handler = nullptr; handler = nullptr;
} }
*/ */
fprintf(stderr, "Sending quit message\n");
if (handler->valid) {
fprintf(stderr, "Sending quit message\n");fflush(stderr);
handler->command_queue->enqueue(CMD_QUIT); handler->command_queue->enqueue(CMD_QUIT);
fprintf(stderr, "Message sent\n"); fprintf(stderr, "Message sent\n");fflush(stderr);
bool stopped = false; bool stopped = false;
while(!stopped) { while(!stopped) {
int cmd; int cmd;
std::string s; std::string s;
fprintf(stderr, "Getting result of quit message\n"); fprintf(stderr, "Getting result of quit message\n");fflush(stderr);
handler->command_result_queue->dequeue(cmd, s, true); handler->command_result_queue->dequeue(cmd, s, true);
fprintf(stderr, "got %d\n", cmd); fprintf(stderr, "got %d\n", cmd);fflush(stderr);
if (cmd == RESULT_QUIT) { if (cmd == RESULT_QUIT) {
stopped = true; stopped = true;
} }
} }
}
delete handler->event_queue; delete handler->event_queue;
delete handler->command_result_queue; delete handler->command_result_queue;
@@ -140,16 +194,23 @@ void rkt_webview_init()
char buf[1024]; char buf[1024];
#ifdef DEBUG #ifdef DEBUG
sprintf(buf, "rktwebview-dbg"); sprintf(buf, "rktwebview-dbg");
#else
#ifdef _WIN32
DWORD p = GetCurrentProcessId();
sprintf(buf, "rktwebview-%ld", p);
#else #else
pid_t p = getpid(); pid_t p = getpid();
sprintf(buf, "rktwebview-%x", p); sprintf(buf, "rktwebview-%x", p);
#endif
#endif #endif
handler = new Handle_t; handler = new Handle_t;
handler->valid = true;
handler->name = buf; handler->name = buf;
handler->shm_size = SHM_SIZE; handler->shm_size = SHM_SIZE;
handler->shm = new Shm(handler->name.data(), handler->shm_size, true); 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_queue = new ShmQueue(handler->shm, COMMAND_SLOT, true);
handler->command_result_queue = new ShmQueue(handler->shm, COMMAND_RESULT_SLOT, true); handler->command_result_queue = new ShmQueue(handler->shm, COMMAND_RESULT_SLOT, true);
handler->event_queue = new ShmQueue(handler->shm, EVENT_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 // Start rktwebview_prg application with the right information
#ifndef DEBUG #ifndef DEBUG
handler->rkt_webview_prg_started = runRktWebview(handler); handler->rkt_webview_prg_started = runRktWebview(handler);
if (!handler->rkt_webview_prg_started) { handler->valid = false; }
#endif #endif
} }
} }
@@ -164,7 +226,7 @@ void rkt_webview_init()
bool rkt_webview_valid(rktwebview_t wv) bool rkt_webview_valid(rktwebview_t wv)
{ {
rkt_webview_init(); rkt_webview_init();
if (handler != nullptr && handler->rkt_webview_prg_started) { if (handler != nullptr && handler->valid) {
handler->command_queue->enqueue(CMD_HANDLE_IS_VALID); handler->command_queue->enqueue(CMD_HANDLE_IS_VALID);
int result; int result;
std::string json_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_wv_context_t rkt_webview_new_context(const char *boilerplate_js, const char *optional_server_cert_pem)
{ {
rkt_webview_init(); rkt_webview_init();
FAIL_CONTEXT
JSON j; 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) int rkt_webview_create(rkt_wv_context_t context, rktwebview_t parent)
{ {
rkt_webview_init(); rkt_webview_init();
FAIL_WV
JSON j; JSON j;
j["context"] = context; j["context"] = context;
j["parent"] = parent; 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) void rkt_webview_close(rktwebview_t wv)
{ {
rkt_webview_init(); rkt_webview_init();
NOOP_HANDLE
JSON j; JSON j;
j["wv"] = wv; 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) \ #define CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, key4, val4) \
rkt_webview_init(); \ rkt_webview_init(); \
FAIL_HANDLE \
JSON j; \ JSON j; \
j["wv"] = wv; \ j["wv"] = wv; \
j[key] = val; \ 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_data_t *rkt_webview_call_js(rktwebview_t wv, const char *js)
{ {
rkt_webview_init(); rkt_webview_init();
FAIL_CALL_JS
JSON j; JSON j;
j["wv"] = wv; 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) void rkt_webview_set_ou_token(rktwebview_t wv, const char *token)
{ {
rkt_webview_init(); rkt_webview_init();
NOOP_HANDLE
JSON j; JSON j;
j["wv"] = wv; j["wv"] = wv;
@@ -401,7 +481,7 @@ void rkt_webview_free_data(rkt_data_t *d)
free(d->data.js_result.value); free(d->data.js_result.value);
free(d); free(d);
} else { } 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); memcpy(d->data.event.event, data.c_str(), ds);
d->data.event.event[ds] = '\0'; d->data.event.event[ds] = '\0';
d->data.event.wv = wv; 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; return d;
} else { } else {
return nullptr; return nullptr;
+3
View File
@@ -31,6 +31,7 @@ void Rktwebview_qt::processCommand(Command *cmd)
switch(cmd->cmd) { switch(cmd->cmd) {
case COMMAND_QUIT: { // Quit application case COMMAND_QUIT: { // Quit application
_app->quit(); _app->quit();
cmd->done = true;
} }
break; break;
case COMMAND_NEW_CONTEXT: { case COMMAND_NEW_CONTEXT: {
@@ -640,6 +641,8 @@ void Rktwebview_qt::rktQuit()
{ {
Command c(COMMAND_QUIT); Command c(COMMAND_QUIT);
postCommand(&c); 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) 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)
+25 -3
View File
@@ -1,16 +1,34 @@
#include "rktwebview.h" #include "rktwebview.h"
#include <string> #include <string>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h> #include <unistd.h>
#endif
#include "utils.h"
int main(int argc, char *argv[]) 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"; 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("RKT_WEBVIEW_PRG", prg.c_str(), true);
setenv("LD_LIBRARY_PATH", loc.c_str(), true); setenv("LD_LIBRARY_PATH", loc.c_str(), true);
#endif
int context = rkt_webview_new_context("", nullptr); int context = rkt_webview_new_context("", nullptr);
@@ -24,7 +42,11 @@ int main(int argc, char *argv[])
rkt_data_t *d = rkt_webview_get_event(); rkt_data_t *d = rkt_webview_get_event();
rkt_webview_free_data(d); rkt_webview_free_data(d);
} }
#ifdef _WIN32
Sleep(10);
#else
sleep(10); sleep(10);
#endif
rkt_webview_close(wv); rkt_webview_close(wv);
+2 -1
View File
@@ -30,7 +30,8 @@ typedef enum {
choose_dir_failed = 14, choose_dir_failed = 14,
open_file_failed = 15, open_file_failed = 15,
save_file_failed = 16, save_file_failed = 16,
failed = 17 failed = 17,
invalid_handle = 18
} result_t; } result_t;
typedef struct { typedef struct {
+304 -89
View File
@@ -1,17 +1,6 @@
#include "shm.h" #include "shm.h"
#ifdef __linux
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <semaphore.h>
typedef struct __shm_item__ { typedef struct __shm_item__ {
@@ -22,35 +11,26 @@ typedef struct __shm_item__ {
} ShmItem; } ShmItem;
class ShmApi class ShmApiBase
{ {
private: protected:
int _shm_fd; char *_mem;
size_t _size;
bool _owner;
void *_mem;
sem_t *_sem;
char *_mem_name; int *_used;
char *_sem_name;
size_t *_used;
ShmPlace *_slots; ShmPlace *_slots;
ShmPlace *_first; ShmPlace *_first;
ShmPlace *_free_list; ShmPlace *_free_list;
char *_mem_name;
char *_sem_name;
int _in_critical; int _in_critical;
size_t _size;
private: bool _owner;
void cleanup() {
// We don't need to do anything here.
}
public: public:
ShmSem *makeSem(const char *name, bool owner) { virtual void enterCritical() = 0;
return new ShmSem(name, owner); virtual void leaveCritical() = 0;
}
public: public:
int slot(int s) { int slot(int s) {
@@ -71,7 +51,7 @@ public:
if (place == SHM_NULL) { if (place == SHM_NULL) {
*p = nullptr; *p = nullptr;
} else { } else {
*p = reinterpret_cast<T *>(reinterpret_cast<char *>(_mem) + place); *p = reinterpret_cast<T *>(_mem + place);
} }
} }
@@ -81,7 +61,7 @@ public:
return nullptr; return nullptr;
} }
return reinterpret_cast<char *>(_mem) + place; return _mem + place;
} }
public: public:
@@ -125,7 +105,7 @@ public:
} else { } else {
ShmPlace p_i = *_used; ShmPlace p_i = *_used;
i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_mem) + p_i); i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_mem) + p_i);
size_t u = *_used + sizeof(ShmItem) + bytes; int u = static_cast<int>(*_used + sizeof(ShmItem) + bytes);
if (u >= _size) { if (u >= _size) {
place = SHM_NULL; place = SHM_NULL;
@@ -185,6 +165,66 @@ public:
leaveCritical(); 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<char *>(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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <semaphore.h>
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() { void enterCritical() {
if (_in_critical > 0) { if (_in_critical > 0) {
_in_critical++; _in_critical++;
@@ -204,19 +244,17 @@ public:
} }
public: public:
ShmApi(const char *name, size_t size, bool owner) { bool isValid() {
return true;
{
char buf[strlen(name) + 50];
sprintf(buf, "sem_%s", name);
_sem_name = strdup(buf);
_mem_name = strdup(name);
} }
public:
ShmApi(const char *name, size_t size, bool owner) : ShmApiBase(name, size, owner)
{
size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS; size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS;
size += slots_size; size += slots_size;
if (owner) { if (_owner) {
_sem = sem_open(_sem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0); _sem = sem_open(_sem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0);
_shm_fd = shm_open(name, O_CREAT | O_RDWR, 0600); _shm_fd = shm_open(name, O_CREAT | O_RDWR, 0600);
ftruncate(_shm_fd, size); ftruncate(_shm_fd, size);
@@ -224,21 +262,18 @@ public:
_sem = sem_open(_sem_name, O_RDWR, S_IRUSR | S_IWUSR, 0); _sem = sem_open(_sem_name, O_RDWR, S_IRUSR | S_IWUSR, 0);
_shm_fd = shm_open(name, O_RDWR, 0600); _shm_fd = shm_open(name, O_RDWR, 0600);
} }
_size = size;
_mem = mmap(nullptr, _size, PROT_READ|PROT_WRITE, MAP_SHARED, _shm_fd, 0); _mem = mmap(nullptr, _size, PROT_READ|PROT_WRITE, MAP_SHARED, _shm_fd, 0);
_slots = reinterpret_cast <ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t) + sizeof(ShmPlace) + sizeof(ShmPlace)); _slots = reinterpret_cast <ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace) + sizeof(ShmPlace));
_used = reinterpret_cast<size_t *>(_mem); _used = reinterpret_cast<int *>(_mem);
_first = reinterpret_cast<ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t)); _first = reinterpret_cast<ShmPlace *>(_mem + sizeof(int));
_free_list = reinterpret_cast<ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t) + sizeof(ShmPlace)); _free_list = reinterpret_cast<ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace));
_owner = owner;
if (_owner) { if (_owner) {
*_first = SHM_NULL; *_first = SHM_NULL;
*_free_list = 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); sem_post(_sem);
} }
@@ -254,44 +289,241 @@ public:
shm_unlink(_mem_name); shm_unlink(_mem_name);
sem_unlink(_sem_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_t *>(_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 #endif
#ifdef _WIN32 #ifdef _WIN32
class ShmApi #include <windows.h>
class ShmApi : public ShmApiBase
{ {
private:
HANDLE _shm_handle;
HANDLE _sem_handle;
bool _valid;
public: 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<DWORD>(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<LPSTR>(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 <ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace) + sizeof(ShmPlace));
_used = reinterpret_cast<int *>(_mem);
_first = reinterpret_cast<ShmPlace *>(_mem + sizeof(int));
_free_list = reinterpret_cast<ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace));
if (_owner) {
*_first = SHM_NULL;
*_free_list = SHM_NULL;
*_used = sizeof(int) + sizeof(ShmItem *) + sizeof(ShmItem *) + slots_size;
}
}
} }
~ShmApi() ~ShmApi()
{ {
if (_valid) {
UnmapViewOfFile(_mem);
CloseHandle(_shm_handle);
CloseHandle(_sem_handle);
}
}
bool isValid() {
return _valid;
} }
void enterCritical() void enterCritical()
{ {
if (_in_critical > 0) {
_in_critical++;
} else {
WaitForSingleObject(_sem_handle, INFINITE);
_in_critical = 1;
}
} }
void leaveCritical() 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) void wait() {
{ DWORD r = WaitForSingleObject(_sem, INFINITE);
free(mem); 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 #endif
@@ -326,6 +558,11 @@ ShmSem *Shm::sem(const char *name, bool owner)
return _shm_api->makeSem(name, owner); return _shm_api->makeSem(name, owner);
} }
bool Shm::isValid()
{
return _shm_api->isValid();
}
const char *Shm::name() const char *Shm::name()
{ {
return _shm_api->name(); return _shm_api->name();
@@ -352,44 +589,22 @@ Shm::~Shm()
} }
void ShmSem::post() { void ShmSem::post() {
sem_post(reinterpret_cast<sem_t *>(_sem)); _api->post();
} }
void ShmSem::wait() { void ShmSem::wait() {
int r = sem_wait(reinterpret_cast<sem_t *>(_sem)); _api->wait();
if (r != 0) {
fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno));
}
} }
bool ShmSem::trywait() { bool ShmSem::trywait() {
int r = sem_trywait(reinterpret_cast<sem_t *>(_sem)); return _api->trywait();
if (r != 0 && r != EAGAIN) {
fprintf(stderr, "sem_wait error: %d, %s\n", errno, strerror(errno));
}
return (r == 0);
} }
ShmSem::ShmSem(const char *n, bool owner) { ShmSem::ShmSem(const char *n, bool owner) {
_name = strdup(n); _api = new ShmSemApi(n, owner);
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<void *>(s);
_owner = owner;
} }
ShmSem::~ShmSem() { ShmSem::~ShmSem() {
sem_close(reinterpret_cast<sem_t *>(_sem)); delete _api;
if (_owner) {
sem_unlink(_name);
}
free(_name);
} }
+5 -3
View File
@@ -4,6 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
class ShmApi; class ShmApi;
class ShmSemApi;
typedef int ShmPlace; typedef int ShmPlace;
typedef int ShmSlot; typedef int ShmSlot;
@@ -12,9 +13,7 @@ typedef int ShmSlot;
class ShmSem { class ShmSem {
private: private:
void *_sem; ShmSemApi *_api;
char *_name;
bool _owner;
public: public:
void post(); void post();
@@ -44,6 +43,9 @@ public:
public: public:
ShmSem *sem(const char *name, bool owner); ShmSem *sem(const char *name, bool owner);
public:
bool isValid();
public: public:
const char *name(); const char *name();
+29
View File
@@ -0,0 +1,29 @@
#ifndef UTILS_H
#define UTILS_H
#include <string>
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