aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrumeet <yuuta@yuuta.moe>2022-07-23 11:32:53 -0700
committerTrumeet <yuuta@yuuta.moe>2022-07-23 11:32:53 -0700
commit34c53bc3d396934df94431f7b76972180b1b0a8c (patch)
tree4fc0a2ad83c9c2217772b13725f29cf6f56a0824
parent6c49e2e93b23defd51d4b342baad5a9c3f843ea1 (diff)
downloadacron-34c53bc3d396934df94431f7b76972180b1b0a8c.tar
acron-34c53bc3d396934df94431f7b76972180b1b0a8c.tar.gz
acron-34c53bc3d396934df94431f7b76972180b1b0a8c.tar.bz2
acron-34c53bc3d396934df94431f7b76972180b1b0a8c.zip
feat(acronc): guard the connection using a mutex
Signed-off-by: Trumeet <yuuta@yuuta.moe>
-rw-r--r--client/libacron/README.md3
-rw-r--r--client/libacron/acronc/main.c85
2 files changed, 88 insertions, 0 deletions
diff --git a/client/libacron/README.md b/client/libacron/README.md
index 09e36dc..d52a4c3 100644
--- a/client/libacron/README.md
+++ b/client/libacron/README.md
@@ -261,6 +261,9 @@ it is the caller's responsibility to guard the whole connection with a mutex. li
provide that because this may limit the flexibility. After locking, it is safe to call the
connection-related functions from any threads.
+Example `acronc/main.c` has a naive cross-platform example of how to guard the connection using
+a mutex.
+
## Roadmap
* Make unit tests
diff --git a/client/libacron/acronc/main.c b/client/libacron/acronc/main.c
index 43802ad..dfd1668 100644
--- a/client/libacron/acronc/main.c
+++ b/client/libacron/acronc/main.c
@@ -15,6 +15,65 @@
#endif
+#ifdef __STDC_NO_THREADS__
+# ifdef WIN32
+#define THREAD_WIN32
+#include <windows.h>
+static HANDLE mtx_conn;
+
+int lock(void) { \
+DWORD _dwlck = WaitForSingleObject(mtx_conn, 0); \
+if (_dwlck == WAIT_FAILED) { _dwlck = GetLastError(); } \
+if (_dwlck) { fprintf(stderr, "Cannot lock the mutex: %d.\n", _dwlck); return _dwlck; } \
+return 0; \
+}
+
+int unlock(void) { \
+if (!ReleaseMutex(mtx_conn)) { \
+int r = GetLastError(); \
+fprintf(stderr, "Cannot release the mutex: %d.\n", r); \
+return r; \
+} \
+return 0; \
+}
+
+# else
+#error "Either C11 threading or Win32 API is required for concurrency."
+# endif
+#else
+
+#define THREAD_C11
+
+#include <threads.h>
+
+static mtx_t mtx_conn;
+
+int lock(void) {
+ \
+if (mtx_lock(&mtx_conn) != thrd_success) {
+ \
+fprintf(stderr, "Cannot lock the mutex.\n"); \
+return 1; \
+
+ } \
+return 0; \
+
+}
+
+int unlock(void) {
+ \
+if (mtx_unlock(&mtx_conn) != thrd_success) {
+ \
+fprintf(stderr, "Cannot release the mutex.\n"); \
+return 1; \
+
+ } \
+return 0; \
+
+}
+
+#endif
+
static const char *world_name(const enum ac_world world) {
switch (world) {
case overworld:
@@ -168,6 +227,19 @@ int main(int argc, char **argv) {
if ((r = net_init())) {
return r;
}
+#if defined(THREAD_WIN32)
+ if (!(mtx_conn = CreateMutex(NULL, TRUE, NULL))) {
+ r = GetLastError();
+ fprintf(stderr, "Cannot create mutex: %d.\n", r);
+ return r;
+ }
+#elif defined(THREAD_C11)
+ if (mtx_init(&mtx_conn, mtx_plain) != thrd_success) {
+ fprintf(stderr, "Cannot create mutex.\n");
+ return 1;
+ }
+#endif
+
#ifdef WIN32
fprintf(stderr, "Warning: ^C handler on Windows is not yet available.\n");
#else
@@ -235,12 +307,15 @@ int main(int argc, char **argv) {
goto end;
}
}
+ if ((r = lock())) { goto end; }
if ((r = ac_receive(connection, buffer, bytes, &obj))) {
+ if ((r = unlock())) { goto end; }
goto end;
}
if (!ready) {
/* Wait until ready. */
if ((r = ac_get_state(connection, &state))) {
+ if ((r = unlock())) { goto end; }
goto end;
}
switch (state) {
@@ -250,12 +325,15 @@ int main(int argc, char **argv) {
printf("Connection is established.\n");
ready = true;
say(connection);
+ if ((r = unlock())) { goto end; }
continue;
default:
fprintf(stderr, "Unexpected state.\n");
+ if ((r = unlock())) { goto end; }
goto end;
}
}
+ if ((r = unlock())) { goto end; }
if (!obj) {
continue;
@@ -277,9 +355,16 @@ int main(int argc, char **argv) {
nr);
}
}
+ if ((r = lock())) { goto end; }
ac_disconnect(connection);
+ if ((r = unlock())) { goto end; }
net_close(&sock);
ac_free();
net_free();
+#if defined(THREAD_WIN32)
+ CloseHandle(mtx_conn);
+#elif defined(THREAD_C11)
+ mtx_destroy(&mtx_conn);
+#endif
return r;
} \ No newline at end of file