source: mainline/uspace/lib/c/include/refcount.h@ b57ba05

Last change on this file since b57ba05 was d7f7a4a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Replace some license headers with SPDX identifier

Headers are replaced using tools/transorm-copyright.sh only
when it can be matched verbatim with the license header used
throughout most of the codebase.

  • Property mode set to 100644
File size: 2.4 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2018 CZ.NIC, z.s.p.o.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*
8 * Authors:
9 * Jiří Zárevúcky (jzr) <zarevucky.jiri@gmail.com>
10 */
11
12/*
13 * Using atomics for reference counting efficiently is a little tricky,
14 * so we define a unified API for this.
15 */
16
17#ifndef _LIBC_REFCOUNT_H_
18#define _LIBC_REFCOUNT_H_
19
20#include <assert.h>
21#include <stdatomic.h>
22#include <stdbool.h>
23
24/* Wrapped in a structure to prevent direct manipulation. */
25typedef struct atomic_refcount {
26 volatile atomic_int __cnt;
27} atomic_refcount_t;
28
29static inline void refcount_init(atomic_refcount_t *rc)
30{
31 atomic_store_explicit(&rc->__cnt, 0, memory_order_relaxed);
32}
33
34/**
35 * Increment a reference count.
36 *
37 * Calling this without already owning a reference is undefined behavior.
38 * E.g. acquiring a reference through a shared mutable pointer requires that
39 * the caller first locks the pointer itself (thereby acquiring the reference
40 * inherent to the shared variable), and only then may call refcount_up().
41 */
42static inline void refcount_up(atomic_refcount_t *rc)
43{
44 // XXX: We can use relaxed operation because acquiring a reference
45 // implies no ordering relationships. A reference-counted object
46 // still needs to be synchronized independently of the refcount.
47
48 int old = atomic_fetch_add_explicit(&rc->__cnt, 1,
49 memory_order_relaxed);
50
51 /* old < 0 indicates that the function is used incorrectly. */
52 assert(old >= 0);
53}
54
55/**
56 * Decrement a reference count. Caller must own the reference.
57 *
58 * If the function returns `false`, the caller no longer owns the reference and
59 * must not access the reference counted object.
60 *
61 * If the function returns `true`, the caller is now the sole owner of the
62 * reference counted object, and must deallocate it.
63 */
64static inline bool refcount_down(atomic_refcount_t *rc)
65{
66 // XXX: The decrementers don't need to synchronize with each other,
67 // but they do need to synchronize with the one doing deallocation.
68 int old = atomic_fetch_sub_explicit(&rc->__cnt, 1,
69 memory_order_release);
70
71 assert(old >= 0);
72
73 if (old == 0) {
74 // XXX: We are holding the last reference, so we must now
75 // synchronize with all the other decrementers.
76
77 int val = atomic_load_explicit(&rc->__cnt,
78 memory_order_acquire);
79 assert(val == -1);
80
81 /*
82 * The compiler probably wouldn't optimize the memory barrier
83 * away, but better safe than sorry.
84 */
85 return val < 0;
86 }
87
88 return false;
89}
90
91#endif
Note: See TracBrowser for help on using the repository browser.