rpm 5.3.7

rpmio/rpmmalloc.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 #include <rpmiotypes.h>
00007 #include <rpmio.h>
00008 #include <rpmlog.h>
00009 #include <yarn.h>
00010 #include "debug.h"
00011 
00012 #if defined(WITH_DMALLOC)
00013 #undef xmalloc
00014 #undef xcalloc
00015 #undef xrealloc
00016 #undef xstrdup
00017 #endif
00018 
00019 #if !defined(EXIT_FAILURE)
00020 #define EXIT_FAILURE    1
00021 #endif
00022 
00023 /*@-modfilesys@*/
00024 /*@only@*/ void *vmefail(size_t size)
00025 {
00026     fprintf(stderr, _("memory alloc (%u bytes) returned NULL.\n"), (unsigned)size);
00027     exit(EXIT_FAILURE);
00028     /*@notreached@*/
00029 /*@-nullret@*/
00030     return NULL;
00031 /*@=nullret@*/
00032 }
00033 /*@=modfilesys@*/
00034 
00037 struct rpmioPool_s {
00038     yarnLock have;              
00039 /*@relnull@*/
00040     void *pool;
00041 /*@relnull@*/
00042     rpmioItem head;             
00043 /*@dependent@*/
00044     rpmioItem * tail;
00045     size_t size;                
00046     int limit;                  
00047     int flags;
00048 /*@null@*/
00049     const char * (*dbg) (void *item)
00050         /*@*/;                  
00051 /*@null@*/
00052     void (*init) (void *item)
00053         /*@modifies *item @*/;  
00054 /*@null@*/
00055     void (*fini) (void *item)
00056         /*@modifies *item @*/;  
00057     int reused;                 
00058     int made;                   
00059 /*@observer@*/
00060     const char *name;
00061 /*@null@*/
00062     void * zlog;
00063 };
00064 
00065 /*@unchecked@*/ /*@only@*/ /*@null@*/
00066 static rpmioPool _rpmioPool;
00067 
00068 rpmioPool rpmioFreePool(rpmioPool pool)
00069         /*@globals _rpmioPool @*/
00070         /*@modifies _rpmioPool @*/
00071 {
00072     if (pool == NULL) {
00073         pool = _rpmioPool;
00074         _rpmioPool = NULL;
00075     }
00076     if (pool != NULL) {
00077         rpmioItem item;
00078         int count = 0;
00079         yarnPossess(pool->have);
00080         while ((item = pool->head) != NULL) {
00081             pool->head = item->pool;    /* XXX pool == next */
00082             if (item->use != NULL)
00083                 item->use = yarnFreeLock(item->use);
00084             item = _free(item);
00085             count++;
00086         }
00087         yarnRelease(pool->have);
00088         pool->have = yarnFreeLock(pool->have);
00089         rpmlog(RPMLOG_DEBUG, D_("pool %s:\treused %d, alloc'd %d, free'd %d items.\n"), pool->name, pool->reused, pool->made, count);
00090 #ifdef  NOTYET
00091 assert(pool->made == count);
00092 #else
00093 if (pool->made != count)
00094 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);
00095 #endif
00096         (void) _free(pool);
00097         VALGRIND_DESTROY_MEMPOOL(pool);
00098     }
00099     return NULL;
00100 }
00101 
00102 /*@-internalglobs@*/
00103 rpmioPool rpmioNewPool(const char * name, size_t size, int limit, int flags,
00104                 char * (*dbg) (void *item),
00105                 void (*init) (void *item),
00106                 void (*fini) (void *item))
00107         /*@*/
00108 {
00109     rpmioPool pool = xcalloc(1, sizeof(*pool));
00110 #if defined(WITH_VALGRIND)
00111     static int rzB = 0;         /* size of red-zones (if any) */
00112     static int is_zeroed = 0;   /* does pool return zero'd allocations? */
00113     rzB = rzB;                  /* XXX CentOS5 valgrind doesn't use. */
00114     is_zeroed = is_zeroed;      /* XXX CentOS5 valgrind doesn't use. */
00115 #endif
00116     VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed);
00117     pool->have = yarnNewLock(0);
00118     pool->pool = NULL;
00119     pool->head = NULL;
00120     pool->tail = &pool->head;
00121     pool->size = size;
00122     pool->limit = limit;
00123     pool->flags = flags;
00124     pool->dbg = (void *) dbg;
00125     pool->init = init;
00126     pool->fini = fini;
00127     pool->reused = 0;
00128     pool->made = 0;
00129     pool->name = name;
00130     pool->zlog = NULL;
00131     rpmlog(RPMLOG_DEBUG, D_("pool %s:\tcreated size %u limit %d flags %d\n"), pool->name, (unsigned)pool->size, pool->limit, pool->flags);
00132     return pool;
00133 }
00134 /*@=internalglobs@*/
00135 
00136 /*@-internalglobs@*/
00137 rpmioItem rpmioUnlinkPoolItem(rpmioItem item, const char * msg,
00138                 const char * fn, unsigned ln)
00139 {
00140     rpmioPool pool;
00141     if (item == NULL) return NULL;
00142     yarnPossess(item->use);
00143     if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
00144         const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
00145 /*@-modfilesys@*/
00146         fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
00147                         item, yarnPeekLock(item->use), msg, fn, ln, imsg);
00148 /*@=modfilesys@*/
00149     }
00150     yarnTwist(item->use, BY, -1);
00151 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
00152     return item;
00153 /*@=retalias@*/
00154 }
00155 /*@=internalglobs@*/
00156 
00157 /*@-internalglobs@*/
00158 rpmioItem rpmioLinkPoolItem(rpmioItem item, const char * msg,
00159                 const char * fn, unsigned ln)
00160 {
00161     rpmioPool pool;
00162     if (item == NULL) return NULL;
00163     yarnPossess(item->use);
00164     if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
00165         const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
00166 /*@-modfilesys@*/
00167         fprintf(stderr, "--> %s %p ++ %ld %s at %s:%u%s\n", pool->name,
00168                         item, yarnPeekLock(item->use)+1, msg, fn, ln, imsg);
00169 /*@=modfilesys@*/
00170     }
00171     yarnTwist(item->use, BY, 1);
00172     return item;
00173 }
00174 /*@=internalglobs@*/
00175 
00176 /*@-internalglobs@*/
00177 /*@null@*/
00178 void * rpmioFreePoolItem(/*@killref@*/ /*@null@*/ rpmioItem item,
00179                 const char * msg, const char * fn, unsigned ln)
00180         /*@modifies item @*/
00181 {
00182     rpmioPool pool;
00183     if (item == NULL) return NULL;
00184 
00185 #ifdef  NOTYET
00186 assert(item->pool != NULL);     /* XXX (*pool->fini) is likely necessary */
00187 #endif
00188     yarnPossess(item->use);
00189     if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
00190         const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
00191 /*@-modfilesys@*/
00192         fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
00193                         item, yarnPeekLock(item->use), msg, fn, ln, imsg);
00194 /*@=modfilesys@*/
00195     }
00196     if (yarnPeekLock(item->use) <= 1L) {
00197         if (pool != NULL && pool->fini != NULL)
00198             (*pool->fini) ((void *)item);
00199         VALGRIND_MEMPOOL_FREE(pool, item + 1);
00200         item = rpmioPutPool(item);
00201     } else
00202         yarnTwist(item->use, BY, -1);
00203 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
00204     return (void *) item;
00205 /*@=retalias@*/
00206 }
00207 /*@=internalglobs@*/
00208 
00209 /*@-internalglobs@*/
00210 rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
00211 {
00212     rpmioItem item;
00213 
00214     if (pool != NULL) {
00215         /* if can't create any more, wait for a space to show up */
00216         yarnPossess(pool->have);
00217         if (pool->limit == 0)
00218             yarnWaitFor(pool->have, NOT_TO_BE, 0);
00219 
00220         /* if a space is available, pull it from the list and return it */
00221         if (pool->head != NULL) {
00222             item = pool->head;
00223             pool->head = item->pool;    /* XXX pool == next */
00224             if (pool->head == NULL)
00225                 pool->tail = &pool->head;
00226             pool->reused++;
00227             item->pool = pool;          /* remember the pool this belongs to */
00228             yarnTwist(pool->have, BY, -1);      /* one less in pool */
00229             VALGRIND_MEMPOOL_ALLOC(pool,
00230                 item + 1,
00231                 size - sizeof(struct rpmioItem_s));
00232             return item;
00233         }
00234 
00235         /* nothing available, don't want to wait, make a new item */
00236 assert(pool->limit != 0);
00237         if (pool->limit > 0)
00238             pool->limit--;
00239         pool->made++;
00240         yarnRelease(pool->have);
00241     }
00242 
00243     item = xcalloc(1, size);
00244     item->use = yarnNewLock(0);         /* XXX newref? */
00245     item->pool = pool;
00246     VALGRIND_MEMPOOL_ALLOC(pool,
00247         item + 1,
00248         size - sizeof(struct rpmioItem_s));
00249     return item;
00250 }
00251 /*@=internalglobs@*/
00252 
00253 /*@-internalglobs@*/
00254 rpmioItem rpmioPutPool(rpmioItem item)
00255 {
00256     rpmioPool pool;
00257 
00258     if ((pool = item->pool) != NULL) {
00259         yarnPossess(pool->have);
00260         item->pool = NULL;              /* XXX pool == next */
00261         *pool->tail = item;
00262         pool->tail = (void *)&item->pool;/* XXX pool == next */
00263         yarnTwist(pool->have, BY, 1);
00264         if (item->use != NULL)
00265             yarnTwist(item->use, TO, 0);
00266         return NULL;
00267     }
00268 
00269     if (item->use != NULL) {
00270         yarnTwist(item->use, TO, 0);
00271         item->use = yarnFreeLock(item->use);
00272     }
00273     (void) _free(item);
00274     return NULL;
00275 }
00276 /*@=internalglobs@*/
00277 
00278 #if !(HAVE_MCHECK_H && defined(__GNUC__)) && !defined(__LCLINT__)
00279 
00280 /*@out@*/ /*@only@*/ void * xmalloc (size_t size)
00281 {
00282     register void *value;
00283     if (size == 0) size++;
00284     value = malloc (size);
00285     if (value == 0)
00286         value = vmefail(size);
00287     return value;
00288 }
00289 
00290 /*@only@*/ void * xcalloc (size_t nmemb, size_t size)
00291 {
00292     register void *value;
00293     if (size == 0) size++;
00294     if (nmemb == 0) nmemb++;
00295     value = calloc (nmemb, size);
00296     if (value == 0)
00297         value = vmefail(size);
00298     return value;
00299 }
00300 
00301 /*@only@*/ void * xrealloc (/*@only@*/ void *ptr, size_t size)
00302 {
00303     register void *value;
00304     if (size == 0) size++;
00305     value = realloc (ptr, size);
00306     if (value == 0)
00307         value = vmefail(size);
00308     return value;
00309 }
00310 
00311 /*@only@*/ char * xstrdup (const char *str)
00312 {
00313     size_t size = strlen(str) + 1;
00314     char *newstr = (char *) malloc (size);
00315     if (newstr == 0)
00316         newstr = (char *) vmefail(size);
00317     strcpy (newstr, str);
00318     return newstr;
00319 }
00320 
00321 #endif  /* !(HAVE_MCHECK_H && defined(__GNUC__)) */