diff options
-rw-r--r-- | cmd/sbc_harness/config/config.h | 10 | ||||
-rw-r--r-- | lib9p/9p.c | 3 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 5 | ||||
-rw-r--r-- | lib9p/internal.h | 4 | ||||
-rw-r--r-- | lib9p/srv.c | 368 | ||||
-rw-r--r-- | lib9p/types.c | 5 | ||||
-rwxr-xr-x | lib9p/types.gen | 7 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/_common.h | 19 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/chan.h | 137 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/mutex.h | 9 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/rpc.h | 22 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/sema.h | 7 | ||||
-rw-r--r-- | libcr_ipc/mutex.c | 4 | ||||
-rw-r--r-- | libcr_ipc/sema.c | 2 |
14 files changed, 363 insertions, 239 deletions
diff --git a/cmd/sbc_harness/config/config.h b/cmd/sbc_harness/config/config.h index 0f0385b..b12eb2c 100644 --- a/cmd/sbc_harness/config/config.h +++ b/cmd/sbc_harness/config/config.h @@ -17,7 +17,7 @@ #endif #ifdef USE_CONFIG_COROUTINE -# define CONFIG_COROUTINE_DEFAULT_STACK_SIZE (8*1024) +# define CONFIG_COROUTINE_DEFAULT_STACK_SIZE (16*1024) # define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */ # define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */ # define CONFIG_COROUTINE_DEBUG 0 /* bool */ @@ -47,8 +47,14 @@ * negotiated. In Plan 9 1e it was (8*1024)+128, and was bumped to * (8*1024)+160 in 2e and 3e. */ -# define CONFIG_9P_MAX_MSG_SIZE ((8*1024)+24) +# define CONFIG_9P_MAX_MSG_SIZE ((4*1024)+24) # define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */ + /** + * Maximum host-data-structure size. A message may be larger in + * unmarshaled-host-structures than marshaled-net-bytes due to (1) + * struct padding, (2) nul-terminator byes for strings. + */ +# define CONFIG_9P_MAX_HOSTMSG_SIZE CONFIG_9P_MAX_MSG_SIZE #endif #endif /* _CONFIG_H */ @@ -62,7 +62,8 @@ ssize_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes) { /* Body */ struct _vtable_msg vtable = _lib9p_vtables[ctx->version].msgs[typ]; if (!vtable.unmarshal_extrasize) - return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %"PRIu8, typ); + return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %s", + lib9p_msg_type_str(typ)); if (vtable.unmarshal_extrasize(&subctx)) return -1; diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index 3ca8b4d..9220bd9 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -4,12 +4,11 @@ #include <libcr/coroutine.h> #include <libcr_ipc/chan.h> -struct lib9p_srv_req; +struct lib9p_req; struct lib9p_srv { int sockfd; - - cr_chan_t(struct lib9p_srv_req *) reqch; + cr_chan_t(struct lib9p_req *) reqch; }; /** diff --git a/lib9p/internal.h b/lib9p/internal.h index 08bb462..f67735b 100644 --- a/lib9p/internal.h +++ b/lib9p/internal.h @@ -14,9 +14,11 @@ #include <lib9p/9p.h> #define USE_CONFIG_9P +#define USE_CONFIG_COROUTINE #include "config.h" static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX); static_assert(CONFIG_9P_MAX_MSG_SIZE <= SSIZE_MAX); +static_assert(CONFIG_9P_MAX_ERR_SIZE + CONFIG_9P_MAX_MSG_SIZE + 2*CONFIG_9P_MAX_HOSTMSG_SIZE < CONFIG_COROUTINE_DEFAULT_STACK_SIZE); /* C language *****************************************************************/ @@ -31,8 +33,6 @@ struct lib9p_ctx { /* negotiated */ enum lib9p_version version; uint32_t max_msg_size; - /* negotiated (server) */ - uint32_t Rerror_overhead; /* state */ uint32_t err_num; diff --git a/lib9p/srv.c b/lib9p/srv.c index 74c2014..997d137 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -1,48 +1,119 @@ #include <assert.h> -#include <stdio.h> /* for fprintf(), stderr */ -#include <string.h> /* for strerror() */ +#include <inttypes.h> /* for PRI* */ +#include <stdio.h> /* for fprintf(), stderr */ +#include <string.h> /* for strerror() */ #include <libcr/coroutine.h> #include <libcr_ipc/chan.h> +#include <libcr_ipc/mutex.h> #include <libnetio/netio.h> #include <lib9p/9p.h> #include <lib9p/srv.h> #include "internal.h" +/* structs ********************************************************************/ + /* The hierarchy of concepts is: * * server -> connection -> session -> request * */ -struct lib9p_srv_sess { +/* struct lib9p_srv {} is defined in <lib9p/srv.h> */ + +struct lib9p_conn { /* immutable */ - struct lib9p_srv *srv; - int connfd; - cid_t reader; /* the lib9p_srv_read_cr() coroutine for this session */ + struct lib9p_srv *parent_srv; + int fd; + cid_t reader; /* the lib9p_srv_read_cr() coroutine */ /* mutable */ - struct lib9p_ctx ctx; + cr_mutex_t writelock; +}; + +struct lib9p_sess { + /* immutable */ + struct lib9p_conn *parent_conn; + enum lib9p_version version; + uint32_t max_msg_size; + uint32_t rerror_overhead; + /* mutable */ + bool initialized; unsigned int refcount; }; -struct lib9p_srv_req { - struct lib9p_srv_sess *sess; - uint8_t *msg; +struct lib9p_req { + /* immutable */ + struct lib9p_sess *parent_sess; + uint16_t tag; + /* mutable */ + uint8_t *net_bytes; /* CONFIG_9P_MAX_MSG_SIZE-sized */ + struct lib9p_ctx ctx; }; -static void marshal_error(struct lib9p_ctx *ctx, uint16_t tag, uint8_t *net) { +/* base utilities *************************************************************/ + +#define nonrespond_errorf(...) fprintf(stderr, "error: " __VA_ARGS__) + +static uint32_t rerror_overhead_for_version(enum lib9p_version version, uint8_t *scratch) { + 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, scratch)); + uint32_t min_msg_size = decode_u32le(scratch); + assert(min_msg_size < (UINT32_MAX - UINT16_MAX)); + assert(CONFIG_9P_MAX_MSG_SIZE >= min_msg_size); + + return min_msg_size; +} + +static void respond_error(struct lib9p_req *req) { + assert(req->ctx.err_num); + assert(req->ctx.err_msg[0]); + + ssize_t r; struct lib9p_msg_Rerror host = { .ename = { - .len = strnlen(ctx->err_msg, CONFIG_9P_MAX_ERR_SIZE), - .utf8 = (uint8_t*)ctx->err_msg, + .len = strnlen(req->ctx.err_msg, CONFIG_9P_MAX_ERR_SIZE), + .utf8 = (uint8_t*)req->ctx.err_msg, }, - .errno = ctx->err_num, + .errno = req->ctx.err_num, }; - lib9p_marshal(ctx, LIB9P_TYP_Rerror, tag, &host, net); + + /* Truncate the error-string if necessary to avoid needing to return ERANGE. */ + if (((uint32_t)host.ename.len) + req->parent_sess->rerror_overhead > req->parent_sess->max_msg_size) + host.ename.len = req->parent_sess->max_msg_size - req->parent_sess->rerror_overhead; + + lib9p_marshal(&req->ctx, LIB9P_TYP_Rerror, req->tag, &host, req->net_bytes); + + cr_mutex_lock(&req->parent_sess->parent_conn->writelock); + r = netio_write(req->parent_sess->parent_conn->fd, req->net_bytes, decode_u32le(req->net_bytes)); + cr_mutex_unlock(&req->parent_sess->parent_conn->writelock); + if (r < 0) + nonrespond_errorf("write: %s", strerror(-r)); } -void handle_message(struct lib9p_srvconn *conn, uint8_t *net); +/* read coroutine *************************************************************/ + +static bool read_at_least(int fd, uint8_t *buf, size_t goal, size_t *done) { + while (*done < goal) { + ssize_t r = netio_read(fd, &buf[*done], CONFIG_9P_MAX_MSG_SIZE - *done); + if (r < 0) { + nonrespond_errorf("read: %s", strerror(-r)); + return true; + } else if (r == 0) { + if (*done != 0) { + nonrespond_errorf("read: unexpected EOF"); + return true; + } + *done += r; + } + } + return false; +} COROUTINE lib9p_srv_read_cr(void *_srv) { uint8_t buf[CONFIG_9P_MAX_MSG_SIZE]; @@ -51,80 +122,67 @@ COROUTINE lib9p_srv_read_cr(void *_srv) { assert(srv); cr_begin(); + uint32_t initial_rerror_overhead = rerror_overhead_for_version(0, buf); + for (;;) { - struct lib9p_srvconn conn = { - .srv = srv, - .reader = cr_getcid(), - - .ctx = { - .version = LIB9P_VER_UNINITIALIZED, - .max_msg_size = CONFIG_9P_MAX_MSG_SIZE, - }, - .refcount = 1, + struct lib9p_conn conn = { + .parent_srv = srv, + .fd = netio_accept(srv->sockfd), + .reader = cr_getcid(), }; - conn.fd = netio_accept(srv->sockfd); if (conn.fd < 0) { - fprintf(stderr, "error: accept: %s", strerror(-conn.fd)); + nonrespond_errorf("accept: %s", strerror(-conn.fd)); continue; } + struct lib9p_sess sess = { + .parent_conn = &conn, + .version = 0, + .max_msg_size = CONFIG_9P_MAX_MSG_SIZE, + .rerror_overhead = initial_rerror_overhead, + .initialized = false, + .refcount = 1, + }; for (;;) { - /* Read the message size. */ - size_t goal = 4, done = 0; - while (done < goal) { - ssize_t r = netio_read(conn.fd, &buf[done], sizeof(buf)-done); - if (r < 0) { - fprintf(stderr, "error: read: %s", strerror(-r)); - goto close; - } else if (r == 0) { - if (done != 0) - fprintf(stderr, "error: read: unexpected EOF"); - goto close; - } - done += r; - } - goal = decode_u32le(buf); + /* Read the message. */ + size_t done = 0; + if (read_at_least(conn.fd, buf, 4, &done)) + goto close; + size_t goal = decode_u32le(buf); if (goal < 7) { - /* 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"); + nonrespond_errorf("T-message is impossibly small"); goto close; } - if (goal > conn.ctx.max_msg_size) { - lib9p_errorf(&conn.ctx, LINUX_EMSGSIZE, "T-message larger than %s limit (%zu > %zu)", - conn.ctx.version ? "negotiated" : "server", goal, conn.ctx.max_msg_size); - uint16_t tag = decode_u16le(&buf[5]); - marshal_error(&conn.ctx, tag, buf); - netio_write(conn.fd, buf, decode_u32le(buf)); + if (read_at_least(conn.fd, buf, 7, &done)) + goto close; + struct lib9p_req req = { + .parent_sess = &sess, + .tag = decode_u16le(&buf[5]), + .net_bytes = buf, + .ctx = { + .version = sess.version, + .max_msg_size = sess.max_msg_size, + }, + }; + if (goal > sess.max_msg_size) { + lib9p_errorf(&req.ctx, LINUX_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")", + sess.initialized ? "negotiated" : "server", goal, sess.max_msg_size); + respond_error(&req); continue; } - /* Read the rest of the message. */ - while (done < goal) { - ssize_t r = netio_read(conn.fd, &buf[done], sizeof(buf)-done); - if (r < 0) { - fprintf(stderr, "error: read: %s", strerror(-r)); - goto close; - } else if (r == 0) { - fprintf(stderr, "error: read: unexpected EOF"); - goto close; - } - done += r; - } + if (read_at_least(conn.fd, buf, goal, &done)) + goto close; - /* Handle the message... */ - if (conn.ctx.version == LIB9P_VER_UNINITIALIZED) { - /* ...synchronously if we haven't negotiated the protocol yet, ... */ - handle_message(&conn, buf); - } else { - /* ...asynchronously if we have. */ - cr_chan_send(&srv->reqch, buf); - cr_pause_and_yield(); - } + /* Handle the message... in another coroutine. */ + sess.refcount++; + cr_chan_send(&srv->reqch, &req); + cr_pause_and_yield(); /* wait for it to have copied req */ } close: - netio_close(conn.fd, true, (--conn.refcount) == 0); - if (conn.refcount) { + netio_close(conn.fd, true, (--sess.refcount) == 0); + if (sess.refcount) { cr_pause_and_yield(); - assert(conn.refcount == 0); + assert(sess.refcount == 0); netio_close(conn.fd, false, true); } } @@ -132,65 +190,118 @@ COROUTINE lib9p_srv_read_cr(void *_srv) { cr_end(); } +/* write coroutine ************************************************************/ + +static void handle_Tversion(struct lib9p_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp); + COROUTINE lib9p_srv_write_cr(void *_srv) { uint8_t net[CONFIG_9P_MAX_MSG_SIZE]; + uint8_t host_req[CONFIG_9P_MAX_HOSTMSG_SIZE]; + uint8_t host_resp[CONFIG_9P_MAX_HOSTMSG_SIZE]; - lib9p_srv *srv = _srv; + struct lib9p_srv *srv = _srv; assert(srv); cr_begin(); for (;;) { - struct lib9p_srvreq req; - cr_chan_recv(&srv->reqch, &req); - memcpy(net, req.msg, decode_u32le(req.msg)); - req.conn->refcount++; - cr_unpause(req.conn->reader); + /* Receive the request from the reader coroutine. */ + struct lib9p_req req; + struct lib9p_req *_req_p; + cr_chan_recv(&srv->reqch, &_req_p); + req = *_req_p; + memcpy(net, req.net_bytes, decode_u32le(req.net_bytes)); + req.net_bytes = net; + cr_unpause(req.parent_sess->parent_conn->reader); /* notify that we've copied req */ - handle_message(&req.conn, net); + /* Unmarshal it. */ + enum lib9p_msg_type typ = net[4]; + if (typ % 2 != 0) { + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "expected a T-message but got an R-message: message_type=%s", + lib9p_msg_type_str(typ)); + goto write; + } + ssize_t host_size = lib9p_unmarshal_size(&req.ctx, net); + if (host_size < 0) + goto write; + if ((size_t)host_size > sizeof(host_req)) { + lib9p_errorf(&req.ctx, LINUX_EMSGSIZE, "unmarshalled payload larger than server limit (%zu > %zu)", + host_size, sizeof(host_req)); + goto write; + } + lib9p_unmarshal(&req.ctx, net, &typ, &req.tag, host_req); + + /* Handle it. */ + switch (typ) { + case LIB9P_TYP_Tversion: + handle_Tversion(&req, (struct lib9p_msg_Tversion *)host_req, (struct lib9p_msg_Rversion *)host_resp); + break; + case LIB9P_TYP_Tauth: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tattach: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tflush: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Twalk: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Topen: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tcreate: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tread: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Twrite: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tclunk: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tremove: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tstat: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Twstat: + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tsession: /* 9P2000.e */ + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tsread: /* 9P2000.e */ + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + case LIB9P_TYP_Tswrite: /* 9P2000.e */ + lib9p_errorf(&req.ctx, LINUX_EOPNOTSUPP, "%s not yet implemented", lib9p_msg_type_str(typ)); + break; + default: + assert(false); + } - if ((--req.conn->refcount) == 0) - cr_unpause(req.conn->reader); + write: + if (req.ctx.err_num || req.ctx.err_msg[0]) + respond_error(&req); + else { + if (lib9p_marshal(&req.ctx, typ+1, req.tag, host_resp, net)) + goto write; + cr_mutex_lock(&req.parent_sess->parent_conn->writelock); + netio_write(req.parent_sess->parent_conn->fd, net, decode_u32le(net)); + cr_mutex_unlock(&req.parent_sess->parent_conn->writelock); + } + if ((--req.parent_sess->refcount) == 0) + cr_unpause(req.parent_sess->parent_conn->reader); } cr_end(); } -void handle_message(struct lib9p_srvconn *conn, uint8_t *net) { - uint8_t host[CONFIG_9P_MAX_MSG_SIZE]; - - struct lib9p_ctx ctx = { - .version = req.conn->version, - .max_msg_size = req.conn->max_msg_size, - }; - - size_t host_size = lib9p_unmarshal_size(&ctx, net); - if (host_size == (size_t)-1) - goto write; - if (host_size > sizeof(host)) { - lib9p_errorf(&ctx, LINUX_EMSGSIZE, "unmarshalled payload larger than server limit (%zu > %zu)", host_size, sizeof(host)); - goto write; - } - - uint16_t tag; - uint8_t typ = lib9p_unmarshal(&ctx, net, &tag, host); - if (typ == (uint8_t)-1) - goto write; - if (typ % 2 != 0) { - lib9p_errorf(&ctx, LINUX_EOPNOTSUPP, "expected a T-message but got an R-message"); - goto write; - } - - TODO; - - write: - if (ctx.err_num || ctx.err_msg[0]) - marshal_error(&ctx, net); - else - TODO; - netio_write(req.conn->fd, net, decode_u32le(net)); -} - -void _version(struct lib9p_srv_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp) { +static void handle_Tversion(struct lib9p_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp) { enum lib9p_version version = LIB9P_VER_unknown; if (req->version.len >= 6 && @@ -201,30 +312,23 @@ void _version(struct lib9p_srv_req *ctx, struct lib9p_msg_Tversion *req, struct '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) + if (strcmp((char *)&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 if (strcmp((char *)&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); - + uint32_t min_msg_size = rerror_overhead_for_version(version, ctx->net_bytes); 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->version.utf8 = (uint8_t *)lib9p_version_str(version); + resp->version.len = strlen((char *)resp->version.utf8); 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 8a48b85..0c03bd5 100644 --- a/lib9p/types.c +++ b/lib9p/types.c @@ -24,7 +24,7 @@ const char *lib9p_version_str(enum lib9p_version ver) { return version_strs[ver]; } -static const char *msg_type_strs[0xFF] = { +static const char *msg_type_strs[0x100] = { [0x00] = "0x00", [0x01] = "0x01", [0x02] = "0x02", @@ -917,9 +917,6 @@ static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach * } static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) { - /* Truncate the error-string if necessary to avoid returning ERANGE. */ - if (((uint32_t)val->ename.len) + ctx->ctx->Rerror_overhead > ctx->ctx->max_msg_size) - val->ename.len = ctx->ctx->max_msg_size - ctx->ctx->Rerror_overhead; return marshal_s(ctx, &val->ename) || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->errno) ); } diff --git a/lib9p/types.gen b/lib9p/types.gen index 590e707..a597022 100755 --- a/lib9p/types.gen +++ b/lib9p/types.gen @@ -359,7 +359,7 @@ const char *{idprefix}version_str(enum {idprefix}version ver) {{ return version_strs[ver]; }} -static const char *msg_type_strs[0xFF] = {{ +static const char *msg_type_strs[0x100] = {{ """ id2name: dict[int, str] = {} for msg in structs: @@ -577,11 +577,6 @@ static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { ret += "}\n" continue - if struct.name == "Rerror": # SPECIAL - ret += "\n\t/* Truncate the error-string if necessary to avoid returning ERANGE. */" - ret += "\n\tif (((uint32_t)val->ename.len) + ctx->ctx->Rerror_overhead > ctx->ctx->max_msg_size)" - ret += "\n\t\tval->ename.len = ctx->ctx->max_msg_size - ctx->ctx->Rerror_overhead;" - prefix0 = "\treturn " prefix1 = "\t || " prefix2 = "\t " diff --git a/libcr_ipc/include/libcr_ipc/_common.h b/libcr_ipc/include/libcr_ipc/_common.h new file mode 100644 index 0000000..5efe964 --- /dev/null +++ b/libcr_ipc/include/libcr_ipc/_common.h @@ -0,0 +1,19 @@ +/* libcr_ipc/_common.h - TODO + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#ifndef _COROUTINE__COMMON_H_ +#define _COROUTINE__COMMON_H_ + +struct _cr_ipc_cid_list { + cid_t val; + struct _cr_ipc_cid_list *next; +}; + +#define _cr_ipc_static_assert_sametype(a, b, msg) \ + static_assert(_Generic(a, typeof(b): 1, default: 0), msg) +#define _cr_ipc_str(a) #a + +#endif /* _COROUTINE__COMMON_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h index 66ea1c4..ca53fc2 100644 --- a/libcr_ipc/include/libcr_ipc/chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -20,14 +20,14 @@ * cr_chan_t(val_t) returns the type definition for a channel on * that transports values of type `val_t`. */ -#define cr_chan_t(val_t) struct { \ - bool ok_to_write; \ - cid_t reader, *tail_reader; \ - val_t *reader_val; \ - \ - bool ok_to_read; \ - cid_t writer, *tail_writer; \ - val_t *writer_val; \ +#define cr_chan_t(val_t) struct { \ + bool ok_to_write; \ + cid_t reader, *tail_reader; \ + val_t *reader_val; \ + \ + bool ok_to_read; \ + cid_t writer, *tail_writer; \ + val_t *writer_val; \ } /* These "functions" are preprocessor macros instead of real C @@ -37,67 +37,76 @@ /** * ch_chan_send(*ch, val) sends `val` over `ch`. */ -#define cr_chan_send(ch, _val) do { \ - if ((ch)->ok_to_write) { /* non-blocking */ \ - *((ch)->reader_val) = (_val); \ - (ch)->ok_to_write = false; \ - cr_unpause((ch)->reader); \ - } else { /* blocking */ \ - cid_t next = 0; \ - if ((ch)->writer) { \ - *((ch)->tail_writer) = cr_getcid(); \ - (ch)->tail_writer = &next; \ - cr_pause_and_yield(); \ - } else { \ - (ch)->writer = cr_getcid(); \ - (ch)->tail_writer = &next; \ - } \ - assert((ch)->writer == cr_getcid()); \ - (ch)->writer_val = &(_val); \ - (ch)->ok_to_read = true; \ - cr_pause_and_yield(); \ - assert((ch)->ok_to_read == false); \ - if (next) { \ - (ch)->writer = next; \ - cr_unpause(next); \ - } else { \ - (ch)->writer = 0; \ - (ch)->tail_writer = NULL; \ - } \ - } \ +#define cr_chan_send(ch, _val) do { \ + _cr_ipc_static_assert_sametype(_val, *(ch)->reader_val, \ + "wrong val type for chan: " \ + _cr_ipc_str(_val)); \ + assert(ch); \ + if ((ch)->ok_to_write) { /* non-blocking */ \ + *((ch)->reader_val) = (_val); \ + (ch)->ok_to_write = false; \ + cr_unpause((ch)->reader); \ + } else { /* blocking */ \ + typeof(*(ch)->writer_val) _val_lvalue = _val; \ + cid_t next = 0; \ + if ((ch)->writer) { \ + *((ch)->tail_writer) = cr_getcid(); \ + (ch)->tail_writer = &next; \ + cr_pause_and_yield(); \ + } else { \ + (ch)->writer = cr_getcid(); \ + (ch)->tail_writer = &next; \ + } \ + assert((ch)->writer == cr_getcid()); \ + (ch)->writer_val = &_val_lvalue; \ + (ch)->ok_to_read = true; \ + cr_pause_and_yield(); \ + assert((ch)->ok_to_read == false); \ + if (next) { \ + (ch)->writer = next; \ + cr_unpause(next); \ + } else { \ + (ch)->writer = 0; \ + (ch)->tail_writer = NULL; \ + } \ + } \ } while (0) /** * cr_chan_recv(ch, val_p) reads a value from ch into `*val_p`. */ -#define cr_chan_recv(ch, _val_p) do { \ - if ((ch)->ok_to_read) { /* non-blocking */ \ - *(_val_p) = *((ch)->writer_val); \ - (ch)->ok_to_read = false; \ - cr_unpause((ch)->writer; \ - } else { /* blocking */ \ - cid_t next = 0; \ - if ((ch)->reader) { \ - *((ch)->tail_reader) = cr_getcid(); \ - (ch)->tail_reader = &next; \ - cr_pause_and_yield(); \ - } else { \ - (ch)->reader = cr_getcid(); \ - (ch)->tail_reader = &next; \ - } \ - assert((ch)->reader == cr_getcid()); \ - (ch)->reader_val = (_val_p); \ - (ch)->ok_to_write = true; \ - cr_pause_and_yield(); \ - assert((ch)->ok_to_write == false); \ - if (next) { \ - (ch)->reader = next; \ - cr_unpause(next); \ - } else { \ - (ch)->reader = 0; \ - (ch)->tail_reader = NULL; \ - } \ - } \ +#define cr_chan_recv(ch, _val_p) do { \ + _cr_ipc_static_assert_sametype(_val_p, (ch)->reader_val, \ + "wrong val_p type for chan: " \ + _cr_ipc_str(_val_p)); \ + assert(ch); \ + if ((ch)->ok_to_read) { /* non-blocking */ \ + *(_val_p) = *((ch)->writer_val); \ + (ch)->ok_to_read = false; \ + cr_unpause((ch)->writer); \ + } else { /* blocking */ \ + cid_t next = 0; \ + if ((ch)->reader) { \ + *((ch)->tail_reader) = cr_getcid(); \ + (ch)->tail_reader = &next; \ + cr_pause_and_yield(); \ + } else { \ + (ch)->reader = cr_getcid(); \ + (ch)->tail_reader = &next; \ + } \ + assert((ch)->reader == cr_getcid()); \ + (ch)->reader_val = (_val_p); \ + (ch)->ok_to_write = true; \ + cr_pause_and_yield(); \ + assert((ch)->ok_to_write == false); \ + if (next) { \ + (ch)->reader = next; \ + cr_unpause(next); \ + } else { \ + (ch)->reader = 0; \ + (ch)->tail_reader = NULL; \ + } \ + } \ } while (0) /** diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h index 38ebde0..1a82423 100644 --- a/libcr_ipc/include/libcr_ipc/mutex.h +++ b/libcr_ipc/include/libcr_ipc/mutex.h @@ -11,17 +11,14 @@ #include <libcr/coroutine.h> /* for cid_t */ -struct _cr_mutex_cid_list { - cid_t val; - struct _cr_mutex_cid_list *next; -}; +#include <libcr_ipc/_common.h> /* for struct _cr_ipc_list_t */ /** * A cr_mutex_t is a fair mutex. */ typedef struct { bool locked; - struct _cr_mutex_cid_list *head, **tail; + struct _cr_ipc_cid_list *head, **tail; } cr_mutex_t; /** @@ -41,6 +38,6 @@ void cr_mutex_lock(cr_mutex_t *); * @yields never * @may_run_in coroutine */ -void cr_mutex_unluck(cr_mutex_t *); +void cr_mutex_unlock(cr_mutex_t *); #endif /* _COROUTINE_MUTEX_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index 3c42f34..2525ba8 100644 --- a/libcr_ipc/include/libcr_ipc/rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -15,6 +15,8 @@ #include <libcr/coroutine.h> +#include <libcr_ipc/_common.h> /* for _cr_ipc_* */ + /** * cr_rpc_t(req_t, resp_t) returns the type definition for a * rpc-channel on which the requester submits a value of type `req_t` @@ -31,10 +33,6 @@ resp_t *resp_p; \ } -#define _cr_rpc_static_assert_sametype(a, b, msg) \ - static_assert(_Generic(a, typeof(b): 1, default: 0), msg) -#define _cr_rpc_str(a) #a - /* These "functions" are preprocessor macros instead of real C * functions so that the compiler can do type-checking instead of * having these functions take `void*`. */ @@ -48,12 +46,12 @@ */ #define cr_rpc_req(ch, _resp_p, _req) do { \ typeof(_req) _req_lvalue = _req; \ - _cr_rpc_static_assert_sametype(_resp_p, (ch)->resp_p, \ + _cr_ipc_static_assert_sametype(_resp_p, (ch)->resp_p, \ "wrong resp_p type for rpc chan: " \ - _cr_rpc_str(_resp_p)); \ - _cr_rpc_static_assert_sametype(&_req_lvalue, (ch)->req_p, \ + _cr_ipc_str(_resp_p)); \ + _cr_ipc_static_assert_sametype(&_req_lvalue, (ch)->req_p, \ "wrong req type for rpc chan: " \ - _cr_rpc_str(_req)); \ + _cr_ipc_str(_req)); \ assert(ch); \ assert(_resp_p); \ cid_t next = 0; \ @@ -98,9 +96,9 @@ * Blocking: Maybe. */ #define cr_rpc_recv_req(ch, _req_p) do { \ - _cr_rpc_static_assert_sametype(_req_p, (ch)->req_p, \ + _cr_ipc_static_assert_sametype(_req_p, (ch)->req_p, \ "wrong req_p type for rpc chan: " \ - _cr_rpc_str(_req_p)); \ + _cr_ipc_str(_req_p)); \ assert(ch); \ assert(_req_p); \ (ch)->responder = cr_getcid(); \ @@ -117,9 +115,9 @@ * Blocking: Never. */ #define cr_rpc_send_resp(ch, _resp) do { \ - _cr_rpc_static_assert_sametype(_resp, *(ch)->resp_p, \ + _cr_ipc_static_assert_sametype(_resp, *(ch)->resp_p, \ "wrong resp type for rpc chan: " \ - _cr_rpc_str(_reps)); \ + _cr_ipc_str(_reps)); \ assert(ch); \ (ch)->responder = 0; \ *((ch)->resp_p) = (_resp); \ diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index 454eb5d..236e7e5 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -11,10 +11,7 @@ #include <libcr/coroutine.h> /* for cid_t */ -struct _cr_sema_cid_list { - cid_t val; - struct _cr_sema_cid_list *next; -}; +#include <libcr_ipc/_common.h> /* for struct _cr_ipc_list_t */ /** * A cr_sema_t is a fair unbounded[1] counting semaphore. @@ -24,7 +21,7 @@ struct _cr_sema_cid_list { typedef volatile struct { int cnt; - struct _cr_sema_cid_list *head, **tail; + struct _cr_ipc_cid_list *head, **tail; /* locked indicates that a call from within a coroutine is is * messing with ->{head,tail}, so a signal handler can't read * it. */ diff --git a/libcr_ipc/mutex.c b/libcr_ipc/mutex.c index c5cea96..198c738 100644 --- a/libcr_ipc/mutex.c +++ b/libcr_ipc/mutex.c @@ -4,6 +4,8 @@ * SPDX-Licence-Identifier: AGPL-3.0-or-later */ +#include <assert.h> + #include <libcr_ipc/mutex.h> void cr_mutex_lock(cr_mutex_t *mu) { @@ -14,7 +16,7 @@ void cr_mutex_lock(cr_mutex_t *mu) { mu->locked = true; return; } - struct _cr_mutex_cid_list self = { + struct _cr_ipc_cid_list self = { .val = cr_getcid(), .next = NULL, }; diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c index 9645a41..a3efb57 100644 --- a/libcr_ipc/sema.c +++ b/libcr_ipc/sema.c @@ -59,7 +59,7 @@ void cr_sema_signal(cr_sema_t *sema) { } void cr_sema_wait(cr_sema_t *sema) { - struct _cr_sema_cid_list self = { + struct _cr_ipc_cid_list self = { .val = cr_getcid(), .next = NULL, }; |