Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
workqueue.c
Go to the documentation of this file.
1#include "procc/workqueue.h"
2#include "hal/acpi/acpi.h"
3#include "hal/cpu/paging.h"
4#include "init/init.h"
5#include "libk/serial.h"
6#include "procc/thread.h"
7#include <hal/cpu/core.h>
8#include <spinlock.h>
9#include <type.h>
10#include <vector.h>
11
13
14#define SLOT_EMPTY 0x00
15#define SLOT_BUSY 0xFF
16
17static void workqueue_process() {
19 LOG2_INFO("workqueue", "worker thread running on core %d",
20 core->core_id);
21
22 while (true) {
23
24 if (!__atomic_load_n(&core->workqueue_count,
25 __ATOMIC_ACQUIRE)) {
26 __asm__ volatile("pause");
27 continue;
28 }
29
30 for (uint16_t i = 0; i < VOXIA_MAX_WORKQUEUE_EACH_CORE; i++) {
31 workqueue_t* workqueue = &core->workqueue[i];
32
33 if (!__atomic_load_n(&workqueue->in_use,
34 __ATOMIC_ACQUIRE))
35 continue;
36
37 if (workqueue->dependency) {
38 boolean_t dependency_done = true;
39 boolean_t dependency_invalid = false;
40
41 for (size_t j = 0;
42 j < workqueue->dependency->size; j++) {
43 workqueue_t* dep =
45
46 if (!dep) {
47 continue;
48 }
49
50 if (__atomic_load_n(&dep->in_use,
51 __ATOMIC_ACQUIRE)) {
52
53 dependency_done = false;
54 break;
55 }
56 }
57
58 (void)dependency_invalid;
59
60 if (!dependency_done)
61 continue;
62 }
63
64 if (workqueue->function) {
65 ((void (*)(void*))workqueue->function)(
67 } else {
68 LOG2_ERROR("workqueue",
69 "core %d slot %d: function pointer "
70 "null, skipping",
71 core->core_id, i);
72 }
73
74 __atomic_store_n(&workqueue->in_use, SLOT_EMPTY,
75 __ATOMIC_RELEASE);
76 __atomic_fetch_sub(&core->workqueue_count, 1,
77 __ATOMIC_RELEASE);
78 }
79 }
80
82}
83
84workqueue_t* vxAddWorkqueueTask(void (*task)(void*), void* arg,
86 static uint8_t next_core_hint = 1;
87
88 for (uint8_t attempt = 0; attempt < VOXIA_MAX_CORE; attempt++) {
89 uint8_t target_apic_id =
90 ((__atomic_fetch_add(&next_core_hint, 1,
91 __ATOMIC_RELAXED)) %
92 (VOXIA_MAX_CORE - 1)) +
93 1;
94
95 auto cpu_info = vxGetCpuInfo(target_apic_id);
96 if (!cpu_info || cpu_info->status != Active) {
97 continue;
98 }
99
100 each_core_data* core = vxGetCoreDataByCoreID(target_apic_id);
101
102 if (__atomic_load_n(&core->workqueue_count, __ATOMIC_ACQUIRE) >=
103 VOXIA_MAX_WORKQUEUE_EACH_CORE) {
104 continue;
105 }
106
108
109 // Re-check after lock
110 if (core->workqueue_count >= VOXIA_MAX_WORKQUEUE_EACH_CORE) {
112 continue;
113 }
114
115 for (uint16_t i = 0; i < VOXIA_MAX_WORKQUEUE_EACH_CORE; i++) {
116 uint8_t expected = SLOT_EMPTY;
117
118 if (__atomic_compare_exchange_n(
119 &core->workqueue[i].in_use, &expected,
120 SLOT_BUSY, false, __ATOMIC_ACQUIRE,
121 __ATOMIC_RELAXED)) {
122
123 core->workqueue[i].function = (void*)task;
124 core->workqueue[i].data = arg;
125 core->workqueue[i].dependency = dependency;
126
127 __atomic_fetch_add(&core->workqueue_count, 1,
128 __ATOMIC_RELEASE);
129
131 return &core->workqueue[i];
132 }
133 }
134
136 }
137
138 LOG_ERROR("workqueue", "no available slot in any active worker core");
139 return 0;
140}
141
142INIT(Workqueue) {
143 auto kernel_page = paging_get_highest_page_map();
144 for (uint8_t i = 1; i < vxGetNumberOfCores(); i++) {
145 auto cpu_info = vxGetCpuInfo(i);
146 if (cpu_info->status != Active) {
147 serial2_printf("cpu %d not active\n", cpu_info->cpuid);
148 continue;
149 }
150 serial2_printf("workqueue init on core %d\n", cpu_info->cpuid);
151
152 auto stack = (uintptr_t)kalloc(4096);
153 // auto stack_top = stack + 4096;
154 auto thr = create_thread(
155 kernel_page, (uintptr_t)workqueue_process, stack, i, 1, 0);
157 }
158}
struct cpu_core * vxGetCpuInfo(uint8_t apicid)
Definition acpi.c:21
uint8_t vxGetNumberOfCores()
Definition acpi.c:45
@ Active
Definition acpi.h:66
uint8_t lock
Definition cache.h:1
#define SLOT_EMPTY
Definition console.c:9
each_core_data * get_current_core_data(void)
Definition core.c:54
each_core_data * vxGetCoreDataByCoreID(uint8_t core_id)
Definition core.c:62
void vxThreadExit()
Definition thread.c:70
uint64_t stack
Definition thread.h:13
#define INIT(fn)
Definition init.h:26
void serial2_printf(const char *fmt,...)
void * kalloc(size_t size)
each_core_data
Definition core.h:32
page_t paging_get_highest_page_map(void)
Definition paging.c:463
void attach_to_scheduler(thread_t *new_thread)
Definition scheduler.c:268
#define LOG_ERROR(mod, fmt,...)
Definition serial.h:25
#define LOG2_ERROR(mod, fmt,...)
Definition serial.h:38
#define LOG2_INFO(mod, fmt,...)
Definition serial.h:33
void spin_acquire(spinlock_t *lock)
Definition spinlock.c:8
void spin_release(spinlock_t *lock)
Definition spinlock.c:19
workqueue_ptr_t * data
Definition workqueue.h:8
uint8_t in_use
Definition workqueue.h:13
void * data
Definition workqueue.h:12
struct vector_workqueue_ptr_t * dependency
Definition workqueue.h:14
void(* function)(void *)
Definition workqueue.h:11
thread_t * create_thread(volatile uintptr_t *page, uintptr_t entry, uintptr_t stack, uint16_t core_affinity, uint8_t priority, uint16_t flags)
Definition thread.c:41
unsigned short uint16_t
Definition type.h:13
uint8_t boolean_t
Definition type.h:89
unsigned long uintptr_t
Definition type.h:73
unsigned char uint8_t
Definition type.h:7
#define vector(T)
Definition vector.h:11
int core
Definition vm_manager.h:5
kstring * dependency
Definition voxmo.h:3
#define SLOT_BUSY
Definition workqueue.c:15
workqueue_t * vxAddWorkqueueTask(void(*task)(void *), void *arg, struct vector_workqueue_ptr_t *dependency)
Definition workqueue.c:84
static void workqueue_process()
Definition workqueue.c:17
struct workqueue * workqueue_ptr_t
Definition workqueue.h:7
struct workqueue workqueue_t