rpm  5.2.1
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 #if defined(WITH_DMALLOC)
13 #undef xmalloc
14 #undef xcalloc
15 #undef xrealloc
16 #undef xstrdup
17 #endif
18 
19 #if !defined(EXIT_FAILURE)
20 #define EXIT_FAILURE 1
21 #endif
22 
23 /*@-modfilesys@*/
24 /*@only@*/ void *vmefail(size_t size)
25 {
26  fprintf(stderr, _("memory alloc (%u bytes) returned NULL.\n"), (unsigned)size);
27  exit(EXIT_FAILURE);
28  /*@notreached@*/
29 /*@-nullret@*/
30  return NULL;
31 /*@=nullret@*/
32 }
33 /*@=modfilesys@*/
34 
37 struct rpmioPool_s {
38  yarnLock have;
39 /*@relnull@*/
40  void *pool;
41 /*@relnull@*/
43 /*@dependent@*/
45  size_t size;
46  int limit;
47  int flags;
48 /*@null@*/
49  const char * (*dbg) (void *item)
50  /*@*/;
51 /*@null@*/
52  void (*init) (void *item)
53  /*@modifies *item @*/;
54 /*@null@*/
55  void (*fini) (void *item)
56  /*@modifies *item @*/;
57  int reused;
58  int made;
59 /*@observer@*/
60  const char *name;
61 /*@null@*/
62  void * zlog;
63 };
64 
65 /*@unchecked@*/ /*@only@*/ /*@null@*/
67 
69  /*@globals _rpmioPool @*/
70  /*@modifies _rpmioPool @*/
71 {
72  if (pool == NULL) {
73  pool = _rpmioPool;
74  _rpmioPool = NULL;
75  }
76  if (pool != NULL) {
77  rpmioItem item;
78  int count = 0;
79  yarnPossess(pool->have);
80  while ((item = pool->head) != NULL) {
81  pool->head = item->pool; /* XXX pool == next */
82  if (item->use != NULL)
83  item->use = yarnFreeLock(item->use);
84  item = _free(item);
85  count++;
86  }
87  yarnRelease(pool->have);
88  pool->have = yarnFreeLock(pool->have);
89  rpmlog(RPMLOG_DEBUG, D_("pool %s:\treused %d, alloc'd %d, free'd %d items.\n"), pool->name, pool->reused, pool->made, count);
90 #ifdef NOTYET
91 assert(pool->made == count);
92 #else
93 if (pool->made != count)
94 rpmlog(RPMLOG_DEBUG, 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);
95 #endif
96  pool = _free(pool);
97  }
98  return NULL;
99 }
100 
101 /*@-internalglobs@*/
102 rpmioPool rpmioNewPool(const char * name, size_t size, int limit, int flags,
103  const char * (*dbg) (void *item),
104  void (*init) (void *item),
105  void (*fini) (void *item))
106  /*@*/
107 {
108  rpmioPool pool = xcalloc(1, sizeof(*pool));
109  pool->have = yarnNewLock(0);
110  pool->pool = NULL;
111  pool->head = NULL;
112  pool->tail = &pool->head;
113  pool->size = size;
114  pool->limit = limit;
115  pool->flags = flags;
116  pool->dbg = dbg;
117  pool->init = init;
118  pool->fini = fini;
119  pool->reused = 0;
120  pool->made = 0;
121  pool->name = name;
122  pool->zlog = NULL;
123  rpmlog(RPMLOG_DEBUG, D_("pool %s:\tcreated size %u limit %d flags %d\n"), pool->name, (unsigned)pool->size, pool->limit, pool->flags);
124  return pool;
125 }
126 /*@=internalglobs@*/
127 
128 /*@-internalglobs@*/
129 rpmioItem rpmioUnlinkPoolItem(rpmioItem item, const char * msg,
130  const char * fn, unsigned ln)
131 {
132  rpmioPool pool;
133  if (item == NULL) return NULL;
134  yarnPossess(item->use);
135  if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
136  const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
137 /*@-modfilesys@*/
138  fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
139  item, yarnPeekLock(item->use), msg, fn, ln, imsg);
140 /*@=modfilesys@*/
141  }
142  yarnTwist(item->use, BY, -1);
143 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
144  return item;
145 /*@=retalias@*/
146 }
147 /*@=internalglobs@*/
148 
149 /*@-internalglobs@*/
150 rpmioItem rpmioLinkPoolItem(rpmioItem item, const char * msg,
151  const char * fn, unsigned ln)
152 {
153  rpmioPool pool;
154  if (item == NULL) return NULL;
155  yarnPossess(item->use);
156  if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
157  const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
158 /*@-modfilesys@*/
159  fprintf(stderr, "--> %s %p ++ %ld %s at %s:%u%s\n", pool->name,
160  item, yarnPeekLock(item->use)+1, msg, fn, ln, imsg);
161 /*@=modfilesys@*/
162  }
163  yarnTwist(item->use, BY, 1);
164  return item;
165 }
166 /*@=internalglobs@*/
167 
168 /*@-internalglobs@*/
169 /*@null@*/
170 void * rpmioFreePoolItem(/*@killref@*/ /*@null@*/ rpmioItem item,
171  const char * msg, const char * fn, unsigned ln)
172  /*@modifies item @*/
173 {
174  rpmioPool pool;
175  if (item == NULL) return NULL;
176 
177 #ifdef NOTYET
178 assert(item->pool != NULL); /* XXX (*pool->fini) is likely necessary */
179 #endif
180  yarnPossess(item->use);
181  if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
182  const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
183 /*@-modfilesys@*/
184  fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
185  item, yarnPeekLock(item->use), msg, fn, ln, imsg);
186 /*@=modfilesys@*/
187  }
188  if (yarnPeekLock(item->use) <= 1L) {
189  if (pool != NULL && pool->fini != NULL)
190  (*pool->fini) ((void *)item);
191  item = rpmioPutPool(item);
192  } else
193  yarnTwist(item->use, BY, -1);
194 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
195  return (void *) item;
196 /*@=retalias@*/
197 }
198 /*@=internalglobs@*/
199 
200 /*@-internalglobs@*/
201 rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
202 {
203  rpmioItem item;
204 
205  if (pool != NULL) {
206  /* if can't create any more, wait for a space to show up */
207  yarnPossess(pool->have);
208  if (pool->limit == 0)
209  yarnWaitFor(pool->have, NOT_TO_BE, 0);
210 
211  /* if a space is available, pull it from the list and return it */
212  if (pool->head != NULL) {
213  item = pool->head;
214  pool->head = item->pool; /* XXX pool == next */
215  if (pool->head == NULL)
216  pool->tail = &pool->head;
217  pool->reused++;
218  item->pool = pool; /* remember the pool this belongs to */
219  yarnTwist(pool->have, BY, -1); /* one less in pool */
220  return item;
221  }
222 
223  /* nothing available, don't want to wait, make a new item */
224 assert(pool->limit != 0);
225  if (pool->limit > 0)
226  pool->limit--;
227  pool->made++;
228  yarnRelease(pool->have);
229  }
230 
231  item = xcalloc(1, size);
232  item->use = yarnNewLock(0); /* XXX newref? */
233  item->pool = pool;
234  return item;
235 }
236 /*@=internalglobs@*/
237 
238 /*@-internalglobs@*/
240 {
241  rpmioPool pool;
242 
243  if ((pool = item->pool) != NULL) {
244  yarnPossess(pool->have);
245  item->pool = NULL; /* XXX pool == next */
246  *pool->tail = item;
247  pool->tail = (rpmioItem *)&item->pool;/* XXX pool == next */
248  yarnTwist(pool->have, BY, 1);
249  if (item->use != NULL)
250  yarnTwist(item->use, TO, 0);
251  return NULL;
252  }
253 
254  if (item->use != NULL) {
255  yarnTwist(item->use, TO, 0);
256  item->use = yarnFreeLock(item->use);
257  }
258  item = _free(item);
259  return NULL;
260 }
261 /*@=internalglobs@*/
262 
263 #if !(HAVE_MCHECK_H && defined(__GNUC__)) && !defined(__LCLINT__)
264 
265 /*@out@*/ /*@only@*/ void * xmalloc (size_t size)
266 {
267  register void *value;
268  if (size == 0) size++;
269  value = malloc (size);
270  if (value == 0)
271  value = vmefail(size);
272  return value;
273 }
274 
275 /*@only@*/ void * xcalloc (size_t nmemb, size_t size)
276 {
277  register void *value;
278  if (size == 0) size++;
279  if (nmemb == 0) nmemb++;
280  value = calloc (nmemb, size);
281  if (value == 0)
282  value = vmefail(size);
283  return value;
284 }
285 
286 /*@only@*/ void * xrealloc (/*@only@*/ void *ptr, size_t size)
287 {
288  register void *value;
289  if (size == 0) size++;
290  value = realloc (ptr, size);
291  if (value == 0)
292  value = vmefail(size);
293  return value;
294 }
295 
296 /*@only@*/ char * xstrdup (const char *str)
297 {
298  size_t size = strlen(str) + 1;
299  char *newstr = (char *) malloc (size);
300  if (newstr == 0)
301  newstr = (char *) vmefail(size);
302  strcpy (newstr, str);
303  return newstr;
304 }
305 
306 #endif /* !(HAVE_MCHECK_H && defined(__GNUC__)) */