-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlibmicrokitco.h
136 lines (96 loc) · 4.14 KB
/
libmicrokitco.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* Copyright 2024, UNSW
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <libmicrokitco_opts.h>
// Cothread handle.
typedef int microkit_cothread_ref_t;
#include "libhostedqueue/libhostedqueue.h"
// This err is caught by the provided Makefile so we should never trigger this. But it's included
// in case the client want to compile the library manually.
#ifndef LIBMICROKITCO_MAX_COTHREADS
#error "libmicrokitco: max_cothreads must be known at compile time."
#endif
// No point to use this library if you only have the root PD thread.
#if LIBMICROKITCO_MAX_COTHREADS < 2
#error "libmicrokitco: max_cothreads must be greater or equal to 2."
#endif
// ========== BEGIN DATA TYPES SECTION ==========
#define LIBMICROKITCO_NULL_HANDLE -1
// The form of client entrypoint function.
typedef void (*client_entry_t)(void);
typedef enum {
// This id is not being used
cothread_not_active = 0,
cothread_blocked,
cothread_ready,
cothread_running,
} co_state_t;
typedef void *cothread_t;
typedef struct {
// Thread local storage: context + stack
void *local_storage;
cothread_t co_handle;
// Entrypoint for cothread
client_entry_t client_entry;
void *private_arg;
// Current execution state
co_state_t state;
microkit_cothread_ref_t next_blocked_on_same_event;
} co_tcb_t;
// A linked list data structure that manage all cothreads blocking on a specific sem/event.
typedef struct {
// True if the sem is signaled without any cothread waiting on it.
bool set;
// First cothread waiting on this semaphore
microkit_cothread_ref_t head;
microkit_cothread_ref_t tail;
} microkit_cothread_sem_t;
typedef struct cothreads_control {
int co_stack_size;
microkit_cothread_ref_t running;
// Array of cothreads, first index is root thread AND len(tcbs) == (max_cothreads + 1)
co_tcb_t tcbs[LIBMICROKITCO_MAX_COTHREADS];
// All of these are queues of `microkit_cothread_ref_t`
hosted_queue_t free_handle_queue;
hosted_queue_t scheduling_queue;
// Arrays for queues.
microkit_cothread_ref_t free_handle_queue_mem[LIBMICROKITCO_MAX_COTHREADS];
microkit_cothread_ref_t scheduling_queue_mem[LIBMICROKITCO_MAX_COTHREADS];
// Map of linked list on what cothreads are blocked on which channel.
microkit_cothread_sem_t blocked_channel_map[MICROKIT_MAX_CHANNELS];
} co_control_t;
#define LIBMICROKITCO_CONTROLLER_SIZE sizeof(co_control_t)
// ========== END DATA TYPES SECTION ==========
// ========== BEGIN API SECTION ==========
// You need to provide (LIBMICROKITCO_MAX_COTHREADS - 1) stack pointers for the coroutines.
// -1 because the root thread already have a stack
typedef uintptr_t stack_ptrs_arg_array_t[LIBMICROKITCO_MAX_COTHREADS - 1];
void microkit_cothread_init(
co_control_t *controller_memory_addr,
const size_t co_stack_size,
const stack_ptrs_arg_array_t co_stacks
);
bool microkit_cothread_free_handle_available(microkit_cothread_ref_t *ret_handle);
microkit_cothread_ref_t microkit_cothread_spawn(const client_entry_t client_entry, void *private_arg);
void microkit_cothread_set_arg(const microkit_cothread_ref_t cothread, void *private_arg);
co_state_t microkit_cothread_query_state(const microkit_cothread_ref_t cothread);
microkit_cothread_ref_t microkit_cothread_my_handle(void);
void *microkit_cothread_my_arg(void);
void microkit_cothread_yield(void);
void microkit_cothread_destroy(const microkit_cothread_ref_t cothread);
// Generic blocking mechanism: a userland semaphore
void microkit_cothread_semaphore_init(microkit_cothread_sem_t *ret_sem);
void microkit_cothread_semaphore_wait(microkit_cothread_sem_t *sem);
void microkit_cothread_semaphore_signal(microkit_cothread_sem_t *sem);
bool microkit_cothread_semaphore_is_queue_empty(const microkit_cothread_sem_t *sem);
bool microkit_cothread_semaphore_is_set(const microkit_cothread_sem_t *sem);
// Microkit specific semaphore wrapper: blocking on channel
void microkit_cothread_wait_on_channel(const microkit_channel wake_on);
void microkit_cothread_recv_ntfn(const microkit_channel ch);
// ========== END API SECTION ==========