Skip to content

Commit 4552c62

Browse files
authored
Merge pull request #104 from sysprog21/refine-coroutine
Refine coroutine for hart scheduling
2 parents e2a5b74 + f1045c4 commit 4552c62

File tree

7 files changed

+294
-148
lines changed

7 files changed

+294
-148
lines changed

.ci/common.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ get_timeout() {
4545

4646
case "${OS_TYPE}" in
4747
Darwin)
48-
echo "600"
48+
echo "900"
4949
;;
5050
Linux)
5151
echo "90"

.ci/test-netdev.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ export SCRIPT_DIR
66
source "${SCRIPT_DIR}/common.sh"
77

88
# Override timeout for netdev tests
9-
# Network tests need different timeout: 30s for Linux, 600s for macOS
9+
# Network tests need different timeout: 30s for Linux, 900s for macOS
1010
case "${OS_TYPE}" in
1111
Darwin)
12-
TIMEOUT=600
12+
TIMEOUT=900
1313
;;
1414
Linux)
1515
TIMEOUT=30

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ jobs:
103103
- name: automated test
104104
run: .ci/autorun.sh
105105
shell: bash
106-
timeout-minutes: 15
106+
timeout-minutes: 20
107107
- name: netdev test
108108
# NOTE: vmnet requires sudo privileges which may not be available in GitHub Actions
109109
# This test is conditional and will be skipped if sudo is not available

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 */
@@ -399,25 +401,27 @@ static void coro_entry_wrapper(void *arg)
399401

400402
/* Public API implementation */
401403

402-
bool coro_init(uint32_t n_hart)
404+
bool coro_init(uint32_t total_slots, uint32_t hart_slots)
403405
{
404406
if (coro_state.initialized) {
405407
fprintf(stderr, "coro_init: already initialized\n");
406408
return false;
407409
}
408410

409-
if (n_hart == 0 || n_hart > 32) {
410-
fprintf(stderr, "coro_init: invalid n_hart=%u\n", n_hart);
411+
if (total_slots == 0 || total_slots > 256 || hart_slots > total_slots) {
412+
fprintf(stderr, "coro_init: invalid slots (total=%u, hart=%u)\n",
413+
total_slots, hart_slots);
411414
return false;
412415
}
413416

414-
coro_state.coroutines = calloc(n_hart, sizeof(coro_t *));
417+
coro_state.coroutines = calloc(total_slots, sizeof(coro_t *));
415418
if (!coro_state.coroutines) {
416419
fprintf(stderr, "coro_init: failed to allocate coroutines array\n");
417420
return false;
418421
}
419422

420-
coro_state.n_hart = n_hart;
423+
coro_state.total_slots = total_slots;
424+
coro_state.hart_slots = hart_slots;
421425
coro_state.current_hart = CORO_HART_ID_IDLE;
422426
coro_state.initialized = true;
423427
coro_state.running = NULL;
@@ -430,7 +434,7 @@ void coro_cleanup(void)
430434
if (!coro_state.initialized)
431435
return;
432436

433-
for (uint32_t i = 0; i < coro_state.n_hart; i++) {
437+
for (uint32_t i = 0; i < coro_state.total_slots; i++) {
434438
if (coro_state.coroutines[i]) {
435439
coro_t *co = coro_state.coroutines[i];
436440
if (co->context) {
@@ -446,22 +450,23 @@ void coro_cleanup(void)
446450

447451
free(coro_state.coroutines);
448452
coro_state.coroutines = NULL;
449-
coro_state.n_hart = 0;
453+
coro_state.total_slots = 0;
454+
coro_state.hart_slots = 0;
450455
coro_state.current_hart = CORO_HART_ID_IDLE; /* Reset to idle state */
451456
coro_state.initialized = false;
452457
coro_state.running = NULL;
453458
tls_running_coro = NULL; /* Reset TLS as well */
454459
}
455460

456-
bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
461+
bool coro_create_hart(uint32_t slot_id, void (*func)(void *), void *arg)
457462
{
458463
if (!coro_state.initialized) {
459464
fprintf(stderr, "coro_create_hart: not initialized\n");
460465
return false;
461466
}
462467

463-
if (hart_id >= coro_state.n_hart) {
464-
fprintf(stderr, "coro_create_hart: invalid hart_id=%u\n", hart_id);
468+
if (slot_id >= coro_state.total_slots) {
469+
fprintf(stderr, "coro_create_hart: invalid slot_id=%u\n", slot_id);
465470
return false;
466471
}
467472

@@ -470,9 +475,9 @@ bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
470475
return false;
471476
}
472477

473-
if (coro_state.coroutines[hart_id]) {
474-
fprintf(stderr, "coro_create_hart: hart %u already has coroutine\n",
475-
hart_id);
478+
if (coro_state.coroutines[slot_id]) {
479+
fprintf(stderr, "coro_create_hart: slot %u already has coroutine\n",
480+
slot_id);
476481
return false;
477482
}
478483

@@ -484,8 +489,9 @@ bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
484489
}
485490

486491
/* Store user function and data */
492+
co->id = slot_id;
487493
co->func = func;
488-
co->user_data = hart;
494+
co->user_data = arg;
489495
co->state = CORO_STATE_SUSPENDED;
490496

491497
/* Allocate context */
@@ -529,34 +535,35 @@ bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
529535
}
530536
#endif
531537

532-
coro_state.coroutines[hart_id] = co;
538+
coro_state.coroutines[slot_id] = co;
533539
return true;
534540
}
535541

536-
void coro_resume_hart(uint32_t hart_id)
542+
void coro_resume_hart(uint32_t slot_id)
537543
{
538-
if (!coro_state.initialized || hart_id >= coro_state.n_hart) {
539-
fprintf(stderr, "coro_resume_hart: invalid hart_id=%u\n", hart_id);
544+
if (!coro_state.initialized || slot_id >= coro_state.total_slots) {
545+
fprintf(stderr, "coro_resume_hart: invalid slot_id=%u\n", slot_id);
540546
return;
541547
}
542548

543-
coro_t *co = coro_state.coroutines[hart_id];
549+
coro_t *co = coro_state.coroutines[slot_id];
544550
if (!co || !co->context) {
545-
fprintf(stderr, "coro_resume_hart: hart %u has no coroutine\n",
546-
hart_id);
551+
fprintf(stderr, "coro_resume_hart: slot %u has no coroutine\n",
552+
slot_id);
547553
return;
548554
}
549555

550556
if (co->state != CORO_STATE_SUSPENDED) {
551-
fprintf(stderr, "coro_resume_hart: hart %u not suspended (state=%d)\n",
552-
hart_id, co->state);
557+
/* This may happen if a coroutine is waiting on I/O and the main loop
558+
* tries to resume it. It is not a fatal error.
559+
*/
553560
return;
554561
}
555562

556563
/* Check for stack overflow before resuming */
557564
coro_check_stack(co);
558565

559-
coro_state.current_hart = hart_id;
566+
coro_state.current_hart = slot_id;
560567
co->state = CORO_STATE_RUNNING;
561568
jump_into(co);
562569

@@ -586,12 +593,12 @@ void coro_yield(void)
586593
jump_out(co);
587594
}
588595

589-
bool coro_is_suspended(uint32_t hart_id)
596+
bool coro_is_suspended(uint32_t slot_id)
590597
{
591-
if (!coro_state.initialized || hart_id >= coro_state.n_hart)
598+
if (!coro_state.initialized || slot_id >= coro_state.hart_slots)
592599
return false;
593600

594-
coro_t *co = coro_state.coroutines[hart_id];
601+
coro_t *co = coro_state.coroutines[slot_id];
595602
if (!co || !co->context)
596603
return false;
597604

coro.h

Lines changed: 20 additions & 25 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-
*/
38+
/* Get currently executing hart ID */
4439
uint32_t coro_current_hart_id(void);

0 commit comments

Comments
 (0)