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