|
| 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