Quake II RTX doxygen  1.0 dev
zone.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 #include "shared/shared.h"
20 #include "common/common.h"
21 #include "common/zone.h"
22 
23 #define Z_MAGIC 0x1d0d
24 #define Z_TAIL 0x5b7b
25 
26 #define Z_TAIL_F(z) \
27  *(uint16_t *)((byte *)(z) + (z)->size - sizeof(uint16_t))
28 
29 #define Z_FOR_EACH(z) \
30  for ((z) = z_chain.next; (z) != &z_chain; (z) = (z)->next)
31 
32 #define Z_FOR_EACH_SAFE(z, n) \
33  for ((z) = z_chain.next; (z) != &z_chain; (z) = (n))
34 
35 typedef struct zhead_s {
36  uint16_t magic;
37  uint16_t tag; // for group free
38  size_t size;
39 #ifdef _DEBUG
40  void *addr;
41  time_t time;
42 #endif
43  struct zhead_s *prev, *next;
44 } zhead_t;
45 
46 // number of overhead bytes
47 #define Z_EXTRA (sizeof(zhead_t) + sizeof(uint16_t))
48 
50 
51 typedef struct {
53  char data[2];
54  uint16_t tail;
55 } zstatic_t;
56 
57 static const zstatic_t z_static[] = {
58 #define Z_STATIC(x) \
59  { { Z_MAGIC, TAG_STATIC, q_offsetof(zstatic_t, tail) + sizeof(uint16_t) }, x, Z_TAIL }
60 
61  Z_STATIC("0"),
62  Z_STATIC("1"),
63  Z_STATIC("2"),
64  Z_STATIC("3"),
65  Z_STATIC("4"),
66  Z_STATIC("5"),
67  Z_STATIC("6"),
68  Z_STATIC("7"),
69  Z_STATIC("8"),
70  Z_STATIC("9"),
71  Z_STATIC("")
72 
73 #undef Z_STATIC
74 };
75 
76 typedef struct {
77  size_t count;
78  size_t bytes;
79 } zstats_t;
80 
81 static zstats_t z_stats[TAG_MAX];
82 
83 static const char z_tagnames[TAG_MAX][8] = {
84  "game",
85  "static",
86  "generic",
87  "cmd",
88  "cvar",
89  "fs",
90  "refresh",
91  "ui",
92  "server",
93  "mvd",
94  "sound",
95  "cmodel"
96 };
97 
98 static inline void Z_Validate(zhead_t *z, const char *func)
99 {
100  if (z->magic != Z_MAGIC) {
101  Com_Error(ERR_FATAL, "%s: bad magic", func);
102  }
103  if (Z_TAIL_F(z) != Z_TAIL) {
104  Com_Error(ERR_FATAL, "%s: bad tail", func);
105  }
106  if (z->tag == TAG_FREE) {
107  Com_Error(ERR_FATAL, "%s: bad tag", func);
108  }
109 }
110 
111 void Z_Check(void)
112 {
113  zhead_t *z;
114 
115  Z_FOR_EACH(z) {
116  Z_Validate(z, __func__);
117  }
118 }
119 
120 void Z_LeakTest(memtag_t tag)
121 {
122  zhead_t *z;
123  size_t numLeaks = 0, numBytes = 0;
124 
125  Z_FOR_EACH(z) {
126  Z_Validate(z, __func__);
127  if (z->tag == tag) {
128  numLeaks++;
129  numBytes += z->size;
130  }
131  }
132 
133  if (numLeaks) {
134  Com_WPrintf("************* Z_LeakTest *************\n"
135  "%s leaked %"PRIz" bytes of memory (%"PRIz" object%s)\n"
136  "**************************************\n",
137  z_tagnames[tag < TAG_MAX ? tag : TAG_FREE],
138  numBytes, numLeaks, numLeaks == 1 ? "" : "s");
139  }
140 }
141 
142 /*
143 ========================
144 Z_Free
145 ========================
146 */
147 void Z_Free(void *ptr)
148 {
149  zhead_t *z;
150  zstats_t *s;
151 
152  if (!ptr) {
153  return;
154  }
155 
156  z = (zhead_t *)ptr - 1;
157 
158  Z_Validate(z, __func__);
159 
160  s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE];
161  s->count--;
162  s->bytes -= z->size;
163 
164  if (z->tag != TAG_STATIC) {
165  z->prev->next = z->next;
166  z->next->prev = z->prev;
167  z->magic = 0xdead;
168  z->tag = TAG_FREE;
169  free(z);
170  }
171 }
172 
173 /*
174 ========================
175 Z_Realloc
176 ========================
177 */
178 void *Z_Realloc(void *ptr, size_t size)
179 {
180  zhead_t *z;
181  zstats_t *s;
182 
183  if (!ptr) {
184  return Z_Malloc(size);
185  }
186 
187  if (!size) {
188  Z_Free(ptr);
189  return NULL;
190  }
191 
192  z = (zhead_t *)ptr - 1;
193 
194  Z_Validate(z, __func__);
195 
196  if (z->tag == TAG_STATIC) {
197  Com_Error(ERR_FATAL, "%s: couldn't realloc static memory", __func__);
198  }
199 
200  s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE];
201  s->bytes -= z->size;
202 
203  if (size > SIZE_MAX - Z_EXTRA - 3) {
204  Com_Error(ERR_FATAL, "%s: bad size", __func__);
205  }
206 
207  size = (size + Z_EXTRA + 3) & ~3;
208  z = realloc(z, size);
209  if (!z) {
210  Com_Error(ERR_FATAL, "%s: couldn't realloc %"PRIz" bytes", __func__, size);
211  }
212 
213  z->size = size;
214  z->prev->next = z;
215  z->next->prev = z;
216 
217  s->bytes += size;
218 
219  Z_TAIL_F(z) = Z_TAIL;
220 
221  return z + 1;
222 }
223 
224 /*
225 ========================
226 Z_Stats_f
227 ========================
228 */
229 void Z_Stats_f(void)
230 {
231  size_t bytes = 0, count = 0;
232  zstats_t *s;
233  int i;
234 
235  Com_Printf(" bytes blocks name\n"
236  "--------- ------ -------\n");
237 
238  for (i = 0, s = z_stats; i < TAG_MAX; i++, s++) {
239  if (!s->count) {
240  continue;
241  }
242  Com_Printf("%9"PRIz" %6"PRIz" %s\n", s->bytes, s->count, z_tagnames[i]);
243  bytes += s->bytes;
244  count += s->count;
245  }
246 
247  Com_Printf("--------- ------ -------\n"
248  "%9"PRIz" %6"PRIz" total\n",
249  bytes, count);
250 }
251 
252 /*
253 ========================
254 Z_FreeTags
255 ========================
256 */
257 void Z_FreeTags(memtag_t tag)
258 {
259  zhead_t *z, *n;
260 
261  Z_FOR_EACH_SAFE(z, n) {
262  Z_Validate(z, __func__);
263  n = z->next;
264  if (z->tag == tag) {
265  Z_Free(z + 1);
266  }
267  }
268 }
269 
270 /*
271 ========================
272 Z_TagMalloc
273 ========================
274 */
275 void *Z_TagMalloc(size_t size, memtag_t tag)
276 {
277  zhead_t *z;
278  zstats_t *s;
279 
280  if (!size) {
281  return NULL;
282  }
283 
284  if (tag == TAG_FREE) {
285  Com_Error(ERR_FATAL, "%s: bad tag", __func__);
286  }
287 
288  if (size > SIZE_MAX - Z_EXTRA - 3) {
289  Com_Error(ERR_FATAL, "%s: bad size", __func__);
290  }
291 
292  size = (size + Z_EXTRA + 3) & ~3;
293  z = malloc(size);
294  if (!z) {
295  Com_Error(ERR_FATAL, "%s: couldn't allocate %"PRIz" bytes", __func__, size);
296  }
297  z->magic = Z_MAGIC;
298  z->tag = tag;
299  z->size = size;
300 
301 #ifdef _DEBUG
302 #if (defined __GNUC__)
303  z->addr = __builtin_return_address(0);
304 #elif (defined _MSC_VER)
305  z->addr = _ReturnAddress();
306 #else
307  z->addr = NULL;
308 #endif
309  z->time = time(NULL);
310 #endif
311 
312  z->next = z_chain.next;
313  z->prev = &z_chain;
314  z_chain.next->prev = z;
315  z_chain.next = z;
316 
317  if (z_perturb && z_perturb->integer) {
318  memset(z + 1, z_perturb->integer, size - Z_EXTRA);
319  }
320 
321  Z_TAIL_F(z) = Z_TAIL;
322 
323  s = &z_stats[tag < TAG_MAX ? tag : TAG_FREE];
324  s->count++;
325  s->bytes += size;
326 
327  return z + 1;
328 }
329 
330 void *Z_TagMallocz(size_t size, memtag_t tag)
331 {
332  if (!size) {
333  return NULL;
334  }
335  return memset(Z_TagMalloc(size, tag), 0, size);
336 }
337 
338 static byte *z_reserved_data;
339 static size_t z_reserved_inuse;
340 static size_t z_reserved_total;
341 
342 void Z_TagReserve(size_t size, memtag_t tag)
343 {
344  z_reserved_data = Z_TagMalloc(size, tag);
345  z_reserved_total = size;
346  z_reserved_inuse = 0;
347 }
348 
349 void *Z_ReservedAlloc(size_t size)
350 {
351  void *ptr;
352 
353  if (!size) {
354  return NULL;
355  }
356 
357  if (size > z_reserved_total - z_reserved_inuse) {
358  Com_Error(ERR_FATAL, "%s: couldn't allocate %"PRIz" bytes", __func__, size);
359  }
360 
362  z_reserved_inuse += size;
363 
364  return ptr;
365 }
366 
367 void *Z_ReservedAllocz(size_t size)
368 {
369  if (!size) {
370  return NULL;
371  }
372  return memset(Z_ReservedAlloc(size), 0, size);
373 }
374 
375 char *Z_ReservedCopyString(const char *in)
376 {
377  size_t len;
378 
379  if (!in) {
380  return NULL;
381  }
382 
383  len = strlen(in) + 1;
384  return memcpy(Z_ReservedAlloc(len), in, len);
385 }
386 
387 /*
388 ========================
389 Z_Init
390 ========================
391 */
392 void Z_Init(void)
393 {
395 }
396 
397 /*
398 ================
399 Z_TagCopyString
400 ================
401 */
402 char *Z_TagCopyString(const char *in, memtag_t tag)
403 {
404  size_t len;
405 
406  if (!in) {
407  return NULL;
408  }
409 
410  len = strlen(in) + 1;
411  return memcpy(Z_TagMalloc(len, tag), in, len);
412 }
413 
414 /*
415 ================
416 Z_CvarCopyString
417 ================
418 */
419 char *Z_CvarCopyString(const char *in)
420 {
421  size_t len;
422  zstatic_t *z;
423  zstats_t *s;
424  int i;
425 
426  if (!in) {
427  return NULL;
428  }
429 
430  if (!in[0]) {
431  i = 10;
432  } else if (!in[1] && Q_isdigit(in[0])) {
433  i = in[0] - '0';
434  } else {
435  len = strlen(in) + 1;
436  return memcpy(Z_TagMalloc(len, TAG_CVAR), in, len);
437  }
438 
439  // return static storage
440  z = (zstatic_t *)&z_static[i];
441  s = &z_stats[TAG_STATIC];
442  s->count++;
443  s->bytes += z->z.size;
444  return z->data;
445 }
446 
447 
Z_ReservedAlloc
void * Z_ReservedAlloc(size_t size)
Definition: zone.c:349
Z_CvarCopyString
char * Z_CvarCopyString(const char *in)
Definition: zone.c:419
zstatic_t
Definition: zone.c:51
Z_EXTRA
#define Z_EXTRA
Definition: zone.c:47
z_reserved_total
static size_t z_reserved_total
Definition: zone.c:340
zstats_t
Definition: zone.c:76
Z_LeakTest
void Z_LeakTest(memtag_t tag)
Definition: zone.c:120
Z_FOR_EACH_SAFE
#define Z_FOR_EACH_SAFE(z, n)
Definition: zone.c:32
Z_FOR_EACH
#define Z_FOR_EACH(z)
Definition: zone.c:29
zhead_s::prev
struct zhead_s * prev
Definition: zone.c:43
zhead_s::magic
uint16_t magic
Definition: zone.c:36
zstats_t::bytes
size_t bytes
Definition: zone.c:78
zstatic_t::data
char data[2]
Definition: zone.c:53
zstatic_t::z
zhead_t z
Definition: zone.c:52
Z_Stats_f
void Z_Stats_f(void)
Definition: zone.c:229
Z_MAGIC
#define Z_MAGIC
Definition: zone.c:23
Z_TagCopyString
char * Z_TagCopyString(const char *in, memtag_t tag)
Definition: zone.c:402
Z_TagMalloc
void * Z_TagMalloc(size_t size, memtag_t tag)
Definition: zone.c:275
z_static
static const zstatic_t z_static[]
Definition: zone.c:57
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
z_perturb
cvar_t * z_perturb
Definition: common.c:75
Z_ReservedCopyString
char * Z_ReservedCopyString(const char *in)
Definition: zone.c:375
zhead_s::next
struct zhead_s * next
Definition: zone.c:43
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
zstats_t::count
size_t count
Definition: zone.c:77
Z_TagMallocz
void * Z_TagMallocz(size_t size, memtag_t tag)
Definition: zone.c:330
Z_ReservedAllocz
void * Z_ReservedAllocz(size_t size)
Definition: zone.c:367
Z_Check
void Z_Check(void)
Definition: zone.c:111
Z_TagReserve
void Z_TagReserve(size_t size, memtag_t tag)
Definition: zone.c:342
zhead_s::size
size_t size
Definition: zone.c:38
zhead_t
struct zhead_s zhead_t
z_stats
static zstats_t z_stats[TAG_MAX]
Definition: zone.c:81
zstatic_t::tail
uint16_t tail
Definition: zone.c:54
z_tagnames
static const char z_tagnames[TAG_MAX][8]
Definition: zone.c:83
Z_Init
void Z_Init(void)
Definition: zone.c:392
zhead_s::tag
uint16_t tag
Definition: zone.c:37
z_chain
static zhead_t z_chain
Definition: zone.c:49
Z_FreeTags
void Z_FreeTags(memtag_t tag)
Definition: zone.c:257
Z_STATIC
#define Z_STATIC(x)
z_reserved_inuse
static size_t z_reserved_inuse
Definition: zone.c:339
Z_Validate
static void Z_Validate(zhead_t *z, const char *func)
Definition: zone.c:98
Z_Realloc
void * Z_Realloc(void *ptr, size_t size)
Definition: zone.c:178
z_reserved_data
static byte * z_reserved_data
Definition: zone.c:338
Z_TAIL
#define Z_TAIL
Definition: zone.c:24
Z_TAIL_F
#define Z_TAIL_F(z)
Definition: zone.c:26
zhead_s
Definition: zone.c:35