1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
/* reference counting macros
*
* Copyright (C) 2019 Andrew Cagney
*
* This program 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 of the License, or (at your
* option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>.
*
* This program 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.
*
*/
#ifndef REFCNT_H
#define REFCNT_H
#include <stdbool.h>
#include "lswlog.h" /* for pexpect(), for dbg() */
#include "lswcdefs.h" /* for MUST_USE_RESULT */
#include "where.h"
typedef struct {
unsigned count;
} refcnt_t;
/*
* Initialize the refcnt.
*
* Note that ref_init(O,HERE) breaks as HERE contains braces.
*/
void refcnt_init(const char *what, const void *pointer,
refcnt_t *refcnt, where_t where);
#define refcnt_alloc(THING, WHERE) \
({ \
THING *t_ = alloc_bytes(sizeof(THING), (WHERE).func); \
refcnt_init(#THING, t_, &t_->refcnt, WHERE); \
t_; \
})
/*
* Add a reference.
*
* Note that ref_add(O,HERE) breaks as HERE contains braces.
*/
void refcnt_add(const char *what, const void *pointer,
refcnt_t *refcnt, where_t where);
#define refcnt_addref(O, WHERE) \
({ \
if ((O) == NULL) { \
dbg("addref "#O"@NULL "PRI_WHERE"", pri_where(WHERE)); \
} else { \
refcnt_add(#O, O, &(O)->refcnt, WHERE); \
} \
(O); /* result */ \
})
#define add_ref(O) \
({ \
where_t here_ = HERE; \
refcnt_addref(O, here_); \
})
/*
* Delete a reference.
*
* Note that ref_delete(O,FREE,HERE) breaks as HERE contains braces.
*/
bool refcnt_delete(const char *what, const void *pointer,
refcnt_t *refcnt, where_t where) MUST_USE_RESULT;
#define refcnt_delref(O, FREE, WHERE) \
{ \
if (*(O) == NULL) { \
dbg("delref "#O"@NULL "PRI_WHERE"", pri_where(WHERE)); \
} else if (refcnt_delete(#O, *(O), &(*(O))->refcnt, \
WHERE)) { \
FREE(O, WHERE); \
passert(*(O) == NULL); \
} else { \
*(O) = NULL; /* kill pointer */ \
} \
}
#define delete_ref(O, FREE) \
{ \
where_t here_ = HERE; \
refcnt_delref(O, FREE, here_); \
}
/*
* Replace an existing reference.
*
* Note that ref_replace(O,NEW,FREE,HERE) breaks as HERE contains
* braces.
*/
#define refcnt_replace(O, NEW, FREE, WHERE) \
{ \
/* add new before deleting old */ \
ref_add(NEW, WHERE); \
ref_delete(O, FREE, WHERE); \
*(O) = NEW; \
}
#define replace_ref(O, NEW, FREE) \
{ \
where_t here_ = HERE; \
/* add new before deleting old */ \
refcnt_replace(O, NEW, FREE, here_); \
}
/* for code wanting to use refcnt for normal allocs */
void dbg_alloc(const char *what, const void *pointer, where_t where);
void dbg_free(const char *what, const void *pointer, where_t where);
#endif
|