Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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 */