Skip to content

Commit c61d0c7

Browse files
committed
refcount ckpt
1 parent 949ee1e commit c61d0c7

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed
Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
11
# Reference counting
22

3-
Many resources in the ukoOS
3+
Many resources in the ukoOS kernel have dynamic enough ownership that reference counting is useful to determine if they're still in use and when they should be freed.
4+
5+
We have a helper type, `refcount_t`, to help manage these.
6+
This is similar to the type with the same name in the Linux kernel, but we provide different helpers.
7+
8+
```c
9+
#include <refcount.h>
10+
11+
/**
12+
* This type is some random example resource. It's always
13+
*/
14+
struct foo {
15+
/**
16+
* This field stores the actual reference count. This is an integral type
17+
* that is no wider than usize.
18+
*/
19+
refcount_t refcount;
20+
21+
/**
22+
* A list the value is in.
23+
*/
24+
struct list_head all_foos;
25+
26+
/**
27+
* Another list the value might be in (or the list might be self-linked).
28+
*/
29+
struct list_head bars;
30+
};
31+
32+
struct list_head all_foos;
33+
34+
void add_foos_not_in_a_bars_to_list(struct list_head *bars) {
35+
for (struct list_head *iter = all_foos.next; iter != all_foos;
36+
iter = iter->next) {
37+
struct foo *foo = container_of(iter, struct foo, all_foos);
38+
if (list_is_empty(foo->bars))
39+
continue;
40+
list_push(bars, &foo->bars);
41+
}
42+
}
43+
```

src/kernel/include/refcount.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 ukoOS Contributors
3+
*
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
#ifndef UKO_OS_KERNEL__REFCOUNT_H
8+
#define UKO_OS_KERNEL__REFCOUNT_H 1
9+
10+
#include <container.h>
11+
#include <panic.h>
12+
#include <stdatomic.h>
13+
14+
/**
15+
* A reference count. This essentially just an `atomic usize` that saturates at
16+
* `USIZE_MAX` (and stays there) instead of overflowing.
17+
*/
18+
typedef struct {
19+
atomic usize _count;
20+
} refcount_t;
21+
22+
static inline void refcount_init(refcount_t *refcount) { refcount->_count = 1; }
23+
24+
static inline void refcount_incref(refcount_t *refcount) {
25+
// TODO: refactor to not need a loop
26+
for (;;) {
27+
usize count = atomic_load(&refcount->_count);
28+
assert(count);
29+
30+
// If the counter saturated, don't overflow.
31+
if (unlikely(count == USIZE_MAX))
32+
return;
33+
34+
if (likely(
35+
atomic_compare_exchange_weak(&refcount->_count, &count, count + 1)))
36+
return;
37+
}
38+
}
39+
40+
static inline void refcount_decref(refcount_t *refcount,
41+
void *(*free)(void *ctx), void *ctx) {
42+
// TODO: refactor to not need a loop
43+
usize count;
44+
do {
45+
count = atomic_load(&refcount->_count);
46+
assert(count);
47+
48+
// If the counter saturated, don't decref.
49+
if (unlikely(count == USIZE_MAX))
50+
return;
51+
} while (unlikely(
52+
!atomic_compare_exchange_weak(&refcount->_count, &count, count - 1)));
53+
54+
// The refcount is now zero.
55+
if (count == 1)
56+
free(ctx);
57+
}
58+
59+
#endif // UKO_OS_KERNEL__REFCOUNT_H

0 commit comments

Comments
 (0)