XenevaOS
Loading...
Searching...
No Matches
kref.h
Go to the documentation of this file.
1#ifndef __LINUX_KREF_H__
2#define __LINUX_KREF_H__
3
4/*
5 * DCL <linux/kref.h> -- reference counting for tty_struct and tty_driver,
6 * and now for every drm object that embeds one.
7 *
8 * Both tty types are handed around as bare pointers by tty_io.c (a cdev open
9 * finds a driver, a driver finds a port, a port finds a tty) and freed from
10 * whichever path happens to run last. kref is the contract that says "last
11 * one out turns the lights off".
12 *
13 * Xeneva has no real concurrency in these paths -- <linux/mutex.h> records
14 * that plainly -- so the counter is atomic for mainline's reasons (the
15 * arithmetic must be indivisible on SMP) rather than because anyone here can
16 * actually race it. Keeping the operations atomic anyway costs a ldxr/stxr on
17 * aarch64 and avoids a header whose semantics differ from mainline's the day
18 * the second core turns on.
19 *
20 * The field is a refcount_t rather than the atomic_t it used to be. That was
21 * mainline's own change (commit "kref: add refcount_t"), and this tree could
22 * not skip it: drm_connector.c:1070 does not go through a kref helper, it
23 * reaches inside the struct and writes
24 *
25 * if (!refcount_dec_and_test(&conn->base.refcount.refcount))
26 *
27 * so the field has to be the type refcount_dec_and_test() takes. An
28 * atomic_t there would be the same width and would happen to work, but only
29 * by coincidence of layout -- and -Wno-error=incompatible-pointer-types is
30 * set for this build, so the mistake would be a warning nobody reads rather
31 * than a compile failure. refcount_t also buys saturation, which atomic_t
32 * does not have: a kref that underflows wraps to a large positive value and
33 * looks like a healthy object that will never be freed.
34 *
35 * kref_get_unless_zero() is included because tty_port_get() (tty_port.h:164)
36 * is written around it: it must decline to take a reference on an object
37 * already at zero, or a hangup path resurrects a port being destroyed. It now
38 * resolves to refcount_inc_not_zero(), which is mainline's spelling and adds
39 * the saturation check the atomic version lacked.
40 */
41
42#include <linux/refcount.h>
43
47
48#define KREF_INIT(n) { REFCOUNT_INIT(n) }
49
50static inline void kref_init(struct kref* kref)
51{
52 refcount_set(&kref->refcount, 1);
53}
54
55static inline void kref_get(struct kref* kref)
56{
57 refcount_inc(&kref->refcount);
58}
59
60static inline int kref_get_unless_zero(struct kref* kref)
61{
62 return refcount_inc_not_zero(&kref->refcount);
63}
64
65static inline unsigned int kref_read(const struct kref* kref)
66{
67 return refcount_read(&kref->refcount);
68}
69
70/*
71 * kref_put_unless_zero() is deliberately absent. mainline implements it on
72 * refcount_dec_not_one(), a primitive whose whole job is refusing to take a
73 * count from 0 to -1. The only call site in this tree was in
74 * drm_gem_shmem_helper.c, which is not vendored (see Vendored/README.md);
75 * add both together, where the zero case can be tested against a real driver
76 * rather than against a stub.
77 */
78
79/*
80 * kref_put() -- mainline returns int (1 if this call released) because
81 * tty_release_struct() and friends branch on it. The release function takes
82 * the kref, so callers derive their container with container_of().
83 */
84static inline int kref_put(struct kref* kref, void (*release)(struct kref* kref))
85{
86 if (refcount_dec_and_test(&kref->refcount)) {
87 release(kref);
88 return 1;
89 }
90 return 0;
91}
92
93#endif /* __LINUX_KREF_H__ */
Definition kref.h:44
refcount_t refcount
Definition kref.h:45
Definition refcount_types.h:27