rpm  5.4.10
rpmmalloc.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 #include <rpmiotypes.h>
7 #include <rpmio.h>
8 #include <rpmlog.h>
9 #include <yarn.h>
10 #include "debug.h"
11 
12 #ifdef __cplusplus
13 GENfree(rpmioItem)
14 #endif /* __cplusplus */
15 
16 #if defined(WITH_DMALLOC)
17 #undef xmalloc
18 #undef xcalloc
19 #undef xrealloc
20 #undef xstrdup
21 #endif
22 
23 #if !defined(EXIT_FAILURE)
24 #define EXIT_FAILURE 1
25 #endif
26 
27 /*@-modfilesys@*/
28 /*@only@*/ void *vmefail(size_t size)
29 {
30  fprintf(stderr, _("memory alloc (%u bytes) returned NULL.\n"), (unsigned)size);
31  assert(0);
32  exit(EXIT_FAILURE);
33  /*@notreached@*/
34 /*@-nullret@*/
35  return NULL;
36 /*@=nullret@*/
37 }
38 /*@=modfilesys@*/
39 
42 struct rpmioPool_s {
44 /*@relnull@*/
45  void *pool;
46 /*@relnull@*/
48 /*@dependent@*/
50  size_t size;
51  int limit;
52  int flags;
53 /*@null@*/
54  const char * (*dbg) (void *item)
55  /*@*/;
56 /*@null@*/
57  void (*init) (void *item)
58  /*@modifies *item @*/;
59 /*@null@*/
60  void (*fini) (void *item)
61  /*@modifies *item @*/;
62  int reused;
63  int made;
64 /*@observer@*/
65  const char *name;
66 /*@null@*/
67  void * zlog;
68 };
69 
70 /*@unchecked@*/ /*@only@*/ /*@null@*/
72 
74  /*@globals _rpmioPool @*/
75  /*@modifies _rpmioPool @*/
76 {
77  if (pool == NULL) {
78  pool = _rpmioPool;
79  _rpmioPool = NULL;
80  }
81  if (pool != NULL) {
82  rpmioItem item;
83  int count = 0;
84  yarnPossess(pool->have);
85 VALGRIND_HG_CLEAN_MEMORY(pool, sizeof(*pool));
86  while ((item = pool->head) != NULL) {
87 VALGRIND_HG_CLEAN_MEMORY(item, pool->size);
88  pool->head = (rpmioItem) item->pool; /* XXX pool == next */
89  if (item->use != NULL)
90  item->use = yarnFreeLock(item->use);
91  item = _free(item);
92  count++;
93  }
94  yarnRelease(pool->have);
95  pool->have = yarnFreeLock(pool->have);
96  rpmlog(RPMLOG_DEBUG, D_("pool %s:\treused %d, alloc'd %d, free'd %d items.\n"), pool->name, pool->reused, pool->made, count);
97 #ifdef NOTYET
98 assert(pool->made == count);
99 #else
100 if (pool->made != count)
101 rpmlog(RPMLOG_WARNING, D_("pool %s: FIXME: made %d, count %d\nNote: This is a harmless memory leak discovered while exiting, relax ...\n"), pool->name, pool->made, count);
102 #endif
103  (void) _free(pool);
105  }
106  return NULL;
107 }
108 
109 /*@-internalglobs@*/
110 rpmioPool rpmioNewPool(const char * name, size_t size, int limit, int flags,
111  char * (*dbg) (void *item),
112  void (*init) (void *item),
113  void (*fini) (void *item))
114  /*@*/
115 {
116  rpmioPool pool = (rpmioPool) xcalloc(1, sizeof(*pool));
117 #if defined(WITH_VALGRIND)
118  static int rzB = 0; /* size of red-zones (if any) */
119  static int is_zeroed = 0; /* does pool return zero'd allocations? */
120  rzB = rzB; /* XXX CentOS5 valgrind doesn't use. */
121  is_zeroed = is_zeroed; /* XXX CentOS5 valgrind doesn't use. */
122 #endif
123  VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed);
124  pool->have = yarnNewLock(0);
125  pool->pool = NULL;
126  pool->head = NULL;
127  pool->tail = &pool->head;
128  pool->size = size;
129  pool->limit = limit;
130  pool->flags = flags;
131  pool->dbg = (const char* (*)(void*)) dbg;
132  pool->init = init;
133  pool->fini = fini;
134  pool->reused = 0;
135  pool->made = 0;
136  pool->name = name;
137  pool->zlog = NULL;
138  rpmlog(RPMLOG_DEBUG, D_("pool %s:\tcreated size %u limit %d flags %d\n"), pool->name, (unsigned)pool->size, pool->limit, pool->flags);
139  return pool;
140 }
141 /*@=internalglobs@*/
142 
143 /*@-internalglobs@*/
144 rpmioItem rpmioUnlinkPoolItem(rpmioItem item, const char * msg,
145  const char * fn, unsigned ln)
146 {
147  rpmioPool pool;
148  if (item == NULL) return NULL;
149  yarnPossess(item->use);
151  if ((pool = (rpmioPool) item->pool) != NULL && pool->flags && msg != NULL) {
152  const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
153 /*@-modfilesys@*/
154  fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
155  item, yarnPeekLock(item->use), msg, fn, ln, imsg);
156 /*@=modfilesys@*/
157  }
158  yarnTwist(item->use, BY, -1);
159 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
160  return item;
161 /*@=retalias@*/
162 }
163 /*@=internalglobs@*/
164 
165 /*@-internalglobs@*/
166 rpmioItem rpmioLinkPoolItem(rpmioItem item, const char * msg,
167  const char * fn, unsigned ln)
168 {
169  rpmioPool pool;
170  if (item == NULL) return NULL;
171  yarnPossess(item->use);
172  if ((pool = (rpmioPool) item->pool) != NULL && pool->flags && msg != NULL) {
173  const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
174 /*@-modfilesys@*/
175  fprintf(stderr, "--> %s %p ++ %ld %s at %s:%u%s\n", pool->name,
176  item, yarnPeekLock(item->use)+1, msg, fn, ln, imsg);
177 /*@=modfilesys@*/
178  }
180  yarnTwist(item->use, BY, 1);
181  return item;
182 }
183 /*@=internalglobs@*/
184 
185 /*@-internalglobs@*/
186 /*@null@*/
187 void * rpmioFreePoolItem(/*@killref@*/ /*@null@*/ rpmioItem item,
188  const char * msg, const char * fn, unsigned ln)
189  /*@modifies item @*/
190 {
191  rpmioPool pool;
192  if (item == NULL) return NULL;
193 
194 #ifdef NOTYET
195 assert(item->pool != NULL); /* XXX (*pool->fini) is likely necessary */
196 #endif
197  yarnPossess(item->use);
199  if ((pool = (rpmioPool) item->pool) != NULL && pool->flags && msg != NULL) {
200  const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
201 /*@-modfilesys@*/
202  fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
203  item, yarnPeekLock(item->use), msg, fn, ln, imsg);
204 /*@=modfilesys@*/
205  }
206  if (yarnPeekLock(item->use) <= 1L) {
207 VALGRIND_HG_CLEAN_MEMORY(item, pool->size);
208  if (pool != NULL && pool->fini != NULL)
209  (*pool->fini) ((void *)item);
210  VALGRIND_MEMPOOL_FREE(pool, item + 1);
211  item = rpmioPutPool(item);
212  } else
213  yarnTwist(item->use, BY, -1);
214 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
215  return (void *) item;
216 /*@=retalias@*/
217 }
218 /*@=internalglobs@*/
219 
220 /*@-internalglobs@*/
222 {
223  rpmioItem item;
224 
225  if (pool != NULL) {
226  /* if can't create any more, wait for a space to show up */
227  yarnPossess(pool->have);
228  if (pool->limit == 0)
229  yarnWaitFor(pool->have, NOT_TO_BE, 0);
230 
231  /* if a space is available, pull it from the list and return it */
232  if (pool->head != NULL) {
233  item = pool->head;
234  pool->head = (rpmioItem) item->pool; /* XXX pool == next */
235  if (pool->head == NULL)
236  pool->tail = &pool->head;
237  pool->reused++;
238  item->pool = pool; /* remember the pool this belongs to */
239  yarnTwist(pool->have, BY, -1); /* one less in pool */
241  item + 1,
242  size - sizeof(struct rpmioItem_s));
243  return item;
244  }
245 
246  /* nothing available, don't want to wait, make a new item */
247 assert(pool->limit != 0);
248  if (pool->limit > 0)
249  pool->limit--;
250  pool->made++;
251  yarnRelease(pool->have);
252  }
253 
254  item = (rpmioItem) xcalloc(1, size);
255  item->use = yarnNewLock(0); /* XXX newref? */
256  item->pool = pool;
258  item + 1,
259  size - sizeof(struct rpmioItem_s));
260  return item;
261 }
262 /*@=internalglobs@*/
263 
264 /*@-internalglobs@*/
266 {
267  rpmioPool pool;
268 
269  if ((pool = (rpmioPool) item->pool) != NULL) {
270  yarnPossess(pool->have);
271  item->pool = NULL; /* XXX pool == next */
272  *pool->tail = item;
273  pool->tail = (rpmioItem *)&item->pool;/* XXX pool == next */
274  yarnTwist(pool->have, BY, 1);
275  if (item->use != NULL)
276  yarnTwist(item->use, TO, 0);
277  return NULL;
278  }
279 
280  if (item->use != NULL) {
281  yarnTwist(item->use, TO, 0);
282  item->use = yarnFreeLock(item->use);
283  }
284  (void) _free(item);
285  return NULL;
286 }
287 /*@=internalglobs@*/
288 
289 #if !(HAVE_MCHECK_H && defined(__GNUC__)) && !defined(__LCLINT__)
290 
291 /*@out@*/ /*@only@*/ void * xmalloc (size_t size)
292 {
293  register void *value;
294  if (size == 0) size++;
295  value = malloc (size);
296  if (value == 0)
297  value = vmefail(size);
298  return value;
299 }
300 
301 /*@only@*/ void * xcalloc (size_t nmemb, size_t size)
302 {
303  register void *value;
304  if (size == 0) size++;
305  if (nmemb == 0) nmemb++;
306  value = calloc (nmemb, size);
307  if (value == 0)
308  value = vmefail(size);
309  return value;
310 }
311 
312 /*@only@*/ void * xrealloc (/*@only@*/ void *ptr, size_t size)
313 {
314  register void *value;
315  if (size == 0) size++;
316  value = realloc (ptr, size);
317  if (value == 0)
318  value = vmefail(size);
319  return value;
320 }
321 
322 /*@only@*/ char * xstrdup (const char *str)
323 {
324  size_t size = strlen(str) + 1;
325  char *newstr = (char *) malloc (size);
326  if (newstr == 0)
327  newstr = (char *) vmefail(size);
328  strcpy (newstr, str);
329  return newstr;
330 }
331 
332 #endif /* !(HAVE_MCHECK_H && defined(__GNUC__)) */
rpmioItem * tail
Definition: rpmmalloc.c:49
void * pool
Definition: rpmmalloc.c:45
yarnLock use
Definition: rpmiotypes.h:41
rpmioItem rpmioLinkPoolItem(rpmioItem item, const char *msg, const char *fn, unsigned ln)
Increment a pool item refcount.
Definition: rpmmalloc.c:166
static rpmioPool _rpmioPool
Definition: rpmmalloc.c:71
void * pool
Definition: rpmiotypes.h:43
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
int reused
Definition: rpmmalloc.c:62
#define VALGRIND_MEMPOOL_FREE(pool, addr)
Definition: debug.h:88
#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)
Definition: debug.h:85
const char *(* dbg)(void *item)
Definition: rpmmalloc.c:54
void * xrealloc(void *ptr, size_t size)
Definition: rpmmalloc.c:312
rpmioItem head
Definition: rpmmalloc.c:47
Yet Another syslog(3) API clone.
struct rpmioPool_s * rpmioPool
Definition: rpmiotypes.h:53
size_t size
Definition: rpmmalloc.c:50
void(* fini)(void *item)
Definition: rpmmalloc.c:60
#define VALGRIND_DESTROY_MEMPOOL(pool)
Definition: debug.h:86
void * rpmioFreePoolItem(rpmioItem item, const char *msg, const char *fn, unsigned ln)
Free a pool item.
Definition: rpmmalloc.c:187
void(* init)(void *item)
Definition: rpmmalloc.c:57
yarnLock have
Definition: rpmmalloc.c:43
void * xmalloc(size_t size)
Definition: rpmmalloc.c:291
#define EXIT_FAILURE
Definition: rpmmalloc.c:24
rpmioItem rpmioUnlinkPoolItem(rpmioItem item, const char *msg, const char *fn, unsigned ln)
Decrement a pool item refcount.
Definition: rpmmalloc.c:144
rpmioPool rpmioNewPool(const char *name, size_t size, int limit, int flags, char *(*dbg)(void *item), void(*init)(void *item), void(*fini)(void *item))
Create a memory pool.
Definition: rpmmalloc.c:110
void * zlog
Definition: rpmmalloc.c:67
rpmioItem rpmioPutPool(rpmioItem item)
Put unused item into pool (or free).
Definition: rpmmalloc.c:265
#define L(CS)
Definition: fnmatch.c:155
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:221
struct rpmioItem_s * rpmioItem
Definition: rpmiotypes.h:38
#define ANNOTATE_HAPPENS_BEFORE(_obj)
Definition: debug.h:142
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
#define VALGRIND_HG_CLEAN_MEMORY(_qzz_start, _qzz_len)
Definition: debug.h:131
#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)
Definition: debug.h:87
struct yarnLock_s * yarnLock
Definition: rpmiotypes.h:34
#define _(Text)
Definition: system.h:30
#define ANNOTATE_HAPPENS_AFTER(_obj)
Definition: debug.h:143
rpmioPool rpmioFreePool(rpmioPool pool)
Reclaim memory pool items.
Definition: rpmmalloc.c:73
const char * name
Definition: rpmmalloc.c:65
#define D_(Text)
Definition: system.h:485
void * vmefail(size_t size)
Definition: rpmmalloc.c:28
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:301
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322