Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
notify.c
Go to the documentation of this file.
1#include "hal/acpi/hpet.h"
2#include "hal/cpu/irq_lock.h"
3#include "hal/timer/timer.h"
4#include "hash.h"
5#include "libk/serial.h"
6#include <notify.h>
7#include <spinlock.h>
8#include <str.h>
9
10static struct notify_dev_table notify_table = {0};
11
12static struct notify_dev* find_dev(const char* name) {
14 size_t name_len = strlen(name);
15
17 auto dev = notify_table.buckets[h & NOTIFY_DEV_HASH_MASK];
18 while (dev) {
19 if (strlen(dev->name->c_str) == name_len &&
20 strncmp(dev->name->c_str, name, name_len) == 0) {
21 __atomic_fetch_add(&dev->refcount.counter, 1,
22 __ATOMIC_RELAXED);
23 break;
24 }
25 dev = dev->next;
26 }
28
29 return dev;
30}
31
32static void notify_dev_put(struct notify_dev* dev) {
33 if (!dev)
34 return;
35 if (__atomic_sub_fetch(&dev->refcount.counter, 1, __ATOMIC_RELEASE) ==
36 0) {
37 kfree2(dev);
38 }
39}
40
42 auto h = hash(name->c_str, NOTIFY_DEV_HASH_SIZE);
43
44 auto n = (struct notify_dev*)kalloc(sizeof(struct notify_dev));
45 if (!n)
46 return;
47
48 memset(n, 0, sizeof(struct notify_dev));
49 n->hash = h;
50 n->name = name;
51 n->chain.lock = (spinlock_t)SPINLOCK_INIT;
52 __atomic_store_n(&n->refcount.counter, 1, __ATOMIC_RELAXED);
53
56
57 auto existing = notify_table.buckets[h & NOTIFY_DEV_HASH_MASK];
58 size_t name_len = strlen(name->c_str);
59 while (existing) {
60 if (strlen(existing->name->c_str) == name_len &&
61 strncmp(existing->name->c_str, name->c_str, name_len) ==
62 0) {
65 kfree2(n);
66 return;
67 }
68 existing = existing->next;
69 }
70
71 n->next = notify_table.buckets[h & NOTIFY_DEV_HASH_MASK];
72 notify_table.buckets[h & NOTIFY_DEV_HASH_MASK] = n;
73
76}
77
78int notify_register(char* name, struct notifier* n) {
79 auto current_dev = find_dev(name);
80 if (!current_dev)
81 return 0;
82
83 auto new_notifier = (struct notifier*)kalloc(sizeof(struct notifier));
84 if (!new_notifier)
85 return 0;
86
87 new_notifier->callback = n->callback;
88 new_notifier->context = n->context;
89 new_notifier->priority = n->priority;
90 new_notifier->flags = n->flags;
91
92 spin_acquire(&current_dev->chain.lock);
93
94 auto curr_chain = &current_dev->chain.head;
95 while (*curr_chain && (*curr_chain)->priority >= new_notifier->priority)
96 curr_chain = &(*curr_chain)->next;
97
98 serial2_printf("notift kntl\n");
99
100 new_notifier->next = *curr_chain;
101 *curr_chain = new_notifier;
102 __atomic_fetch_add(&current_dev->chain.size, 1, __ATOMIC_RELAXED);
103
104 spin_release(&current_dev->chain.lock);
105
106 notify_dev_put(current_dev);
107 return 1;
108}
109
110int notify_call(char* name, uint32_t event, void* data) {
111 auto current_dev = find_dev(name);
112 if (!current_dev)
113 return 0;
114
115#define MAX_SNAPSHOT 64
116 struct notifier* snapshot[MAX_SNAPSHOT];
117 int count = 0;
118
119 spin_acquire(&current_dev->chain.lock);
120 auto current = current_dev->chain.head;
121 while (current && count < MAX_SNAPSHOT) {
122 snapshot[count++] = current;
123 current = current->next;
124 }
125
126 spin_release(&current_dev->chain.lock);
127
128 for (int i = 0; i < count; i++) {
129 if (snapshot[i]->callback)
130 snapshot[i]->callback(event, data,
131 snapshot[i]->context);
132 }
133 __atomic_fetch_add(&current_dev->event_received, 1, __ATOMIC_RELEASE);
134
135 notify_dev_put(current_dev);
136 return 1;
137}
138
139/* timeout in ms */
140int wait_until_receive_notify(const char *name, uint64_t timeout) {
141 struct notify_dev *current_dev = find_dev(name);
142 if (!current_dev)
143 return 0;
144
145 uint64_t initial =
146 __atomic_load_n(&current_dev->event_received, __ATOMIC_ACQUIRE);
147
148 uint64_t timeout_count = 0;
149 while (timeout_count < timeout) {
150 uint64_t current_gen = __atomic_load_n(
151 &current_dev->event_received, __ATOMIC_ACQUIRE);
152 if (current_gen != initial) {
153 notify_dev_put(current_dev);
154 return 1;
155 }
156
157 usleep(ms2ns(1));
158 timeout_count += 1;
159 }
160
161 notify_dev_put(current_dev);
162 return 0;
163}
struct SDT h
Definition acpi.h:0
int count
Definition cache.h:2
kstring name
Definition dentry.h:5
uint32_t hash
Definition dentry.h:3
struct fs_data data
Definition filesystem.h:1
#define ms2ns(ms)
Definition hpet.h:12
uint16_t flags
Definition thread.h:5
void serial2_printf(const char *fmt,...)
static void irq_restore(uintptr_t flags)
Definition irq_lock.h:20
static uintptr_t irq_save(void)
Definition irq_lock.h:6
uint8_t name_len
Definition iso9660.h:19
void * kalloc(size_t size)
void kfree2(void *ptr)
void notify_dev_create(kstring name)
Definition notify.c:41
int notify_call(char *name, uint32_t event, void *data)
Definition notify.c:110
int notify_register(char *name, struct notifier *n)
Definition notify.c:78
static struct notify_dev_table notify_table
Definition notify.c:10
#define MAX_SNAPSHOT
static void notify_dev_put(struct notify_dev *dev)
Definition notify.c:32
int wait_until_receive_notify(const char *name, uint64_t timeout)
Definition notify.c:140
static struct notify_dev * find_dev(const char *name)
Definition notify.c:12
#define NOTIFY_DEV_HASH_MASK
Definition notify.h:44
#define NOTIFY_DEV_HASH_SIZE
Definition notify.h:43
#define SPINLOCK_INIT
Definition spinlock.h:15
void spin_acquire(spinlock_t *lock)
Definition spinlock.c:8
void spin_release(spinlock_t *lock)
Definition spinlock.c:19
int strncmp(const char *s1, const char *s2, size_t n)
size_t strlen(const char *s)
Definition str.c:105
void memset(void *ptr, int value, size_t num)
int counter
Definition type.h:80
uint32_t flags
Definition notify.h:33
notify_callback_t callback
Definition notify.h:30
struct notifier * next
Definition notify.h:34
uint32_t priority
Definition notify.h:32
void * context
Definition notify.h:31
atomic_t refcount
Definition notify.h:55
volatile uint64_t event_received
Definition notify.h:58
void usleep(const uint64_t time_ns)
Definition timer.c:31
unsigned int uint32_t
Definition type.h:19
unsigned long uintptr_t
Definition type.h:73
unsigned long uint64_t
Definition type.h:25