summaryrefslogtreecommitdiff
path: root/lib9p
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p')
-rw-r--r--lib9p/include/lib9p/srv.h2
-rw-r--r--lib9p/srv.c15
-rwxr-xr-xlib9p/tests/runtest9
-rw-r--r--lib9p/tests/test_server/main.c105
4 files changed, 111 insertions, 20 deletions
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
index 55cf5db..d45d9a4 100644
--- a/lib9p/include/lib9p/srv.h
+++ b/lib9p/include/lib9p/srv.h
@@ -100,6 +100,8 @@ struct lib9p_srv {
/* For internal use */
BEGIN_PRIVATE(LIB9P_SRV_H)
+ unsigned int readers;
+ unsigned int writers;
_lib9p_srv_reqch_t _reqch;
END_PRIVATE(LIB9P_SRV_H)
};
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 7e6402e..10a8a96 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -200,6 +200,8 @@ static void handle_message(struct _lib9p_srv_req *ctx);
assert(srv->rootdir);
assert(listener);
+ srv->readers++;
+
uint32_t initial_rerror_overhead = rerror_overhead_for_version(0, buf);
for (;;) {
@@ -210,7 +212,11 @@ static void handle_message(struct _lib9p_srv_req *ctx);
};
if (!conn.fd) {
nonrespond_errorf("accept: error");
- continue;
+ srv->readers--;
+ if (srv->readers == 0)
+ while (srv->writers > 0)
+ _lib9p_srv_reqch_send_req(&srv->_reqch, NULL);
+ cr_exit();
}
struct _srv_sess sess = {
@@ -287,9 +293,16 @@ COROUTINE lib9p_srv_write_cr(void *_srv) {
assert(srv->rootdir);
cr_begin();
+ srv->writers++;
+
for (;;) {
/* Receive the request from the reader coroutine. ************/
rpc_handle = _lib9p_srv_reqch_recv_req(&srv->_reqch);
+ if (!rpc_handle.req) {
+ srv->writers--;
+ _lib9p_srv_reqch_send_resp(rpc_handle, 0);
+ cr_exit();
+ }
/* Deep-copy the request from the reader coroutine's
* stack to our stack. */
req = *rpc_handle.req;
diff --git a/lib9p/tests/runtest b/lib9p/tests/runtest
index 29d2089..d963c53 100755
--- a/lib9p/tests/runtest
+++ b/lib9p/tests/runtest
@@ -26,7 +26,8 @@ while [[ -d /proc/$server_pid && "$(readlink /proc/$server_pid/fd/4 2>/dev/null)
out=$("${client[@]}" ls -l '')
expect_lines \
'd-r-xr-xr-x M 0 root root 0 Oct 7 15:51 Documentation' \
- '--r--r--r-- M 0 root root 14 Oct 7 15:51 README.md'
+ '--r--r--r-- M 0 root root 14 Oct 7 15:51 README.md' \
+ '---w--w--w- M 0 root root 0 Oct 7 15:51 shutdown'
out=$("${client[@]}" ls -l 'Documentation/')
expect_lines \
@@ -43,3 +44,9 @@ expect_lines \
out=$("${client[@]}" stat 'Documentation/x')
expect_lines \
"'x' 'root' 'root' 'root' q (0000000000000009 1 ) m 0444 at 1728337905 mt 1728337904 l 4 t 0 d 0"
+
+out=$("${client[@]}" write 'shutdown' <<<1)
+expect_lines ''
+
+wait "$server_pid"
+trap - EXIT
diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c
index 8e5011a..71c6cc2 100644
--- a/lib9p/tests/test_server/main.c
+++ b/lib9p/tests/test_server/main.c
@@ -24,7 +24,80 @@
#error config.h must define CONFIG_SRV9P_NUM_CONNS
#endif
-/* implementation *************************************************************/
+/* globals ********************************************************************/
+
+static implements_lib9p_srv_file *get_root(struct lib9p_srv_ctx *, struct lib9p_s);
+
+const char *hexdig = "0123456789abcdef";
+
+struct {
+ struct hostnet_tcp_listener listeners[CONFIG_SRV9P_NUM_CONNS];
+ struct lib9p_srv srv;
+} globals = {
+ .srv = (struct lib9p_srv){
+ .rootdir = get_root,
+ },
+};
+
+/* api ************************************************************************/
+
+struct api_file {
+ implements_lib9p_srv_file;
+
+ uint64_t pathnum;
+};
+
+static implements_lib9p_srv_file *api_clone(implements_lib9p_srv_file *self, struct lib9p_srv_ctx *) { return self; }
+static void api_free(implements_lib9p_srv_file *, struct lib9p_srv_ctx *) {}
+
+static uint32_t api_io(implements_lib9p_srv_file *, struct lib9p_srv_ctx *, lib9p_o_t) { return 0; }
+static void api_wstat(implements_lib9p_srv_file *, struct lib9p_srv_ctx *ctx, struct lib9p_stat) { lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file"); }
+static void api_remove(implements_lib9p_srv_file *, struct lib9p_srv_ctx *ctx) { lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file"); }
+
+static struct lib9p_stat api_stat(implements_lib9p_srv_file *_self, struct lib9p_srv_ctx *) {
+ struct api_file *self = VCALL_SELF(struct api_file, implements_lib9p_srv_file, _self);
+ return (struct lib9p_stat){
+ .kern_type = 0,
+ .kern_dev = 0,
+ .file_qid = {
+ .type = LIB9P_QT_FILE,
+ .vers = 1,
+ .path = self->pathnum,
+ },
+ .file_mode = 0222,
+ .file_atime = 1728337905,
+ .file_mtime = 1728337904,
+ .file_size = 0,
+ .file_name = lib9p_str("shutdown"),
+ .file_owner_uid = lib9p_str("root"),
+ .file_owner_gid = lib9p_str("root"),
+ .file_last_modified_uid = lib9p_str("root"),
+ .file_extension = lib9p_str(NULL),
+ .file_owner_n_uid = 0,
+ .file_owner_n_gid = 0,
+ .file_last_modified_n_uid = 0,
+ };
+}
+static uint32_t api_pwrite(implements_lib9p_srv_file *, struct lib9p_srv_ctx *, void *, uint32_t byte_count, uint64_t) {
+ if (byte_count == 0)
+ return 0;
+ for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++)
+ VCALL(&globals.listeners[i], close);
+ return byte_count;
+}
+
+static struct lib9p_srv_file_vtable api_file_vtable = {
+ .clone = api_clone,
+ .free = api_free,
+
+ .io = api_io,
+ .stat = api_stat,
+ .wstat = api_wstat,
+ .remove = api_remove,
+
+ .pread = NULL,
+ .pwrite = api_pwrite,
+};
/* file tree ******************************************************************/
@@ -74,6 +147,10 @@ static struct util9p_static_dir root = {
},
}),
STATIC_FILE("README.md", README_md),
+ &((struct api_file){
+ .vtable = &api_file_vtable,
+ .pathnum = __COUNTER__,
+ }),
NULL,
},
};
@@ -84,26 +161,17 @@ static implements_lib9p_srv_file *get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx),
/* main ***********************************************************************/
-static COROUTINE read_cr(void *_srv) {
- struct lib9p_srv *srv = _srv;
- assert(srv);
-
+static COROUTINE read_cr(void *_i) {
+ int i = *((int *)_i);
cr_begin();
- struct hostnet_tcp_listener listener;
- hostnet_tcp_listener_init(&listener, 9000);
+ hostnet_tcp_listener_init(&globals.listeners[i], 9000);
- lib9p_srv_read_cr(srv, &listener);
+ lib9p_srv_read_cr(&globals.srv, &globals.listeners[i]);
cr_end();
}
-const char *hexdig = "0123456789abcdef";
-
-struct lib9p_srv srv = {
- .rootdir = get_root,
-};
-
static COROUTINE init_cr(void *) {
cr_begin();
@@ -111,13 +179,13 @@ static COROUTINE init_cr(void *) {
for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) {
char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'};
- if (!coroutine_add(name, read_cr, &srv))
- error(1, 0, "coroutine_add(read_cr, &srv)");
+ if (!coroutine_add(name, read_cr, &i))
+ error(1, 0, "coroutine_add(read_cr, &i)");
}
for (int i = 0; i < 2*CONFIG_SRV9P_NUM_CONNS; i++) {
char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'};
- if (!coroutine_add(name, lib9p_srv_write_cr, &srv))
- error(1, 0, "coroutine_add(lib9p_srv_write_cr, &srv)");
+ if (!coroutine_add(name, lib9p_srv_write_cr, &globals.srv))
+ error(1, 0, "coroutine_add(lib9p_srv_write_cr, &globals.srv)");
}
cr_exit();
@@ -126,4 +194,5 @@ static COROUTINE init_cr(void *) {
int main() {
coroutine_add("init", init_cr, NULL);
coroutine_main();
+ return 0;
}