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