xref: /plan9/sys/src/cmd/gs/src/gsrefct.h (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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