summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-28 20:50:36 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-28 20:54:43 -0600
commitf410026b7bc96dbb42fec3839dc5d2e41b12f4a4 (patch)
tree22e831eb47101ee4e3635fcaf2729a81a178823c
parentf898850c2b4fef03f0d175ec052b3725bd406496 (diff)
misc
-rw-r--r--lib9p/include/lib9p/_types.h45
-rw-r--r--lib9p/include/lib9p/srv.h14
-rw-r--r--lib9p/internal.h5
-rw-r--r--lib9p/srv.c59
-rw-r--r--lib9p/types.c281
-rwxr-xr-xlib9p/types.gen58
-rw-r--r--libcr_ipc/CMakeLists.txt1
-rw-r--r--libcr_ipc/include/libcr_ipc/mutex.h46
-rw-r--r--libcr_ipc/include/libcr_ipc/sema.h6
-rw-r--r--libcr_ipc/mutex.c37
-rw-r--r--libcr_ipc/sema.c3
-rw-r--r--libnetio/include/libnetio/netio.h9
12 files changed, 492 insertions, 72 deletions
diff --git a/lib9p/include/lib9p/_types.h b/lib9p/include/lib9p/_types.h
index 7f320a5..94accc0 100644
--- a/lib9p/include/lib9p/_types.h
+++ b/lib9p/include/lib9p/_types.h
@@ -8,13 +8,15 @@
/* versions *******************************************************************/
enum lib9p_version {
- LIB9P_VER_UNINITIALIZED = 0,
- LIB9P_VER_9P2000, /* "9P2000" */
- LIB9P_VER_9P2000_e, /* "9P2000.e" */
- LIB9P_VER_9P2000_u, /* "9P2000.u" */
+ LIB9P_VER_unknown = 0, /* "unknown" */
+ LIB9P_VER_9P2000, /* "9P2000" */
+ LIB9P_VER_9P2000_e, /* "9P2000.e" */
+ LIB9P_VER_9P2000_u, /* "9P2000.u" */
LIB9P_VER_NUM,
};
+const char *lib9p_version_str(enum lib9p_version);
+
/* non-message structs ********************************************************/
struct lib9p_d {
@@ -90,40 +92,7 @@ enum lib9p_msg_type { /* uint8_t */
LIB9P_TYP_Rswrite = 155, /* 9P2000.e */
};
-#define LIB9P_TYPECODE_FOR_CTYPE(msg) _Generic((msg), \
- struct lib9p_msg_Tversion: LIB9P_TYP_Tversion, \
- struct lib9p_msg_Rversion: LIB9P_TYP_Rversion, \
- struct lib9p_msg_Tauth: LIB9P_TYP_Tauth, \
- struct lib9p_msg_Rauth: LIB9P_TYP_Rauth, \
- struct lib9p_msg_Tattach: LIB9P_TYP_Tattach, \
- struct lib9p_msg_Rattach: LIB9P_TYP_Rattach, \
- struct lib9p_msg_Rerror: LIB9P_TYP_Rerror, \
- struct lib9p_msg_Tflush: LIB9P_TYP_Tflush, \
- struct lib9p_msg_Rflush: LIB9P_TYP_Rflush, \
- struct lib9p_msg_Twalk: LIB9P_TYP_Twalk, \
- struct lib9p_msg_Rwalk: LIB9P_TYP_Rwalk, \
- struct lib9p_msg_Topen: LIB9P_TYP_Topen, \
- struct lib9p_msg_Ropen: LIB9P_TYP_Ropen, \
- struct lib9p_msg_Tcreate: LIB9P_TYP_Tcreate, \
- struct lib9p_msg_Rcreate: LIB9P_TYP_Rcreate, \
- struct lib9p_msg_Tread: LIB9P_TYP_Tread, \
- struct lib9p_msg_Rread: LIB9P_TYP_Rread, \
- struct lib9p_msg_Twrite: LIB9P_TYP_Twrite, \
- struct lib9p_msg_Rwrite: LIB9P_TYP_Rwrite, \
- struct lib9p_msg_Tclunk: LIB9P_TYP_Tclunk, \
- struct lib9p_msg_Rclunk: LIB9P_TYP_Rclunk, \
- struct lib9p_msg_Tremove: LIB9P_TYP_Tremove, \
- struct lib9p_msg_Rremove: LIB9P_TYP_Rremove, \
- struct lib9p_msg_Tstat: LIB9P_TYP_Tstat, \
- struct lib9p_msg_Rstat: LIB9P_TYP_Rstat, \
- struct lib9p_msg_Twstat: LIB9P_TYP_Twstat, \
- struct lib9p_msg_Rwstat: LIB9P_TYP_Rwstat, \
- struct lib9p_msg_Tsession: LIB9P_TYP_Tsession, \
- struct lib9p_msg_Rsession: LIB9P_TYP_Rsession, \
- struct lib9p_msg_Tsread: LIB9P_TYP_Tsread, \
- struct lib9p_msg_Rsread: LIB9P_TYP_Rsread, \
- struct lib9p_msg_Tswrite: LIB9P_TYP_Tswrite, \
- struct lib9p_msg_Rswrite: LIB9P_TYP_Rswrite)
+const char *lib9p_msg_type_str(enum lib9p_msg_type);
struct lib9p_msg_Tversion {
uint32_t max_msg_size;
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
index a8bd9c7..3ca8b4d 100644
--- a/lib9p/include/lib9p/srv.h
+++ b/lib9p/include/lib9p/srv.h
@@ -4,13 +4,23 @@
#include <libcr/coroutine.h>
#include <libcr_ipc/chan.h>
-struct lib9p_srvreq;
+struct lib9p_srv_req;
struct lib9p_srv {
int sockfd;
- cr_chan_t(struct lib9p_srvreq *) reqch;
+
+ cr_chan_t(struct lib9p_srv_req *) reqch;
};
+/**
+ * Will just close the connection if a T-message has a size[4] <7.
+ * @errno LINUX_EMSGSIZE T-message has size[4] bigger than max_msg_size
+ * @errno LINUX_EDOM Tversion specified an impossibly small max_msg_size
+ * @errno LINUX_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type
+ * @errno LINUX_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8
+ * @errno LINUX_ERANGE R-message does not fit into max_msg_size
+ */
+
COROUTINE lib9p_srv_read_cr(void *_srv);
COROUTINE lib9p_srv_write_cr(void *_srv);
diff --git a/lib9p/internal.h b/lib9p/internal.h
index a5175af..08bb462 100644
--- a/lib9p/internal.h
+++ b/lib9p/internal.h
@@ -51,6 +51,7 @@ struct _checksize_ctx {
* "extra" beyond sizeof(). */
size_t host_extra;
};
+typedef bool (*_checksize_fn_t)(struct _checksize_ctx *ctx);
struct _unmarshal_ctx {
struct lib9p_ctx *ctx;
@@ -60,6 +61,7 @@ struct _unmarshal_ctx {
/* `extra` points to the beginning of unallocated space. */
void *extra;
};
+typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out);
struct _marshal_ctx {
struct lib9p_ctx *ctx;
@@ -67,9 +69,6 @@ struct _marshal_ctx {
uint8_t *net_bytes;
uint32_t net_offset;
};
-
-typedef bool (*_checksize_fn_t)(struct _checksize_ctx *ctx);
-typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out);
typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val);
struct _vtable_msg {
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 039b4c2..74c2014 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -10,18 +10,24 @@
#include <lib9p/srv.h>
#include "internal.h"
-struct lib9p_srvconn {
+/* The hierarchy of concepts is:
+ *
+ * server -> connection -> session -> request
+ *
+ */
+
+struct lib9p_srv_sess {
/* immutable */
struct lib9p_srv *srv;
- cid_t reader;
- int fd;
+ int connfd;
+ cid_t reader; /* the lib9p_srv_read_cr() coroutine for this session */
/* mutable */
struct lib9p_ctx ctx;
unsigned int refcount;
};
-struct lib9p_srvreq {
- struct lib9p_srvconn *conn;
+struct lib9p_srv_req {
+ struct lib9p_srv_sess *sess;
uint8_t *msg;
};
@@ -79,7 +85,7 @@ COROUTINE lib9p_srv_read_cr(void *_srv) {
}
goal = decode_u32le(buf);
if (goal < 7) {
- /* We can't respond with an Rerror becuase we wouldn't know what tag to use! */
+ /* We can't even respond with an Rerror becuase we wouldn't know what tag to use! */
fprintf(stderr, "error: T-message is impossibly small");
goto close;
}
@@ -184,5 +190,42 @@ void handle_message(struct lib9p_srvconn *conn, uint8_t *net) {
netio_write(req.conn->fd, net, decode_u32le(net));
}
-// EMSGSIZE for request too large
-// EPROTONOSUPPORT for version errors
+void _version(struct lib9p_srv_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp) {
+ enum lib9p_version version = LIB9P_VER_unknown;
+
+ if (req->version.len >= 6 &&
+ req->version.utf8[0] == '9' &&
+ req->version.utf8[1] == 'P' &&
+ '0' <= req->version.utf8[2] && req->version.utf8[2] <= '9' &&
+ '0' <= req->version.utf8[3] && req->version.utf8[3] <= '9' &&
+ '0' <= req->version.utf8[4] && req->version.utf8[4] <= '9' &&
+ '0' <= req->version.utf8[5] && req->version.utf8[5] <= '9' &&
+ (req->version.utf8[6] == '\0' || req->version.utf8[6] == '.')) {
+ if (strcmp(&req->version.utf8[6], ".u") == 0)
+ version = LIB9P_VER_9P2000_u;
+ //else if (strcmp(&req->version.utf8[6], ".e") == 0)
+ // version = LIB9P_VER_9P2000_e;
+ else
+ version = LIB9P_VER_9P2000;
+ }
+
+ struct lib9p_ctx empty_ctx = {
+ .version = version,
+ .max_msg_size = CONFIG_9P_MAX_MSG_SIZE,
+ };
+ struct lib9p_msg_Rerror empty_error = { 0 };
+ assert(!lib9p_marshal(&empty_ctx, LIB9P_TYP_Rerror, 0, &empty_error, ctx->net));
+ uint32_t min_msg_size = decode_u32le(ctx->net);
+ assert(CONFIG_9P_MAX_MSG_SIZE >= min_msg_size);
+
+ if (req->max_msg_size < min_msg_size) {
+ lib9p_errorf(&ctx->ctx, LINUX_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")",
+ version, req->max_msg_size, min_msg_size);
+ return;
+ }
+
+ resp->version = lib9p_version_str(version);
+ resp->max_msg_size = (CONFIG_9P_MAX_MSG_SIZE < req->max_msg_size)
+ ? CONFIG_9P_MAX_MSG_SIZE
+ : req->max_msg_size;
+}
diff --git a/lib9p/types.c b/lib9p/types.c
index 91a503d..8a48b85 100644
--- a/lib9p/types.c
+++ b/lib9p/types.c
@@ -1,5 +1,6 @@
/* Generated by `./lib9p/types.gen lib9p/9P2000.txt lib9p/9P2000.u.txt lib9p/9P2000.e.txt`. DO NOT EDIT! */
+#include <assert.h>
#include <stdbool.h>
#include <stddef.h> /* for size_t */
#include <inttypes.h> /* for PRI* macros */
@@ -9,6 +10,284 @@
#include "internal.h"
+/* strings ********************************************************************/
+
+static const char *version_strs[LIB9P_VER_NUM] = {
+ [LIB9P_VER_unknown] = "unknown",
+ [LIB9P_VER_9P2000] = "9P2000",
+ [LIB9P_VER_9P2000_e] = "9P2000.e",
+ [LIB9P_VER_9P2000_u] = "9P2000.u",
+};
+
+const char *lib9p_version_str(enum lib9p_version ver) {
+ assert(0 <= ver && ver < LIB9P_VER_NUM);
+ return version_strs[ver];
+}
+
+static const char *msg_type_strs[0xFF] = {
+ [0x00] = "0x00",
+ [0x01] = "0x01",
+ [0x02] = "0x02",
+ [0x03] = "0x03",
+ [0x04] = "0x04",
+ [0x05] = "0x05",
+ [0x06] = "0x06",
+ [0x07] = "0x07",
+ [0x08] = "0x08",
+ [0x09] = "0x09",
+ [0x0A] = "0x0A",
+ [0x0B] = "0x0B",
+ [0x0C] = "0x0C",
+ [0x0D] = "0x0D",
+ [0x0E] = "0x0E",
+ [0x0F] = "0x0F",
+ [0x10] = "0x10",
+ [0x11] = "0x11",
+ [0x12] = "0x12",
+ [0x13] = "0x13",
+ [0x14] = "0x14",
+ [0x15] = "0x15",
+ [0x16] = "0x16",
+ [0x17] = "0x17",
+ [0x18] = "0x18",
+ [0x19] = "0x19",
+ [0x1A] = "0x1A",
+ [0x1B] = "0x1B",
+ [0x1C] = "0x1C",
+ [0x1D] = "0x1D",
+ [0x1E] = "0x1E",
+ [0x1F] = "0x1F",
+ [0x20] = "0x20",
+ [0x21] = "0x21",
+ [0x22] = "0x22",
+ [0x23] = "0x23",
+ [0x24] = "0x24",
+ [0x25] = "0x25",
+ [0x26] = "0x26",
+ [0x27] = "0x27",
+ [0x28] = "0x28",
+ [0x29] = "0x29",
+ [0x2A] = "0x2A",
+ [0x2B] = "0x2B",
+ [0x2C] = "0x2C",
+ [0x2D] = "0x2D",
+ [0x2E] = "0x2E",
+ [0x2F] = "0x2F",
+ [0x30] = "0x30",
+ [0x31] = "0x31",
+ [0x32] = "0x32",
+ [0x33] = "0x33",
+ [0x34] = "0x34",
+ [0x35] = "0x35",
+ [0x36] = "0x36",
+ [0x37] = "0x37",
+ [0x38] = "0x38",
+ [0x39] = "0x39",
+ [0x3A] = "0x3A",
+ [0x3B] = "0x3B",
+ [0x3C] = "0x3C",
+ [0x3D] = "0x3D",
+ [0x3E] = "0x3E",
+ [0x3F] = "0x3F",
+ [0x40] = "0x40",
+ [0x41] = "0x41",
+ [0x42] = "0x42",
+ [0x43] = "0x43",
+ [0x44] = "0x44",
+ [0x45] = "0x45",
+ [0x46] = "0x46",
+ [0x47] = "0x47",
+ [0x48] = "0x48",
+ [0x49] = "0x49",
+ [0x4A] = "0x4A",
+ [0x4B] = "0x4B",
+ [0x4C] = "0x4C",
+ [0x4D] = "0x4D",
+ [0x4E] = "0x4E",
+ [0x4F] = "0x4F",
+ [0x50] = "0x50",
+ [0x51] = "0x51",
+ [0x52] = "0x52",
+ [0x53] = "0x53",
+ [0x54] = "0x54",
+ [0x55] = "0x55",
+ [0x56] = "0x56",
+ [0x57] = "0x57",
+ [0x58] = "0x58",
+ [0x59] = "0x59",
+ [0x5A] = "0x5A",
+ [0x5B] = "0x5B",
+ [0x5C] = "0x5C",
+ [0x5D] = "0x5D",
+ [0x5E] = "0x5E",
+ [0x5F] = "0x5F",
+ [0x60] = "0x60",
+ [0x61] = "0x61",
+ [0x62] = "0x62",
+ [0x63] = "0x63",
+ [0x64] = "Tversion",
+ [0x65] = "Rversion",
+ [0x66] = "Tauth",
+ [0x67] = "Rauth",
+ [0x68] = "Tattach",
+ [0x69] = "Rattach",
+ [0x6A] = "0x6A",
+ [0x6B] = "Rerror",
+ [0x6C] = "Tflush",
+ [0x6D] = "Rflush",
+ [0x6E] = "Twalk",
+ [0x6F] = "Rwalk",
+ [0x70] = "Topen",
+ [0x71] = "Ropen",
+ [0x72] = "Tcreate",
+ [0x73] = "Rcreate",
+ [0x74] = "Tread",
+ [0x75] = "Rread",
+ [0x76] = "Twrite",
+ [0x77] = "Rwrite",
+ [0x78] = "Tclunk",
+ [0x79] = "Rclunk",
+ [0x7A] = "Tremove",
+ [0x7B] = "Rremove",
+ [0x7C] = "Tstat",
+ [0x7D] = "Rstat",
+ [0x7E] = "Twstat",
+ [0x7F] = "Rwstat",
+ [0x80] = "0x80",
+ [0x81] = "0x81",
+ [0x82] = "0x82",
+ [0x83] = "0x83",
+ [0x84] = "0x84",
+ [0x85] = "0x85",
+ [0x86] = "0x86",
+ [0x87] = "0x87",
+ [0x88] = "0x88",
+ [0x89] = "0x89",
+ [0x8A] = "0x8A",
+ [0x8B] = "0x8B",
+ [0x8C] = "0x8C",
+ [0x8D] = "0x8D",
+ [0x8E] = "0x8E",
+ [0x8F] = "0x8F",
+ [0x90] = "0x90",
+ [0x91] = "0x91",
+ [0x92] = "0x92",
+ [0x93] = "0x93",
+ [0x94] = "0x94",
+ [0x95] = "0x95",
+ [0x96] = "Tsession",
+ [0x97] = "Rsession",
+ [0x98] = "Tsread",
+ [0x99] = "Rsread",
+ [0x9A] = "Tswrite",
+ [0x9B] = "Rswrite",
+ [0x9C] = "0x9C",
+ [0x9D] = "0x9D",
+ [0x9E] = "0x9E",
+ [0x9F] = "0x9F",
+ [0xA0] = "0xA0",
+ [0xA1] = "0xA1",
+ [0xA2] = "0xA2",
+ [0xA3] = "0xA3",
+ [0xA4] = "0xA4",
+ [0xA5] = "0xA5",
+ [0xA6] = "0xA6",
+ [0xA7] = "0xA7",
+ [0xA8] = "0xA8",
+ [0xA9] = "0xA9",
+ [0xAA] = "0xAA",
+ [0xAB] = "0xAB",
+ [0xAC] = "0xAC",
+ [0xAD] = "0xAD",
+ [0xAE] = "0xAE",
+ [0xAF] = "0xAF",
+ [0xB0] = "0xB0",
+ [0xB1] = "0xB1",
+ [0xB2] = "0xB2",
+ [0xB3] = "0xB3",
+ [0xB4] = "0xB4",
+ [0xB5] = "0xB5",
+ [0xB6] = "0xB6",
+ [0xB7] = "0xB7",
+ [0xB8] = "0xB8",
+ [0xB9] = "0xB9",
+ [0xBA] = "0xBA",
+ [0xBB] = "0xBB",
+ [0xBC] = "0xBC",
+ [0xBD] = "0xBD",
+ [0xBE] = "0xBE",
+ [0xBF] = "0xBF",
+ [0xC0] = "0xC0",
+ [0xC1] = "0xC1",
+ [0xC2] = "0xC2",
+ [0xC3] = "0xC3",
+ [0xC4] = "0xC4",
+ [0xC5] = "0xC5",
+ [0xC6] = "0xC6",
+ [0xC7] = "0xC7",
+ [0xC8] = "0xC8",
+ [0xC9] = "0xC9",
+ [0xCA] = "0xCA",
+ [0xCB] = "0xCB",
+ [0xCC] = "0xCC",
+ [0xCD] = "0xCD",
+ [0xCE] = "0xCE",
+ [0xCF] = "0xCF",
+ [0xD0] = "0xD0",
+ [0xD1] = "0xD1",
+ [0xD2] = "0xD2",
+ [0xD3] = "0xD3",
+ [0xD4] = "0xD4",
+ [0xD5] = "0xD5",
+ [0xD6] = "0xD6",
+ [0xD7] = "0xD7",
+ [0xD8] = "0xD8",
+ [0xD9] = "0xD9",
+ [0xDA] = "0xDA",
+ [0xDB] = "0xDB",
+ [0xDC] = "0xDC",
+ [0xDD] = "0xDD",
+ [0xDE] = "0xDE",
+ [0xDF] = "0xDF",
+ [0xE0] = "0xE0",
+ [0xE1] = "0xE1",
+ [0xE2] = "0xE2",
+ [0xE3] = "0xE3",
+ [0xE4] = "0xE4",
+ [0xE5] = "0xE5",
+ [0xE6] = "0xE6",
+ [0xE7] = "0xE7",
+ [0xE8] = "0xE8",
+ [0xE9] = "0xE9",
+ [0xEA] = "0xEA",
+ [0xEB] = "0xEB",
+ [0xEC] = "0xEC",
+ [0xED] = "0xED",
+ [0xEE] = "0xEE",
+ [0xEF] = "0xEF",
+ [0xF0] = "0xF0",
+ [0xF1] = "0xF1",
+ [0xF2] = "0xF2",
+ [0xF3] = "0xF3",
+ [0xF4] = "0xF4",
+ [0xF5] = "0xF5",
+ [0xF6] = "0xF6",
+ [0xF7] = "0xF7",
+ [0xF8] = "0xF8",
+ [0xF9] = "0xF9",
+ [0xFA] = "0xFA",
+ [0xFB] = "0xFB",
+ [0xFC] = "0xFC",
+ [0xFD] = "0xFD",
+ [0xFE] = "0xFE",
+ [0xFF] = "0xFF",
+};
+
+const char *lib9p_msg_type_str(enum lib9p_msg_type typ) {
+ assert(0 <= typ && typ <= 0xFF);
+ return msg_type_strs[typ];
+}
+
/* checksize_* (internals of unmarshal_size()) ********************************/
static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) {
@@ -799,7 +1078,7 @@ static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *
}
struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM] = {
- [LIB9P_VER_UNINITIALIZED] = { .msgs = {
+ [LIB9P_VER_unknown] = { .msgs = {
_MSG(Tversion),
_MSG(Rversion),
_MSG(Rerror),
diff --git a/lib9p/types.gen b/lib9p/types.gen
index 15936e7..590e707 100755
--- a/lib9p/types.gen
+++ b/lib9p/types.gen
@@ -241,14 +241,16 @@ def gen_h(idprefix: str, versions: set[str], structs: list[Struct]) -> str:
/* versions *******************************************************************/
enum {idprefix}version {{
- {idprefix.upper()}VER_UNINITIALIZED = 0,
"""
- verwidth = max(len(v) for v in versions)
- for ver in sorted(versions):
+ fullversions = ["unknown = 0", *sorted(versions)]
+ verwidth = max(len(v) for v in fullversions)
+ for ver in fullversions:
ret += f"\t{c_verenum(idprefix, ver)},"
- ret += (" " * (verwidth - len(ver))) + ' /* "' + ver + '" */\n'
- ret += f"\t{idprefix.upper()}VER_NUM,\n"
+ ret += (" " * (verwidth - len(ver))) + ' /* "' + ver.split()[0] + '" */\n'
+ ret += f"\t{c_verenum(idprefix, 'NUM')},\n"
ret += "};\n"
+ ret += "\n"
+ ret += f"const char *{idprefix}version_str(enum {idprefix}version);\n"
ret += """
/* non-message structs ********************************************************/
@@ -287,16 +289,8 @@ enum {idprefix}version {{
ret += " " + comment
ret += "\n"
ret += "};\n"
-
ret += "\n"
- ret += f"#define {idprefix.upper()}TYPECODE_FOR_CTYPE(msg) _Generic((msg)"
- for msg in structs:
- if msg.msgid is None:
- continue
- ret += (
- f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}"
- )
- ret += ")\n"
+ ret += f"const char *{idprefix}msg_type_str(enum {idprefix}msg_type);\n"
for msg in structs:
if msg.msgid is None:
@@ -333,6 +327,7 @@ enum {idprefix}version {{
def gen_c(idprefix: str, versions: set[str], structs: list[Struct]) -> str:
ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
+#include <assert.h>
#include <stdbool.h>
#include <stddef.h> /* for size_t */
#include <inttypes.h> /* for PRI* macros */
@@ -349,6 +344,37 @@ def gen_c(idprefix: str, versions: set[str], structs: list[Struct]) -> str:
def unused(arg: str) -> str:
return f"UNUSED({arg})"
+ # strings ##################################################################
+ ret += f"""
+/* strings ********************************************************************/
+
+static const char *version_strs[{c_verenum(idprefix, 'NUM')}] = {{
+"""
+ for ver in ["unknown", *sorted(versions)]:
+ ret += f'\t[{c_verenum(idprefix, ver)}] = "{ver}",\n'
+ ret += "};\n"
+ ret += f"""
+const char *{idprefix}version_str(enum {idprefix}version ver) {{
+ assert(0 <= ver && ver < {c_verenum(idprefix, 'NUM')});
+ return version_strs[ver];
+}}
+
+static const char *msg_type_strs[0xFF] = {{
+"""
+ id2name: dict[int, str] = {}
+ for msg in structs:
+ if msg.msgid is not None:
+ id2name[msg.msgid] = msg.name
+ for n in range(0, 0x100):
+ ret += '\t[0x{:02X}] = "{}",\n'.format(n, id2name.get(n, "0x{:02X}".format(n)))
+ ret += "};\n"
+ ret += f"""
+const char *{idprefix}msg_type_str(enum {idprefix}msg_type typ) {{
+ assert(0 <= typ && typ <= 0xFF);
+ return msg_type_strs[typ];
+}}
+"""
+
# checksize_* ##############################################################
ret += """
/* checksize_* (internals of unmarshal_size()) ********************************/
@@ -591,10 +617,10 @@ static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) {
.marshal = (_marshal_fn_t)marshal_##typ, \\
}}
-struct _vtable_version _{idprefix}vtables[LIB9P_VER_NUM] = {{
+struct _vtable_version _{idprefix}vtables[{c_verenum(idprefix, 'NUM')}] = {{
"""
- ret += f"\t[{idprefix.upper()}VER_UNINITIALIZED] = {{ .msgs = {{\n"
+ ret += f"\t[{c_verenum(idprefix, 'unknown')}] = {{ .msgs = {{\n"
for msg in structs:
if msg.name in ["Tversion", "Rversion", "Rerror"]: # SPECIAL
ret += f"\t\t_MSG({msg.name}),\n"
diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt
index 3388fcd..957b638 100644
--- a/libcr_ipc/CMakeLists.txt
+++ b/libcr_ipc/CMakeLists.txt
@@ -7,6 +7,7 @@ add_library(libcr_ipc INTERFACE)
target_include_directories(libcr_ipc SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
target_sources(libcr_ipc INTERFACE
sema.c
+ mutex.c
)
target_link_libraries(libcr_ipc INTERFACE
libcr
diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h
new file mode 100644
index 0000000..38ebde0
--- /dev/null
+++ b/libcr_ipc/include/libcr_ipc/mutex.h
@@ -0,0 +1,46 @@
+/* libcr_ipc/mutex.h - Simple mutexes for libcr (header file)
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _COROUTINE_MUTEX_H_
+#define _COROUTINE_MUTEX_H_
+
+#include <stdbool.h> /* for bool */
+
+#include <libcr/coroutine.h> /* for cid_t */
+
+struct _cr_mutex_cid_list {
+ cid_t val;
+ struct _cr_mutex_cid_list *next;
+};
+
+/**
+ * A cr_mutex_t is a fair mutex.
+ */
+typedef struct {
+ bool locked;
+ struct _cr_mutex_cid_list *head, **tail;
+} cr_mutex_t;
+
+/**
+ * Lock the mutex. Blocks if it is already locked.
+ *
+ * @blocks maybe
+ * @yields maybe
+ * @run_in coroutine
+ */
+void cr_mutex_lock(cr_mutex_t *);
+
+/**
+ * Unlock the mutex. Unblocks a coroutine that is blocked on
+ * cr_mutex_lock().
+ *
+ * @blocks never
+ * @yields never
+ * @may_run_in coroutine
+ */
+void cr_mutex_unluck(cr_mutex_t *);
+
+#endif /* _COROUTINE_MUTEX_H_ */
diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h
index a2a176d..454eb5d 100644
--- a/libcr_ipc/include/libcr_ipc/sema.h
+++ b/libcr_ipc/include/libcr_ipc/sema.h
@@ -1,4 +1,4 @@
-/* coroutine_sema.h - Simple semaphores for coroutine.{h,c}
+/* libcr_ipc/sema.h - Simple semaphores for libcr (header file)
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
@@ -7,6 +7,10 @@
#ifndef _COROUTINE_SEMA_H_
#define _COROUTINE_SEMA_H_
+#include <stdbool.h> /* for bool */
+
+#include <libcr/coroutine.h> /* for cid_t */
+
struct _cr_sema_cid_list {
cid_t val;
struct _cr_sema_cid_list *next;
diff --git a/libcr_ipc/mutex.c b/libcr_ipc/mutex.c
new file mode 100644
index 0000000..c5cea96
--- /dev/null
+++ b/libcr_ipc/mutex.c
@@ -0,0 +1,37 @@
+/* libcr_ipc/mutex.c - Simple mutexes for libcr (implementation file)
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libcr_ipc/mutex.h>
+
+void cr_mutex_lock(cr_mutex_t *mu) {
+ assert(mu);
+ if (!mu->tail)
+ mu->tail = &mu->head;
+ if (!mu->locked) {
+ mu->locked = true;
+ return;
+ }
+ struct _cr_mutex_cid_list self = {
+ .val = cr_getcid(),
+ .next = NULL,
+ };
+ *(mu->tail) = &self;
+ mu->tail = &(self.next);
+ cr_pause_and_yield();
+}
+
+void cr_mutex_unlock(cr_mutex_t *mu) {
+ assert(mu);
+ assert(mu->tail);
+ assert(mu->locked);
+ if (mu->head) {
+ cr_unpause(mu->head->val);
+ mu->head = mu->head->next;
+ if (!mu->head)
+ mu->tail = &mu->head;
+ } else
+ mu->locked = false;
+}
diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c
index a3b2ca0..9645a41 100644
--- a/libcr_ipc/sema.c
+++ b/libcr_ipc/sema.c
@@ -1,4 +1,4 @@
-/* coroutine_sema.h - Simple semaphores for coroutine.{h,c}
+/* libcr_ipc/sema.c - Simple semaphores for libcr (implementation file)
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
@@ -6,7 +6,6 @@
#include <assert.h>
-#include <libcr/coroutine.h>
#include <libcr_ipc/sema.h>
/** Drain the sema->{head,tail} list. Returns true if cr_getcid() was drained. */
diff --git a/libnetio/include/libnetio/netio.h b/libnetio/include/libnetio/netio.h
index 9383c54..370d2ca 100644
--- a/libnetio/include/libnetio/netio.h
+++ b/libnetio/include/libnetio/netio.h
@@ -12,7 +12,14 @@ int netio_listen(uint16_t port);
int netio_accept(int sock);
/** Return bytes-read on success, 0 on EOF, -errno on error; a short read is *not* an error. */
ssize_t netio_read(int conn, void *buf, size_t count);
-/** Return `count` on success, -errno on error; a short write *is* an error. */
+/**
+ * Return `count` on success, -errno on error; a short write *is* an
+ * error.
+ *
+ * Writes are *not* guaranteed to be atomic (as this would be
+ * expensive to implement), so if you have concurrent writers then you
+ * should arrange for a mutex to protect the connection.
+ */
ssize_t netio_write(int conn, void *buf, size_t count);
/** Return 0 on success, -errno on error. */
int netio_close(int conn, bool rd, bool wr);