1 /* Copyright (C) 1993, 1994, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: gsrefct.h,v 1.5 2002/06/16 08:45:42 lpd Exp $ */ 18 /* Reference counting definitions */ 19 20 #ifndef gsrefct_INCLUDED 21 # define gsrefct_INCLUDED 22 23 /* 24 * A reference-counted object must include the following header: 25 * rc_header rc; 26 * The header need not be the first element of the object. 27 * 28 * Reference-counted objects have a freeing procedure that gets called when 29 * the reference count reaches zero. In retrospect, we probably should have 30 * used finalization for this, but it's too difficult to change now. 31 * Because of the interaction between these two features, the freeing 32 * procedure for reference-counted objects that do use finalization must 33 * free the object itself first, before decrementing the reference counts 34 * of referenced objects (which of course requires saving pointers to those 35 * objects before freeing the containing object). 36 */ 37 typedef struct rc_header_s rc_header; 38 struct rc_header_s { 39 long ref_count; 40 gs_memory_t *memory; 41 #define rc_free_proc(proc)\ 42 void proc(gs_memory_t *, void *, client_name_t) 43 rc_free_proc((*free)); 44 }; 45 46 #ifdef DEBUG 47 void rc_trace_init_free(const void *vp, const rc_header *prc); 48 void rc_trace_free_struct(const void *vp, const rc_header *prc, 49 client_name_t cname); 50 void rc_trace_increment(const void *vp, const rc_header *prc); 51 void rc_trace_adjust(const void *vp, const rc_header *prc, int delta); 52 #define IF_RC_DEBUG(call) if (gs_debug_c('^')) dlputs(""), call 53 #else 54 #define IF_RC_DEBUG(call) DO_NOTHING 55 #endif 56 57 /* ------ Allocate/free ------ */ 58 59 rc_free_proc(rc_free_struct_only); 60 /* rc_init[_free] is only used to initialize stack-allocated structures. */ 61 #define rc_init_free(vp, mem, rcinit, proc)\ 62 BEGIN\ 63 (vp)->rc.ref_count = rcinit;\ 64 (vp)->rc.memory = mem;\ 65 (vp)->rc.free = proc;\ 66 IF_RC_DEBUG(rc_trace_init_free(vp, &(vp)->rc));\ 67 END 68 #define rc_init(vp, mem, rcinit)\ 69 rc_init_free(vp, mem, rcinit, rc_free_struct_only) 70 71 #define rc_alloc_struct_n(vp, typ, pstyp, mem, errstat, cname, rcinit)\ 72 BEGIN\ 73 if ( ((vp) = gs_alloc_struct(mem, typ, pstyp, cname)) == 0 ) {\ 74 errstat;\ 75 } else {\ 76 rc_init(vp, mem, rcinit);\ 77 }\ 78 END 79 #define rc_alloc_struct_0(vp, typ, pstype, mem, errstat, cname)\ 80 rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 0) 81 #define rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname)\ 82 rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 1) 83 84 #define rc_free_struct(vp, cname)\ 85 BEGIN\ 86 IF_RC_DEBUG(rc_trace_free_struct(vp, &(vp)->rc, cname));\ 87 (vp)->rc.free((vp)->rc.memory, (void *)(vp), cname);\ 88 END 89 90 /* ------ Reference counting ------ */ 91 92 /* Increment a reference count. */ 93 #define RC_DO_INCREMENT(vp)\ 94 BEGIN\ 95 (vp)->rc.ref_count++;\ 96 IF_RC_DEBUG(rc_trace_increment(vp, &(vp)->rc));\ 97 END 98 #define rc_increment(vp)\ 99 BEGIN\ 100 if (vp) RC_DO_INCREMENT(vp);\ 101 END 102 103 /* Increment a reference count, allocating the structure if necessary. */ 104 #define rc_allocate_struct(vp, typ, pstype, mem, errstat, cname)\ 105 BEGIN\ 106 if (vp)\ 107 RC_DO_INCREMENT(vp);\ 108 else\ 109 rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname);\ 110 END 111 112 /* Guarantee that a structure is allocated and is not shared. */ 113 #define RC_DO_ADJUST(vp, delta)\ 114 BEGIN\ 115 IF_RC_DEBUG(rc_trace_adjust(vp, &(vp)->rc, delta));\ 116 (vp)->rc.ref_count += (delta);\ 117 END 118 #define rc_unshare_struct(vp, typ, pstype, mem, errstat, cname)\ 119 BEGIN\ 120 if ( (vp) == 0 || (vp)->rc.ref_count > 1 || (vp)->rc.memory != (mem) ) {\ 121 typ *new;\ 122 rc_alloc_struct_1(new, typ, pstype, mem, errstat, cname);\ 123 if ( vp ) RC_DO_ADJUST(vp, -1);\ 124 (vp) = new;\ 125 }\ 126 END 127 128 /* Adjust a reference count either up or down. */ 129 #ifdef DEBUG 130 # define rc_check_(vp)\ 131 BEGIN\ 132 if (gs_debug_c('?') && (vp)->rc.ref_count < 0)\ 133 lprintf2("0x%lx has ref_count of %ld!\n", (ulong)(vp),\ 134 (vp)->rc.ref_count);\ 135 END 136 #else 137 # define rc_check_(vp) DO_NOTHING 138 #endif 139 #define rc_adjust_(vp, delta, cname, body)\ 140 BEGIN\ 141 if (vp) {\ 142 RC_DO_ADJUST(vp, delta);\ 143 if (!(vp)->rc.ref_count) {\ 144 rc_free_struct(vp, cname);\ 145 body;\ 146 } else\ 147 rc_check_(vp);\ 148 }\ 149 END 150 #define rc_adjust(vp, delta, cname)\ 151 rc_adjust_(vp, delta, cname, (vp) = 0) 152 #define rc_adjust_only(vp, delta, cname)\ 153 rc_adjust_(vp, delta, cname, DO_NOTHING) 154 #define rc_adjust_const(vp, delta, cname)\ 155 rc_adjust_only(vp, delta, cname) 156 #define rc_decrement(vp, cname)\ 157 rc_adjust(vp, -1, cname) 158 #define rc_decrement_only(vp, cname)\ 159 rc_adjust_only(vp, -1, cname) 160 161 /* 162 * Assign a pointer, adjusting reference counts. vpfrom might be a local 163 * variable with a copy of the last reference to the object, and freeing 164 * vpto might decrement the object's reference count and cause it to be 165 * freed (incorrectly); for that reason, we do the increment first. 166 */ 167 #define rc_assign(vpto, vpfrom, cname)\ 168 BEGIN\ 169 if ((vpto) != (vpfrom)) {\ 170 rc_increment(vpfrom);\ 171 rc_decrement_only(vpto, cname);\ 172 (vpto) = (vpfrom);\ 173 }\ 174 END 175 /* 176 * Adjust reference counts for assigning a pointer, 177 * but don't do the assignment. We use this before assigning 178 * an entire structure containing reference-counted pointers. 179 */ 180 #define rc_pre_assign(vpto, vpfrom, cname)\ 181 BEGIN\ 182 if ((vpto) != (vpfrom)) {\ 183 rc_increment(vpfrom);\ 184 rc_decrement_only(vpto, cname);\ 185 }\ 186 END 187 188 #endif /* gsrefct_INCLUDED */ 189