17dd7cddfSDavid du Colombier /* Copyright (C) 1993, 1994, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. 27dd7cddfSDavid du Colombier 3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or 4*593dc095SDavid du Colombier implied. 57dd7cddfSDavid du Colombier 6*593dc095SDavid du Colombier This software is distributed under license and may not be copied, 7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms 8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution. 97dd7cddfSDavid du Colombier 10*593dc095SDavid du Colombier For more information about licensing, please refer to 11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on 12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or 13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861. 157dd7cddfSDavid du Colombier */ 167dd7cddfSDavid du Colombier 17*593dc095SDavid du Colombier /* $Id: gsrefct.h,v 1.5 2002/06/16 08:45:42 lpd Exp $ */ 187dd7cddfSDavid du Colombier /* Reference counting definitions */ 197dd7cddfSDavid du Colombier 207dd7cddfSDavid du Colombier #ifndef gsrefct_INCLUDED 217dd7cddfSDavid du Colombier # define gsrefct_INCLUDED 227dd7cddfSDavid du Colombier 237dd7cddfSDavid du Colombier /* 247dd7cddfSDavid du Colombier * A reference-counted object must include the following header: 257dd7cddfSDavid du Colombier * rc_header rc; 267dd7cddfSDavid du Colombier * The header need not be the first element of the object. 277dd7cddfSDavid du Colombier * 287dd7cddfSDavid du Colombier * Reference-counted objects have a freeing procedure that gets called when 297dd7cddfSDavid du Colombier * the reference count reaches zero. In retrospect, we probably should have 307dd7cddfSDavid du Colombier * used finalization for this, but it's too difficult to change now. 317dd7cddfSDavid du Colombier * Because of the interaction between these two features, the freeing 327dd7cddfSDavid du Colombier * procedure for reference-counted objects that do use finalization must 337dd7cddfSDavid du Colombier * free the object itself first, before decrementing the reference counts 347dd7cddfSDavid du Colombier * of referenced objects (which of course requires saving pointers to those 357dd7cddfSDavid du Colombier * objects before freeing the containing object). 367dd7cddfSDavid du Colombier */ 377dd7cddfSDavid du Colombier typedef struct rc_header_s rc_header; 387dd7cddfSDavid du Colombier struct rc_header_s { 397dd7cddfSDavid du Colombier long ref_count; 407dd7cddfSDavid du Colombier gs_memory_t *memory; 417dd7cddfSDavid du Colombier #define rc_free_proc(proc)\ 42*593dc095SDavid du Colombier void proc(gs_memory_t *, void *, client_name_t) 437dd7cddfSDavid du Colombier rc_free_proc((*free)); 447dd7cddfSDavid du Colombier }; 457dd7cddfSDavid du Colombier 467dd7cddfSDavid du Colombier #ifdef DEBUG 47*593dc095SDavid du Colombier void rc_trace_init_free(const void *vp, const rc_header *prc); 48*593dc095SDavid du Colombier void rc_trace_free_struct(const void *vp, const rc_header *prc, 49*593dc095SDavid du Colombier client_name_t cname); 50*593dc095SDavid du Colombier void rc_trace_increment(const void *vp, const rc_header *prc); 51*593dc095SDavid du Colombier void rc_trace_adjust(const void *vp, const rc_header *prc, int delta); 527dd7cddfSDavid du Colombier #define IF_RC_DEBUG(call) if (gs_debug_c('^')) dlputs(""), call 537dd7cddfSDavid du Colombier #else 547dd7cddfSDavid du Colombier #define IF_RC_DEBUG(call) DO_NOTHING 557dd7cddfSDavid du Colombier #endif 567dd7cddfSDavid du Colombier 577dd7cddfSDavid du Colombier /* ------ Allocate/free ------ */ 587dd7cddfSDavid du Colombier 597dd7cddfSDavid du Colombier rc_free_proc(rc_free_struct_only); 607dd7cddfSDavid du Colombier /* rc_init[_free] is only used to initialize stack-allocated structures. */ 617dd7cddfSDavid du Colombier #define rc_init_free(vp, mem, rcinit, proc)\ 627dd7cddfSDavid du Colombier BEGIN\ 637dd7cddfSDavid du Colombier (vp)->rc.ref_count = rcinit;\ 647dd7cddfSDavid du Colombier (vp)->rc.memory = mem;\ 657dd7cddfSDavid du Colombier (vp)->rc.free = proc;\ 667dd7cddfSDavid du Colombier IF_RC_DEBUG(rc_trace_init_free(vp, &(vp)->rc));\ 677dd7cddfSDavid du Colombier END 687dd7cddfSDavid du Colombier #define rc_init(vp, mem, rcinit)\ 697dd7cddfSDavid du Colombier rc_init_free(vp, mem, rcinit, rc_free_struct_only) 707dd7cddfSDavid du Colombier 717dd7cddfSDavid du Colombier #define rc_alloc_struct_n(vp, typ, pstyp, mem, errstat, cname, rcinit)\ 727dd7cddfSDavid du Colombier BEGIN\ 737dd7cddfSDavid du Colombier if ( ((vp) = gs_alloc_struct(mem, typ, pstyp, cname)) == 0 ) {\ 747dd7cddfSDavid du Colombier errstat;\ 757dd7cddfSDavid du Colombier } else {\ 767dd7cddfSDavid du Colombier rc_init(vp, mem, rcinit);\ 777dd7cddfSDavid du Colombier }\ 787dd7cddfSDavid du Colombier END 797dd7cddfSDavid du Colombier #define rc_alloc_struct_0(vp, typ, pstype, mem, errstat, cname)\ 807dd7cddfSDavid du Colombier rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 0) 817dd7cddfSDavid du Colombier #define rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname)\ 827dd7cddfSDavid du Colombier rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 1) 837dd7cddfSDavid du Colombier 847dd7cddfSDavid du Colombier #define rc_free_struct(vp, cname)\ 857dd7cddfSDavid du Colombier BEGIN\ 867dd7cddfSDavid du Colombier IF_RC_DEBUG(rc_trace_free_struct(vp, &(vp)->rc, cname));\ 877dd7cddfSDavid du Colombier (vp)->rc.free((vp)->rc.memory, (void *)(vp), cname);\ 887dd7cddfSDavid du Colombier END 897dd7cddfSDavid du Colombier 907dd7cddfSDavid du Colombier /* ------ Reference counting ------ */ 917dd7cddfSDavid du Colombier 927dd7cddfSDavid du Colombier /* Increment a reference count. */ 937dd7cddfSDavid du Colombier #define RC_DO_INCREMENT(vp)\ 947dd7cddfSDavid du Colombier BEGIN\ 957dd7cddfSDavid du Colombier (vp)->rc.ref_count++;\ 967dd7cddfSDavid du Colombier IF_RC_DEBUG(rc_trace_increment(vp, &(vp)->rc));\ 977dd7cddfSDavid du Colombier END 987dd7cddfSDavid du Colombier #define rc_increment(vp)\ 997dd7cddfSDavid du Colombier BEGIN\ 1007dd7cddfSDavid du Colombier if (vp) RC_DO_INCREMENT(vp);\ 1017dd7cddfSDavid du Colombier END 1027dd7cddfSDavid du Colombier 1037dd7cddfSDavid du Colombier /* Increment a reference count, allocating the structure if necessary. */ 1047dd7cddfSDavid du Colombier #define rc_allocate_struct(vp, typ, pstype, mem, errstat, cname)\ 1057dd7cddfSDavid du Colombier BEGIN\ 1067dd7cddfSDavid du Colombier if (vp)\ 1077dd7cddfSDavid du Colombier RC_DO_INCREMENT(vp);\ 1087dd7cddfSDavid du Colombier else\ 1097dd7cddfSDavid du Colombier rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname);\ 1107dd7cddfSDavid du Colombier END 1117dd7cddfSDavid du Colombier 1127dd7cddfSDavid du Colombier /* Guarantee that a structure is allocated and is not shared. */ 1137dd7cddfSDavid du Colombier #define RC_DO_ADJUST(vp, delta)\ 1147dd7cddfSDavid du Colombier BEGIN\ 1157dd7cddfSDavid du Colombier IF_RC_DEBUG(rc_trace_adjust(vp, &(vp)->rc, delta));\ 1167dd7cddfSDavid du Colombier (vp)->rc.ref_count += (delta);\ 1177dd7cddfSDavid du Colombier END 1187dd7cddfSDavid du Colombier #define rc_unshare_struct(vp, typ, pstype, mem, errstat, cname)\ 1197dd7cddfSDavid du Colombier BEGIN\ 1207dd7cddfSDavid du Colombier if ( (vp) == 0 || (vp)->rc.ref_count > 1 || (vp)->rc.memory != (mem) ) {\ 1217dd7cddfSDavid du Colombier typ *new;\ 1227dd7cddfSDavid du Colombier rc_alloc_struct_1(new, typ, pstype, mem, errstat, cname);\ 1237dd7cddfSDavid du Colombier if ( vp ) RC_DO_ADJUST(vp, -1);\ 1247dd7cddfSDavid du Colombier (vp) = new;\ 1257dd7cddfSDavid du Colombier }\ 1267dd7cddfSDavid du Colombier END 1277dd7cddfSDavid du Colombier 1287dd7cddfSDavid du Colombier /* Adjust a reference count either up or down. */ 1297dd7cddfSDavid du Colombier #ifdef DEBUG 1307dd7cddfSDavid du Colombier # define rc_check_(vp)\ 1317dd7cddfSDavid du Colombier BEGIN\ 1327dd7cddfSDavid du Colombier if (gs_debug_c('?') && (vp)->rc.ref_count < 0)\ 1337dd7cddfSDavid du Colombier lprintf2("0x%lx has ref_count of %ld!\n", (ulong)(vp),\ 1347dd7cddfSDavid du Colombier (vp)->rc.ref_count);\ 1357dd7cddfSDavid du Colombier END 1367dd7cddfSDavid du Colombier #else 1377dd7cddfSDavid du Colombier # define rc_check_(vp) DO_NOTHING 1387dd7cddfSDavid du Colombier #endif 1397dd7cddfSDavid du Colombier #define rc_adjust_(vp, delta, cname, body)\ 1407dd7cddfSDavid du Colombier BEGIN\ 1417dd7cddfSDavid du Colombier if (vp) {\ 1427dd7cddfSDavid du Colombier RC_DO_ADJUST(vp, delta);\ 1437dd7cddfSDavid du Colombier if (!(vp)->rc.ref_count) {\ 1447dd7cddfSDavid du Colombier rc_free_struct(vp, cname);\ 1457dd7cddfSDavid du Colombier body;\ 1467dd7cddfSDavid du Colombier } else\ 1477dd7cddfSDavid du Colombier rc_check_(vp);\ 1487dd7cddfSDavid du Colombier }\ 1497dd7cddfSDavid du Colombier END 1507dd7cddfSDavid du Colombier #define rc_adjust(vp, delta, cname)\ 1517dd7cddfSDavid du Colombier rc_adjust_(vp, delta, cname, (vp) = 0) 1527dd7cddfSDavid du Colombier #define rc_adjust_only(vp, delta, cname)\ 1537dd7cddfSDavid du Colombier rc_adjust_(vp, delta, cname, DO_NOTHING) 1547dd7cddfSDavid du Colombier #define rc_adjust_const(vp, delta, cname)\ 1557dd7cddfSDavid du Colombier rc_adjust_only(vp, delta, cname) 1567dd7cddfSDavid du Colombier #define rc_decrement(vp, cname)\ 1577dd7cddfSDavid du Colombier rc_adjust(vp, -1, cname) 1587dd7cddfSDavid du Colombier #define rc_decrement_only(vp, cname)\ 1597dd7cddfSDavid du Colombier rc_adjust_only(vp, -1, cname) 1607dd7cddfSDavid du Colombier 1617dd7cddfSDavid du Colombier /* 1627dd7cddfSDavid du Colombier * Assign a pointer, adjusting reference counts. vpfrom might be a local 1637dd7cddfSDavid du Colombier * variable with a copy of the last reference to the object, and freeing 1647dd7cddfSDavid du Colombier * vpto might decrement the object's reference count and cause it to be 1657dd7cddfSDavid du Colombier * freed (incorrectly); for that reason, we do the increment first. 1667dd7cddfSDavid du Colombier */ 1677dd7cddfSDavid du Colombier #define rc_assign(vpto, vpfrom, cname)\ 1687dd7cddfSDavid du Colombier BEGIN\ 1697dd7cddfSDavid du Colombier if ((vpto) != (vpfrom)) {\ 1707dd7cddfSDavid du Colombier rc_increment(vpfrom);\ 1717dd7cddfSDavid du Colombier rc_decrement_only(vpto, cname);\ 1727dd7cddfSDavid du Colombier (vpto) = (vpfrom);\ 1737dd7cddfSDavid du Colombier }\ 1747dd7cddfSDavid du Colombier END 1757dd7cddfSDavid du Colombier /* 1767dd7cddfSDavid du Colombier * Adjust reference counts for assigning a pointer, 1777dd7cddfSDavid du Colombier * but don't do the assignment. We use this before assigning 1787dd7cddfSDavid du Colombier * an entire structure containing reference-counted pointers. 1797dd7cddfSDavid du Colombier */ 1807dd7cddfSDavid du Colombier #define rc_pre_assign(vpto, vpfrom, cname)\ 1817dd7cddfSDavid du Colombier BEGIN\ 1827dd7cddfSDavid du Colombier if ((vpto) != (vpfrom)) {\ 1837dd7cddfSDavid du Colombier rc_increment(vpfrom);\ 1847dd7cddfSDavid du Colombier rc_decrement_only(vpto, cname);\ 1857dd7cddfSDavid du Colombier }\ 1867dd7cddfSDavid du Colombier END 1877dd7cddfSDavid du Colombier 1887dd7cddfSDavid du Colombier #endif /* gsrefct_INCLUDED */ 189