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
|
/*
* KPL environment objects
*/
#pragma once
typedef enum : int32_t {
KPL_THREAD_DETERIMINE_COUNT = -1,
KPL_THREAD_MAIN_ID = 0
} kpl_thread_enum;
typedef struct _kpl_thread {
int32_t thread_id; // self id
kpl_memory_allocator memory_allocator;
kpl_io_uring io_uring;
// TODO jit allocator
_Atomic ssize_t priority; // running + the total number of tasks in threads queue, lower is higher priority
kpl_object_queue task_queue;
pthread_t pthread; // not used for main thread
sem_t sem; // wait when no task queue and io queue is empty
} kpl_thread;
/*
* All allocations must extend the KPL_OBJECT_HEADER
* All objects are allocated through this
*/
inline void *kpl_thread_object_allocate(kpl_thread *thread, int32_t size) {
return kpl_memory_allocator_allocate(&thread->memory_allocator, size, thread->thread_id);
}
/*
* Life cycle:
* kpl_env env = {};
* kpl_env_config &env, argc, argv
* kpl_env_init &env
* add to the namespace tree
* add a file load task, string evaluate task or REPL task to main thread task queue
* kpl_env_run &env
* kpl_env_free &env
*/
typedef struct _kpl_env {
int32_t io_uring_queue_size_pow2; // the power of two to calculate the entries in the io_uring queue
int32_t thread_count; // -1 updates this value to max possible, 0 invalid, >= 1 for specific number
_Atomic ssize_t total_priority; // the sum of the threads priority fields, application stops on zero
kpl_thread *threads; // 0 is main thread, >= 1 are spawned pthreads
kpl_tree *namespace_tree, *module_tree; // *namespace_tree lookups are thread safe, *module_tree needs mutex
pthread_mutex_t module_tree_mutex;
} kpl_env; // kpl state, no globals, must be zero initialized
/*
* All objects are returned by this
*/
inline void kpl_env_object_return(kpl_env *env, void *object) {
kpl_memory_allocator_return(&env->threads[((kpl_object*) object)->thread_id].memory_allocator, object);
}
/*
* Must match the type of c main return
* if code != KPL_EXIT_CODE_SUCCESS then return code
*/
typedef enum : int32_t {
KPL_EXIT_CODE_SUCCESS = 0,
KPL_EXIT_CODE_ERROR = 1,
KPL_EXIT_CODE_HELP = 2
} kpl_exit_code;
/*
* Set up initial values before initialization
* For defaults and/or directly setting without arguments, pass 0 to argc then fields can be updated directly
*/
kpl_exit_code kpl_env_config(kpl_env *env, int32_t argc, char *argv[]);
/*
* Initialize
* env kpl_env_config must be called before this
*/
kpl_exit_code kpl_env_init(kpl_env *env);
/*
* Run once, not re-enetrant
* TODO RUN TASK AND IO ORDERING
*/
kpl_exit_code kpl_env_run(kpl_env *env);
/*
* Stops KPL, can be called on any task in KPL
* Does not return just signals to all threads to stop, the return status will be from kpl_env_run
*/
void kpl_env_stop(kpl_env *env);
/*
* Clean up
*/
void kpl_env_free(kpl_env *env);
|