/* lib9p_util/coroutine.c - 9P access to libcr process information * * Copyright (C) 2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include #include #include #include #include #include /******************************************************************************/ LO_IMPLEMENTATION_C(lib9p_srv_file, struct coroutine_file, coroutine_file); static_assert(CONFIG_COROUTINE_NUM < 1000); #define MAX(a, b) ( ((a)>(b)) ? (a) : (b) ) static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8); #define SIZE_MAX_BASE10_LEN (sizeof(size_t) == 4 ? 10 : 20) struct coroutine_fio { struct coroutine_file *parent; size_t buf_len; char buf[ (3 +2 /* cid */ +MAX(CONFIG_COROUTINE_NAME_LEN, 6) +2 /* name */ +14 +2 /* state; len("CR_INITIALIZING")=14 */ +MAX(SIZE_MAX_BASE10_LEN, 9) +2 /* stack_cap */ +MAX(SIZE_MAX_BASE10_LEN, 9) +2 /* stack_max */ +MAX(SIZE_MAX_BASE10_LEN, 9) +2 /* stack_cur */ +MAX(SIZE_MAX_BASE10_LEN, 14) +2 /* heap_bytes_cur */ +MAX(SIZE_MAX_BASE10_LEN, 13) +1 /* heap_segs_cur */ )*(CONFIG_COROUTINE_NUM+4)]; }; LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct coroutine_fio, coroutine_fio); /* srv_file *******************************************************************/ void coroutine_file_free(struct coroutine_file *self) { assert(self); } struct lib9p_qid coroutine_file_qid(struct coroutine_file *self) { assert(self); return (struct lib9p_qid){ .type = LIB9P_QT_FILE, .vers = 1, .path = self->pathnum, }; } error coroutine_file_stat(struct coroutine_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) { assert(self); assert(ctx); assert(out); *out = ((struct lib9p_srv_stat){ .qid = coroutine_file_qid(self), .mode = 0444, .atime_sec = UTIL9P_ATIME, .mtime_sec = UTIL9P_MTIME, .size = 0, .name = lib9p_str(self->name), .owner_uid = { .name = lib9p_str("root"), .num = 0 }, .owner_gid = { .name = lib9p_str("root"), .num = 0 }, .last_modifier_uid = { .name = lib9p_str("root"), .num = 0 }, .extension = lib9p_str(NULL), }); return ERROR_NULL; } error coroutine_file_wstat(struct coroutine_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) { assert(self); assert(ctx); return error_new(E_POSIX_EROFS, "read-only part of filesystem"); } error coroutine_file_remove(struct coroutine_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); return error_new(E_POSIX_EROFS, "read-only part of filesystem"); } LIB9P_SRV_NOTDIR(, struct coroutine_file, coroutine_file); lib9p_srv_fio_or_error coroutine_file_fopen(struct coroutine_file *self, struct lib9p_srv_ctx *ctx, bool LM_UNUSED(rd), bool LM_UNUSED(wr), bool LM_UNUSED(trunc)) { assert(self); assert(ctx); struct coroutine_fio *ret = heap_alloc(1, struct coroutine_fio); ret->parent = self; return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret)); } /* srv_fio ********************************************************************/ static uint32_t coroutine_fio_iounit(struct coroutine_fio *self) { assert(self); return sizeof(self->buf); } static void coroutine_fio_iofree(struct coroutine_fio *self) { assert(self); heap_free(self); } static struct lib9p_qid coroutine_fio_ioqid(struct coroutine_fio *self) { assert(self); assert(self->parent); return coroutine_file_qid(self->parent); } static error coroutine_fio_pread(struct coroutine_fio *self, struct lib9p_srv_ctx *ctx, lo_interface io_writer dst, uint64_t byte_offset, uint32_t byte_count) { assert(self); assert(ctx); if (byte_offset == 0 || self->buf_len == 0) { struct fmt_buf _w = { .dat = self->buf, .cap = sizeof(self->buf) }; lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); struct heap_info heap_info; heap_usage(&heap_info); size_t w_cid = 3; size_t w_name = MAX(CONFIG_COROUTINE_NAME_LEN, strlen("KERNEL")); size_t w_state = strlen("CR_INITIALZING"); size_t w_stack_cap = MAX(SIZE_MAX_BASE10_LEN, strlen("stack_cap")); size_t w_stack_max = MAX(SIZE_MAX_BASE10_LEN, strlen("stack_max")); size_t w_stack_cur = MAX(SIZE_MAX_BASE10_LEN, strlen("stack_cur")); size_t w_heap_bytes_cur = MAX(SIZE_MAX_BASE10_LEN, strlen("heap_bytes_cur")); size_t w_heap_segs_cur = MAX(SIZE_MAX_BASE10_LEN, strlen("heap_segs_cur")); fmt_print(w, (ljust, w_cid, ' ', "cid"), " ", (ljust, w_name, ' ', "name"), " ", (ljust, w_state, ' ', "state"), " ", (rjust, w_stack_cap, ' ', "stack_cap"), " ", (rjust, w_stack_max, ' ', "stack_max"), " ", (rjust, w_stack_cur, ' ', "stack_cur"), " ", (rjust, w_heap_bytes_cur, ' ', "heap_bytes_cur"), " ", (rjust, w_heap_segs_cur, ' ', "heap_segs_cur"), "\n"); fmt_print(w, (ljust, w_cid, ' ', "-"), " ", (ljust, w_name, ' ', "KERNEL"), " ", (ljust, w_state, ' ', "-"), " ", (rjust, w_stack_cap, ' ', "?"), " ", (rjust, w_stack_max, ' ', "?"), " ", (rjust, w_stack_cur, ' ', "?"), " ", (rjust, w_heap_bytes_cur, ' ', heap_info.allocated[HEAP_CID_KERNEL].sum), " ", (rjust, w_heap_segs_cur, ' ', heap_info.allocated[HEAP_CID_KERNEL].nseg), "\n"); for (cid_t cid = 1; cid <= CONFIG_COROUTINE_NUM; cid++) { struct cr_cid_info info; cr_cid_info(cid, &info); if (info.state == CR_NONE) continue; fmt_print(w, (ljust, w_cid, ' ', cid), " ", (ljust, w_name, ' ', (strn, info.name, sizeof(info.name))), " ", (ljust, w_state, ' ', coroutine_state_str(info.state)), " ", (rjust, w_stack_cap, ' ', info.stack_cap), " ", (rjust, w_stack_max, ' ', info.stack_max), " ", (rjust, w_stack_cur, ' ', info.stack_cur), " ", (rjust, w_heap_bytes_cur, ' ', heap_info.allocated[cid].sum), " ", (rjust, w_heap_segs_cur, ' ', heap_info.allocated[cid].nseg), "\n"); } fmt_print(w, (ljust, w_cid, ' ', "-"), " ", (ljust, w_name, ' ', "HEAP"), " ", (ljust, w_state, ' ', "-"), " ", (rjust, w_stack_cap, ' ', "-"), " ", (rjust, w_stack_max, ' ', "-"), " ", (rjust, w_stack_cur, ' ', "-"), " ", (rjust, w_heap_bytes_cur, ' ', heap_info.internal_use), " ", (rjust, w_heap_segs_cur, ' ', "-"), "\n"); fmt_print(w, (ljust, w_cid, ' ', "-"), " ", (ljust, w_name, ' ', "FREE"), " ", (ljust, w_state, ' ', "-"), " ", (rjust, w_stack_cap, ' ', "-"), " ", (rjust, w_stack_max, ' ', "-"), " ", (rjust, w_stack_cur, ' ', "-"), " ", (rjust, w_heap_bytes_cur, ' ', heap_info.allocated[HEAP_CID_UNALLOCATED].sum), " ", (rjust, w_heap_segs_cur, ' ', heap_info.allocated[HEAP_CID_UNALLOCATED].nseg), "\n"); assert(_w.len <= _w.cap); self->buf_len = _w.len; } if (byte_offset > (uint64_t)self->buf_len) return error_new(E_POSIX_EINVAL, "offset is past end-of-file length"); size_t beg_off = (size_t)byte_offset; size_t end_off = beg_off + (size_t)byte_count; if (end_off > self->buf_len) end_off = self->buf_len; return io_write(dst, &((char *)(self->buf))[beg_off], end_off-beg_off).err; } static uint32_t_or_error coroutine_fio_pwrite(struct coroutine_fio *self, struct lib9p_srv_ctx *ctx, const void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset)) { assert(self); assert(ctx); return ERROR_NEW_ERR(uint32_t, error_new(E_POSIX_EROFS, "read-only part of filesystem")); }