Skip to content

Commit 01709bf

Browse files
committed
Refine coroutine for hart scheduling
This refines I/O coroutine API that was designed for peripheral I/O but provided no benefit over inline polling.
1 parent 8f0c958 commit 01709bf

File tree

4 files changed

+334
-177
lines changed

4 files changed

+334
-177
lines changed

coro.c

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ typedef struct {
201201
/* Internal coroutine structure */
202202

203203
typedef struct {
204+
uint32_t id; /* Coroutine identifier */
204205
void (*func)(void *); /* Entry point function (user-provided) */
205206
void *user_data; /* User data (hart pointer) */
206207
coro_state_t state; /* Current state */
@@ -213,7 +214,8 @@ typedef struct {
213214

214215
static struct {
215216
coro_t **coroutines; /* Array of coroutine pointers */
216-
uint32_t n_hart; /* Number of harts */
217+
uint32_t total_slots; /* Total number of coroutine slots */
218+
uint32_t hart_slots; /* Number of slots reserved for harts */
217219
uint32_t current_hart; /* Currently executing hart ID */
218220
bool initialized; /* True if subsystem initialized */
219221
coro_t *running; /* Currently running coroutine */
@@ -376,25 +378,27 @@ static void coro_entry_wrapper(void *arg)
376378

377379
/* Public API implementation */
378380

379-
bool coro_init(uint32_t n_hart)
381+
bool coro_init(uint32_t total_slots, uint32_t hart_slots)
380382
{
381383
if (coro_state.initialized) {
382384
fprintf(stderr, "coro_init: already initialized\n");
383385
return false;
384386
}
385387

386-
if (n_hart == 0 || n_hart > 32) {
387-
fprintf(stderr, "coro_init: invalid n_hart=%u\n", n_hart);
388+
if (total_slots == 0 || total_slots > 256 || hart_slots > total_slots) {
389+
fprintf(stderr, "coro_init: invalid slots (total=%u, hart=%u)\n",
390+
total_slots, hart_slots);
388391
return false;
389392
}
390393

391-
coro_state.coroutines = calloc(n_hart, sizeof(coro_t *));
394+
coro_state.coroutines = calloc(total_slots, sizeof(coro_t *));
392395
if (!coro_state.coroutines) {
393396
fprintf(stderr, "coro_init: failed to allocate coroutines array\n");
394397
return false;
395398
}
396399

397-
coro_state.n_hart = n_hart;
400+
coro_state.total_slots = total_slots;
401+
coro_state.hart_slots = hart_slots;
398402
coro_state.current_hart = CORO_HART_ID_IDLE;
399403
coro_state.initialized = true;
400404
coro_state.running = NULL;
@@ -407,7 +411,7 @@ void coro_cleanup(void)
407411
if (!coro_state.initialized)
408412
return;
409413

410-
for (uint32_t i = 0; i < coro_state.n_hart; i++) {
414+
for (uint32_t i = 0; i < coro_state.total_slots; i++) {
411415
if (coro_state.coroutines[i]) {
412416
coro_t *co = coro_state.coroutines[i];
413417
if (co->context) {
@@ -423,22 +427,23 @@ void coro_cleanup(void)
423427

424428
free(coro_state.coroutines);
425429
coro_state.coroutines = NULL;
426-
coro_state.n_hart = 0;
430+
coro_state.total_slots = 0;
431+
coro_state.hart_slots = 0;
427432
coro_state.current_hart = CORO_HART_ID_IDLE; /* Reset to idle state */
428433
coro_state.initialized = false;
429434
coro_state.running = NULL;
430435
tls_running_coro = NULL; /* Reset TLS as well */
431436
}
432437

433-
bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
438+
bool coro_create_hart(uint32_t slot_id, void (*func)(void *), void *arg)
434439
{
435440
if (!coro_state.initialized) {
436441
fprintf(stderr, "coro_create_hart: not initialized\n");
437442
return false;
438443
}
439444

440-
if (hart_id >= coro_state.n_hart) {
441-
fprintf(stderr, "coro_create_hart: invalid hart_id=%u\n", hart_id);
445+
if (slot_id >= coro_state.total_slots) {
446+
fprintf(stderr, "coro_create_hart: invalid slot_id=%u\n", slot_id);
442447
return false;
443448
}
444449

@@ -447,9 +452,9 @@ bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
447452
return false;
448453
}
449454

450-
if (coro_state.coroutines[hart_id]) {
451-
fprintf(stderr, "coro_create_hart: hart %u already has coroutine\n",
452-
hart_id);
455+
if (coro_state.coroutines[slot_id]) {
456+
fprintf(stderr, "coro_create_hart: slot %u already has coroutine\n",
457+
slot_id);
453458
return false;
454459
}
455460

@@ -461,8 +466,9 @@ bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
461466
}
462467

463468
/* Store user function and data */
469+
co->id = slot_id;
464470
co->func = func;
465-
co->user_data = hart;
471+
co->user_data = arg;
466472
co->state = CORO_STATE_SUSPENDED;
467473

468474
/* Allocate context */
@@ -496,31 +502,32 @@ bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
496502
}
497503
#endif
498504

499-
coro_state.coroutines[hart_id] = co;
505+
coro_state.coroutines[slot_id] = co;
500506
return true;
501507
}
502508

503-
void coro_resume_hart(uint32_t hart_id)
509+
void coro_resume_hart(uint32_t slot_id)
504510
{
505-
if (!coro_state.initialized || hart_id >= coro_state.n_hart) {
506-
fprintf(stderr, "coro_resume_hart: invalid hart_id=%u\n", hart_id);
511+
if (!coro_state.initialized || slot_id >= coro_state.total_slots) {
512+
fprintf(stderr, "coro_resume_hart: invalid slot_id=%u\n", slot_id);
507513
return;
508514
}
509515

510-
coro_t *co = coro_state.coroutines[hart_id];
516+
coro_t *co = coro_state.coroutines[slot_id];
511517
if (!co || !co->context) {
512-
fprintf(stderr, "coro_resume_hart: hart %u has no coroutine\n",
513-
hart_id);
518+
fprintf(stderr, "coro_resume_hart: slot %u has no coroutine\n",
519+
slot_id);
514520
return;
515521
}
516522

517523
if (co->state != CORO_STATE_SUSPENDED) {
518-
fprintf(stderr, "coro_resume_hart: hart %u not suspended (state=%d)\n",
519-
hart_id, co->state);
524+
/* This may happen if a coroutine is waiting on I/O and the main loop
525+
* tries to resume it. It is not a fatal error.
526+
*/
520527
return;
521528
}
522529

523-
coro_state.current_hart = hart_id;
530+
coro_state.current_hart = slot_id;
524531
co->state = CORO_STATE_RUNNING;
525532
jump_into(co);
526533
}
@@ -547,12 +554,12 @@ void coro_yield(void)
547554
jump_out(co);
548555
}
549556

550-
bool coro_is_suspended(uint32_t hart_id)
557+
bool coro_is_suspended(uint32_t slot_id)
551558
{
552-
if (!coro_state.initialized || hart_id >= coro_state.n_hart)
559+
if (!coro_state.initialized || slot_id >= coro_state.hart_slots)
553560
return false;
554561

555-
coro_t *co = coro_state.coroutines[hart_id];
562+
coro_t *co = coro_state.coroutines[slot_id];
556563
if (!co || !co->context)
557564
return false;
558565

coro.h

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,39 @@
1-
/* Lightweight coroutine for multi-hart execution */
2-
31
#pragma once
42

53
#include <stdbool.h>
4+
#include <stddef.h>
65
#include <stdint.h>
76

87
/* Forward declaration */
98
typedef struct __hart_internal hart_t;
109

11-
/* Initialize coroutine subsystem for a VM with n_hart cores */
12-
bool coro_init(uint32_t n_hart);
10+
/* Sentinel value when no coroutine is executing */
11+
#define CORO_INVALID_ID UINT32_MAX
12+
13+
/* Initialize coroutine subsystem for SMP hart scheduling.
14+
* total_slots: total coroutine slots (usually n_hart)
15+
* hart_slots: number of actual CPU harts
16+
*/
17+
bool coro_init(uint32_t total_slots, uint32_t hart_slots);
1318

1419
/* Cleanup coroutine subsystem */
1520
void coro_cleanup(void);
1621

17-
/* Create coroutine for a specific hart.
18-
* @hart_id: Hart identifier (0 to n_hart-1)
19-
* @func: Entry point function for the coroutine
20-
* @hart: User data (hart_t pointer) passed to the entry function
21-
*
22-
* Returns: true on success, false on failure
22+
/* Create coroutine for a hart.
23+
* slot_id: Hart identifier
24+
* func: Entry point (hart execution loop)
25+
* arg: User data (hart_t pointer)
2326
*/
24-
bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart);
27+
bool coro_create_hart(uint32_t slot_id, void (*func)(void *), void *arg);
2528

26-
/* Resume execution of a specific hart's coroutine
27-
* The coroutine will execute until it yields or terminates.
28-
*/
29-
void coro_resume_hart(uint32_t hart_id);
29+
/* Resume execution of a hart coroutine */
30+
void coro_resume_hart(uint32_t slot_id);
3031

31-
/* Yield from current hart (called from WFI)
32-
* Suspends the current coroutine and returns control to the scheduler.
33-
*/
32+
/* Yield from current hart (called from WFI) */
3433
void coro_yield(void);
3534

36-
/* Check if a hart's coroutine is suspended (waiting in WFI)
37-
* Returns: true if suspended, false otherwise
38-
*/
39-
bool coro_is_suspended(uint32_t hart_id);
35+
/* Check if hart is suspended (in WFI) */
36+
bool coro_is_suspended(uint32_t slot_id);
4037

41-
/* Get the currently running hart ID
42-
* Returns: Hart ID of the currently executing coroutine, or UINT32_MAX if idle
43-
*/
44-
uint32_t coro_current_hart_id(void);
38+
/* Get currently executing hart ID */
39+
uint32_t coro_current_hart_id(void);

device.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#if SEMU_HAS(VIRTIONET)
4+
#include <poll.h>
45
#include "netdev.h"
56
#endif
67
#include "riscv.h"
@@ -121,8 +122,15 @@ void virtio_net_write(hart_t *core,
121122
uint8_t width,
122123
uint32_t value);
123124
void virtio_net_refresh_queue(virtio_net_state_t *vnet);
125+
size_t virtio_net_collect_fds(virtio_net_state_t *vnet,
126+
struct pollfd *pfds,
127+
size_t max);
128+
void virtio_net_handle_fds(virtio_net_state_t *vnet,
129+
struct pollfd *pfds,
130+
size_t count);
124131

125132
void virtio_net_recv_from_peer(void *peer);
133+
void virtio_net_coro_entry(void *arg);
126134

127135
bool virtio_net_init(virtio_net_state_t *vnet, const char *name);
128136
#endif /* SEMU_HAS(VIRTIONET) */
@@ -455,4 +463,4 @@ typedef struct {
455463
/* The fields used for debug mode */
456464
bool is_interrupted;
457465
int curr_cpuid;
458-
} emu_state_t;
466+
} emu_state_t;

0 commit comments

Comments
 (0)