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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 516e780 was 498ced1, checked in by Jiří Zárevúcky <jiri.zarevucky@…>, 7 years ago

Unify reference counting and remove some unnecessary instances of <atomic.h>

  • Property mode set to 100644
File size: 3.8 KB
Line 
1/*
2 * Copyright (c) 2018 CZ.NIC, z.s.p.o.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Authors:
31 * Jiří Zárevúcky (jzr) <zarevucky.jiri@gmail.com>
32 */
33
34/*
35 * Using atomics for reference counting efficiently is a little tricky,
36 * so we define a unified API for this.
37 */
38
39#ifndef LIBC_REFCOUNT_H_
40#define LIBC_REFCOUNT_H_
41
42// TODO: #include <stdatomic.h>
43
44#include <assert.h>
45#include <atomic.h>
46#include <stdbool.h>
47
48/* Wrapped in a structure to prevent direct manipulation. */
49typedef struct atomic_refcount {
50 //volatile atomic_int __cnt;
51 atomic_t __cnt;
52} atomic_refcount_t;
53
54static inline void refcount_init(atomic_refcount_t *rc)
55{
56 //atomic_store_explicit(&rc->__cnt, 0, memory_order_relaxed);
57 atomic_set(&rc->__cnt, 0);
58}
59
60/**
61 * Increment a reference count.
62 *
63 * Calling this without already owning a reference is undefined behavior.
64 * E.g. acquiring a reference through a shared mutable pointer requires that
65 * the caller first locks the pointer itself (thereby acquiring the reference
66 * inherent to the shared variable), and only then may call refcount_up().
67 */
68static inline void refcount_up(atomic_refcount_t *rc)
69{
70 // XXX: We can use relaxed operation because acquiring a reference
71 // implies no ordering relationships. A reference-counted object
72 // still needs to be synchronized independently of the refcount.
73
74 //int old = atomic_fetch_add_explicit(&rc->__cnt, 1,
75 // memory_order_relaxed);
76
77 atomic_signed_t old = atomic_postinc(&rc->__cnt);
78
79 /* old < 0 indicates that the function is used incorrectly. */
80 assert(old >= 0);
81}
82
83/**
84 * Decrement a reference count. Caller must own the reference.
85 *
86 * If the function returns `false`, the caller no longer owns the reference and
87 * must not access the reference counted object.
88 *
89 * If the function returns `true`, the caller is now the sole owner of the
90 * reference counted object, and must deallocate it.
91 */
92static inline bool refcount_down(atomic_refcount_t *rc)
93{
94 // XXX: The decrementers don't need to synchronize with each other,
95 // but they do need to synchronize with the one doing deallocation.
96 //int old = atomic_fetch_sub_explicit(&rc->__cnt, 1,
97 // memory_order_release);
98
99 atomic_signed_t old = atomic_postdec(&rc->__cnt);
100
101 assert(old >= 0);
102
103 if (old == 0) {
104 // XXX: We are holding the last reference, so we must now
105 // synchronize with all the other decrementers.
106 //int val = atomic_load_explicit(&rc->__cnt,
107 // memory_order_acquire);
108 //assert(val == -1);
109 return true;
110 }
111
112 return false;
113}
114
115#endif
116
Note: See TracBrowser for help on using the repository browser.