1#include <mem/alloc.h>
2#include <string.h>
3#include <structures/locked_list.h>
4#include <time/clock.h>
5#include <time/names.h>
6
7#include "internal.h"
8
9struct clock_globals clock_global = {0};
10
11void clocks_init(void) {
12 locked_list_init(ll: &clock_global.clock_evdevs, LOCKED_LIST_INIT_NORMAL);
13 locked_list_init(ll: &clock_global.clock_evdev_groups, LOCKED_LIST_INIT_NORMAL);
14 locked_list_init(ll: &clock_global.clocks, LOCKED_LIST_INIT_NORMAL);
15}
16
17struct clock *clock_create(const char *fmt, ...) {
18 struct clock *clock = kmalloc(sizeof(struct clock), ALLOC_FLAGS_ZERO);
19 if (!clock)
20 return NULL;
21
22 va_list args;
23 va_start(args, fmt);
24 int ret = ERR_GUARD(vasprintf(&clock->name, fmt, args), ERR_NO_MEM);
25 va_end(args);
26
27 if (ret == ERR_NO_MEM) {
28 kfree(clock);
29 return NULL;
30 }
31
32 return clock;
33}
34
35void clock_register(struct clock *c) {
36 locked_list_add(ll: &clock_global.clocks, lh: &c->list_internal);
37}
38
39void clock_unregister(struct clock *c) {
40 locked_list_del(ll: &clock_global.clocks, lh: &c->list_internal);
41}
42
43/* TODO: If/When we start we start getting actual callers that use dynamic
44 * lock registration, we'll need to refcount the clocks */
45struct clock *clock_get_best(void) {
46 struct clock *best = NULL;
47 enum clock_rating best_rating = CLOCK_RATING_UNSUITABLE;
48
49 struct list_head *pos;
50 enum irql irql = spin_lock(&clock_global.clocks.lock);
51 list_for_each(pos, &clock_global.clocks.list) {
52 struct clock *c = container_of(pos, struct clock, list_internal);
53 if (c->state == CLOCK_STATE_ON && !(c->flags & CLOCK_FLAG_UNSTABLE)) {
54 if (c->rating > best_rating) {
55 best_rating = c->rating;
56 best = c;
57 }
58 }
59 }
60 spin_unlock(&clock_global.clocks.lock, irql);
61
62 return best;
63}
64
65struct clock *clock_get_by_name(const char *name) {
66 struct clock *found = NULL;
67 struct list_head *pos;
68 enum irql irql = spin_lock(&clock_global.clocks.lock);
69 list_for_each(pos, &clock_global.clocks.list) {
70 struct clock *c = container_of(pos, struct clock, list_internal);
71 if (strcmp(str1: c->name, str2: name) == 0) {
72 found = c;
73 break;
74 }
75 }
76 spin_unlock(&clock_global.clocks.lock, irql);
77 return found;
78}
79