From 8faea20349dc1d8cfd0117d28a3f1271083192d0 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Tue, 6 May 2014 19:52:04 +0200 Subject: [PATCH 2/5] include: add lock-less reference counting primitives * include/refcount.h: New file. --- include/refcount.h | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 include/refcount.h diff --git a/include/refcount.h b/include/refcount.h new file mode 100644 index 0000000..946938a --- /dev/null +++ b/include/refcount.h @@ -0,0 +1,155 @@ +/* Lock-less reference counting primitives + + Copyright (C) 2014 Free Software Foundation, Inc. + + Written by Justus Winter <4winter@informatik.uni-hamburg.de> + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see . */ + +#ifndef _HURD_REFCOUNT_H_ +#define _HURD_REFCOUNT_H_ + +#include + +/* Simple reference counting. */ + +/* An opaque type. You must not access these values directly. */ +typedef uint32_t refcount_t; + +/* Initialize REF with REFERENCES. */ +static inline void +refcount_init (refcount_t *ref, uint32_t references) +{ + *ref = references; +} + +/* Increment REF. Return the result of the operation. */ +static inline uint32_t +refcount_ref (refcount_t *ref) +{ + return __atomic_add_fetch (ref, 1, __ATOMIC_RELAXED); +} + +/* Decrement REF. Return the result of the operation. */ +static inline uint32_t +refcount_deref (refcount_t *ref) +{ + return __atomic_sub_fetch (ref, 1, __ATOMIC_RELAXED); +} + +/* Return REF. */ +static inline uint32_t +refcount_references (refcount_t *ref) +{ + return __atomic_load_n (ref, __ATOMIC_RELAXED); +} + +/* Reference counting with weak references. */ + +/* An opaque type. You must not access these values directly. */ +typedef uint64_t refcounts_t; + +/* Instead, the functions manipulating refcounts_t values write the + results into this kind of objects. */ +struct references { + uint32_t hard; + uint32_t weak; +}; + +union _references { + struct references refs; + refcounts_t rc; +}; + +/* Initialize REF with HARD and WEAK references. */ +static inline void +refcounts_init (refcounts_t *ref, uint32_t hard, uint32_t weak) +{ + ((union _references *) ref)->refs = + (struct references) { .hard = hard, .weak = weak }; +} + +/* Increment the hard reference count of REF. If RESULT is not NULL, + the result of the operation is written there. */ +static inline void +refcounts_ref (refcounts_t *ref, struct references *result) +{ + const union _references op = { .refs = { .hard = 1 } }; + refcounts_t r = __atomic_add_fetch (ref, op.rc, __ATOMIC_RELAXED); + if (result) + ((union _references *) result)->rc = r; +} + +/* Decrement the hard reference count of REF. If RESULT is not NULL, + the result of the operation is written there. */ +static inline void +refcounts_deref (refcounts_t *ref, struct references *result) +{ + const union _references op = { .refs = { .hard = 1 } }; + refcounts_t r = __atomic_sub_fetch (ref, op.rc, __ATOMIC_RELAXED); + if (result) + ((union _references *) result)->rc = r; +} + +/* Increment the weak reference count of REF. If RESULT is not NULL, + the result of the operation is written there. */ +static inline void +refcounts_ref_weak (refcounts_t *ref, struct references *result) +{ + const union _references op = { .refs = { .weak = 1 } }; + refcounts_t r = __atomic_add_fetch (ref, op.rc, __ATOMIC_RELAXED); + if (result) + ((union _references *) result)->rc = r; +} + +/* Decrement the weak reference count of REF. If RESULT is not NULL, + the result of the operation is written there. */ +static inline void +refcounts_deref_weak (refcounts_t *ref, struct references *result) +{ + const union _references op = { .refs = { .weak = 1 } }; + refcounts_t r = __atomic_sub_fetch (ref, op.rc, __ATOMIC_RELAXED); + if (result) + ((union _references *) result)->rc = r; +} + +/* Store the current reference counts of REF in RESULT. */ +static inline void +refcounts_references (refcounts_t *ref, struct references *result) +{ + ((union _references *) result)->rc = + __atomic_load_n (ref, __ATOMIC_RELAXED); +} + +/* Return the hard reference count of REF. */ +static inline uint32_t +refcounts_hard_references (refcounts_t *ref) +{ + struct references result; + refcounts_references (ref, &result); + return result.hard; +} + +/* Return the weak reference count of REF. */ +static inline uint32_t +refcounts_weak_references (refcounts_t *ref) +{ + struct references result; + refcounts_references (ref, &result); + return result.weak; +} + +#endif /* _HURD_REFCOUNT_H_ */ -- 2.0.0.rc0