rpm  5.4.4
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 VALGRIND_HG_CLEAN_MEMORY(pool, sizeof(*pool));
00081         while ((item = pool->head) != NULL) {
00082 VALGRIND_HG_CLEAN_MEMORY(item, pool->size);
00083             pool->head = item->pool;    /* XXX pool == next */
00084             if (item->use != NULL)
00085                 item->use = yarnFreeLock(item->use);
00086             item = _free(item);
00087             count++;
00088         }
00089         yarnRelease(pool->have);
00090         pool->have = yarnFreeLock(pool->have);
00091         rpmlog(RPMLOG_DEBUG, D_("pool %s:\treused %d, alloc'd %d, free'd %d items.\n"), pool->name, pool->reused, pool->made, count);
00092 #ifdef  NOTYET
00093 assert(pool->made == count);
00094 #else
00095 if (pool->made != count)
00096 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);
00097 #endif
00098         (void) _free(pool);
00099         VALGRIND_DESTROY_MEMPOOL(pool);
00100     }
00101     return NULL;
00102 }
00103 
00104 /*@-internalglobs@*/
00105 rpmioPool rpmioNewPool(const char * name, size_t size, int limit, int flags,
00106                 char * (*dbg) (void *item),
00107                 void (*init) (void *item),
00108                 void (*fini) (void *item))
00109         /*@*/
00110 {
00111     rpmioPool pool = xcalloc(1, sizeof(*pool));
00112 #if defined(WITH_VALGRIND)
00113     static int rzB = 0;         /* size of red-zones (if any) */
00114     static int is_zeroed = 0;   /* does pool return zero'd allocations? */
00115     rzB = rzB;                  /* XXX CentOS5 valgrind doesn't use. */
00116     is_zeroed = is_zeroed;      /* XXX CentOS5 valgrind doesn't use. */
00117 #endif
00118     VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed);
00119     pool->have = yarnNewLock(0);
00120     pool->pool = NULL;
00121     pool->head = NULL;
00122     pool->tail = &pool->head;
00123     pool->size = size;
00124     pool->limit = limit;
00125     pool->flags = flags;
00126     pool->dbg = (void *) dbg;
00127     pool->init = init;
00128     pool->fini = fini;
00129     pool->reused = 0;
00130     pool->made = 0;
00131     pool->name = name;
00132     pool->zlog = NULL;
00133     rpmlog(RPMLOG_DEBUG, D_("pool %s:\tcreated size %u limit %d flags %d\n"), pool->name, (unsigned)pool->size, pool->limit, pool->flags);
00134     return pool;
00135 }
00136 /*@=internalglobs@*/
00137 
00138 /*@-internalglobs@*/
00139 rpmioItem rpmioUnlinkPoolItem(rpmioItem item, const char * msg,
00140                 const char * fn, unsigned ln)
00141 {
00142     rpmioPool pool;
00143     if (item == NULL) return NULL;
00144     yarnPossess(item->use);
00145 ANNOTATE_HAPPENS_AFTER(item);
00146     if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
00147         const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
00148 /*@-modfilesys@*/
00149         fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
00150                         item, yarnPeekLock(item->use), msg, fn, ln, imsg);
00151 /*@=modfilesys@*/
00152     }
00153     yarnTwist(item->use, BY, -1);
00154 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
00155     return item;
00156 /*@=retalias@*/
00157 }
00158 /*@=internalglobs@*/
00159 
00160 /*@-internalglobs@*/
00161 rpmioItem rpmioLinkPoolItem(rpmioItem item, const char * msg,
00162                 const char * fn, unsigned ln)
00163 {
00164     rpmioPool pool;
00165     if (item == NULL) return NULL;
00166     yarnPossess(item->use);
00167     if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
00168         const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
00169 /*@-modfilesys@*/
00170         fprintf(stderr, "--> %s %p ++ %ld %s at %s:%u%s\n", pool->name,
00171                         item, yarnPeekLock(item->use)+1, msg, fn, ln, imsg);
00172 /*@=modfilesys@*/
00173     }
00174 ANNOTATE_HAPPENS_BEFORE(item);
00175     yarnTwist(item->use, BY, 1);
00176     return item;
00177 }
00178 /*@=internalglobs@*/
00179 
00180 /*@-internalglobs@*/
00181 /*@null@*/
00182 void * rpmioFreePoolItem(/*@killref@*/ /*@null@*/ rpmioItem item,
00183                 const char * msg, const char * fn, unsigned ln)
00184         /*@modifies item @*/
00185 {
00186     rpmioPool pool;
00187     if (item == NULL) return NULL;
00188 
00189 #ifdef  NOTYET
00190 assert(item->pool != NULL);     /* XXX (*pool->fini) is likely necessary */
00191 #endif
00192     yarnPossess(item->use);
00193 ANNOTATE_HAPPENS_AFTER(item);
00194     if ((pool = item->pool) != NULL && pool->flags && msg != NULL) {
00195         const char * imsg = (pool->dbg ? (*pool->dbg)((void *)item) : "");
00196 /*@-modfilesys@*/
00197         fprintf(stderr, "--> %s %p -- %ld %s at %s:%u%s\n", pool->name,
00198                         item, yarnPeekLock(item->use), msg, fn, ln, imsg);
00199 /*@=modfilesys@*/
00200     }
00201     if (yarnPeekLock(item->use) <= 1L) {
00202 VALGRIND_HG_CLEAN_MEMORY(item, pool->size);
00203         if (pool != NULL && pool->fini != NULL)
00204             (*pool->fini) ((void *)item);
00205         VALGRIND_MEMPOOL_FREE(pool, item + 1);
00206         item = rpmioPutPool(item);
00207     } else
00208         yarnTwist(item->use, BY, -1);
00209 /*@-retalias@*/ /* XXX returning the deref'd item is used to detect nrefs = 0 */
00210     return (void *) item;
00211 /*@=retalias@*/
00212 }
00213 /*@=internalglobs@*/
00214 
00215 /*@-internalglobs@*/
00216 rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
00217 {
00218     rpmioItem item;
00219 
00220     if (pool != NULL) {
00221         /* if can't create any more, wait for a space to show up */
00222         yarnPossess(pool->have);
00223         if (pool->limit == 0)
00224             yarnWaitFor(pool->have, NOT_TO_BE, 0);
00225 
00226         /* if a space is available, pull it from the list and return it */
00227         if (pool->head != NULL) {
00228             item = pool->head;
00229             pool->head = item->pool;    /* XXX pool == next */
00230             if (pool->head == NULL)
00231                 pool->tail = &pool->head;
00232             pool->reused++;
00233             item->pool = pool;          /* remember the pool this belongs to */
00234             yarnTwist(pool->have, BY, -1);      /* one less in pool */
00235             VALGRIND_MEMPOOL_ALLOC(pool,
00236                 item + 1,
00237                 size - sizeof(struct rpmioItem_s));
00238             return item;
00239         }
00240 
00241         /* nothing available, don't want to wait, make a new item */
00242 assert(pool->limit != 0);
00243         if (pool->limit > 0)
00244             pool->limit--;
00245         pool->made++;
00246         yarnRelease(pool->have);
00247     }
00248 
00249     item = xcalloc(1, size);
00250     item->use = yarnNewLock(0);         /* XXX newref? */
00251     item->pool = pool;
00252     VALGRIND_MEMPOOL_ALLOC(pool,
00253         item + 1,
00254         size - sizeof(struct rpmioItem_s));
00255     return item;
00256 }
00257 /*@=internalglobs@*/
00258 
00259 /*@-internalglobs@*/
00260 rpmioItem rpmioPutPool(rpmioItem item)
00261 {
00262     rpmioPool pool;
00263 
00264     if ((pool = item->pool) != NULL) {
00265         yarnPossess(pool->have);
00266         item->pool = NULL;              /* XXX pool == next */
00267         *pool->tail = item;
00268         pool->tail = (void *)&item->pool;/* XXX pool == next */
00269         yarnTwist(pool->have, BY, 1);
00270         if (item->use != NULL)
00271             yarnTwist(item->use, TO, 0);
00272         return NULL;
00273     }
00274 
00275     if (item->use != NULL) {
00276         yarnTwist(item->use, TO, 0);
00277         item->use = yarnFreeLock(item->use);
00278     }
00279     (void) _free(item);
00280     return NULL;
00281 }
00282 /*@=internalglobs@*/
00283 
00284 #if !(HAVE_MCHECK_H && defined(__GNUC__)) && !defined(__LCLINT__)
00285 
00286 /*@out@*/ /*@only@*/ void * xmalloc (size_t size)
00287 {
00288     register void *value;
00289     if (size == 0) size++;
00290     value = malloc (size);
00291     if (value == 0)
00292         value = vmefail(size);
00293     return value;
00294 }
00295 
00296 /*@only@*/ void * xcalloc (size_t nmemb, size_t size)
00297 {
00298     register void *value;
00299     if (size == 0) size++;
00300     if (nmemb == 0) nmemb++;
00301     value = calloc (nmemb, size);
00302     if (value == 0)
00303         value = vmefail(size);
00304     return value;
00305 }
00306 
00307 /*@only@*/ void * xrealloc (/*@only@*/ void *ptr, size_t size)
00308 {
00309     register void *value;
00310     if (size == 0) size++;
00311     value = realloc (ptr, size);
00312     if (value == 0)
00313         value = vmefail(size);
00314     return value;
00315 }
00316 
00317 /*@only@*/ char * xstrdup (const char *str)
00318 {
00319     size_t size = strlen(str) + 1;
00320     char *newstr = (char *) malloc (size);
00321     if (newstr == 0)
00322         newstr = (char *) vmefail(size);
00323     strcpy (newstr, str);
00324     return newstr;
00325 }
00326 
00327 #endif  /* !(HAVE_MCHECK_H && defined(__GNUC__)) */