Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

os_alloc.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1997-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: os_alloc.c,v 12.2 2005/06/16 20:23:23 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #endif
00018 
00019 #include "db_int.h"
00020 
00021 #ifdef DIAGNOSTIC
00022 static void __os_guard __P((DB_ENV *));
00023 
00024 union __db_allocinfo {
00025         size_t size;
00026         double align;
00027 };
00028 #endif
00029 
00030 /*
00031  * !!!
00032  * Correct for systems that return NULL when you allocate 0 bytes of memory.
00033  * There are several places in DB where we allocate the number of bytes held
00034  * by the key/data item, and it can be 0.  Correct here so that malloc never
00035  * returns a NULL for that reason (which behavior is permitted by ANSI).  We
00036  * could make these calls macros on non-Alpha architectures (that's where we
00037  * saw the problem), but it's probably not worth the autoconf complexity.
00038  *
00039  * !!!
00040  * Correct for systems that don't set errno when malloc and friends fail.
00041  *
00042  *      Out of memory.
00043  *      We wish to hold the whole sky,
00044  *      But we never will.
00045  */
00046 
00047 /*
00048  * __os_umalloc --
00049  *      A malloc(3) function that will use, in order of preference,
00050  *      the allocation function specified to the DB handle, the DB_ENV
00051  *      handle, or __os_malloc.
00052  *
00053  * PUBLIC: int __os_umalloc __P((DB_ENV *, size_t, void *));
00054  */
00055 int
00056 __os_umalloc(dbenv, size, storep)
00057         DB_ENV *dbenv;
00058         size_t size;
00059         void *storep;
00060 {
00061         int ret;
00062 
00063         /* Never allocate 0 bytes -- some C libraries don't like it. */
00064         if (size == 0)
00065                 ++size;
00066 
00067         if (dbenv == NULL || dbenv->db_malloc == NULL) {
00068                 if (DB_GLOBAL(j_malloc) != NULL)
00069                         *(void **)storep = DB_GLOBAL(j_malloc)(size);
00070                 else
00071                         *(void **)storep = malloc(size);
00072                 if (*(void **)storep == NULL) {
00073                         /*
00074                          *  Correct error return, see __os_malloc.
00075                          */
00076                         if ((ret = __os_get_errno_ret_zero()) == 0) {
00077                                 ret = ENOMEM;
00078                                 __os_set_errno(ENOMEM);
00079                         }
00080                         __db_err(dbenv,
00081                             "malloc: %s: %lu", strerror(ret), (u_long)size);
00082                         return (ret);
00083                 }
00084                 return (0);
00085         }
00086 
00087         if ((*(void **)storep = dbenv->db_malloc(size)) == NULL) {
00088                 __db_err(dbenv, "User-specified malloc function returned NULL");
00089                 return (ENOMEM);
00090         }
00091 
00092         return (0);
00093 }
00094 
00095 /*
00096  * __os_urealloc --
00097  *      realloc(3) counterpart to __os_umalloc.
00098  *
00099  * PUBLIC: int __os_urealloc __P((DB_ENV *, size_t, void *));
00100  */
00101 int
00102 __os_urealloc(dbenv, size, storep)
00103         DB_ENV *dbenv;
00104         size_t size;
00105         void *storep;
00106 {
00107         int ret;
00108         void *ptr;
00109 
00110         ptr = *(void **)storep;
00111 
00112         /* Never allocate 0 bytes -- some C libraries don't like it. */
00113         if (size == 0)
00114                 ++size;
00115 
00116         if (dbenv == NULL || dbenv->db_realloc == NULL) {
00117                 if (ptr == NULL)
00118                         return (__os_umalloc(dbenv, size, storep));
00119 
00120                 if (DB_GLOBAL(j_realloc) != NULL)
00121                         *(void **)storep = DB_GLOBAL(j_realloc)(ptr, size);
00122                 else
00123                         *(void **)storep = realloc(ptr, size);
00124                 if (*(void **)storep == NULL) {
00125                         /*
00126                          * Correct errno, see __os_realloc.
00127                          */
00128                         if ((ret = __os_get_errno_ret_zero()) == 0) {
00129                                 ret = ENOMEM;
00130                                 __os_set_errno(ENOMEM);
00131                         }
00132                         __db_err(dbenv,
00133                             "realloc: %s: %lu", strerror(ret), (u_long)size);
00134                         return (ret);
00135                 }
00136                 return (0);
00137         }
00138 
00139         if ((*(void **)storep = dbenv->db_realloc(ptr, size)) == NULL) {
00140                 __db_err(dbenv,
00141                     "User-specified realloc function returned NULL");
00142                 return (ENOMEM);
00143         }
00144 
00145         return (0);
00146 }
00147 
00148 /*
00149  * __os_ufree --
00150  *      free(3) counterpart to __os_umalloc.
00151  *
00152  * PUBLIC: void __os_ufree __P((DB_ENV *, void *));
00153  */
00154 void
00155 __os_ufree(dbenv, ptr)
00156         DB_ENV *dbenv;
00157         void *ptr;
00158 {
00159         if (dbenv != NULL && dbenv->db_free != NULL)
00160                 dbenv->db_free(ptr);
00161         else if (DB_GLOBAL(j_free) != NULL)
00162                 DB_GLOBAL(j_free)(ptr);
00163         else
00164                 free(ptr);
00165 }
00166 
00167 /*
00168  * __os_strdup --
00169  *      The strdup(3) function for DB.
00170  *
00171  * PUBLIC: int __os_strdup __P((DB_ENV *, const char *, void *));
00172  */
00173 int
00174 __os_strdup(dbenv, str, storep)
00175         DB_ENV *dbenv;
00176         const char *str;
00177         void *storep;
00178 {
00179         size_t size;
00180         int ret;
00181         void *p;
00182 
00183         *(void **)storep = NULL;
00184 
00185         size = strlen(str) + 1;
00186         if ((ret = __os_malloc(dbenv, size, &p)) != 0)
00187                 return (ret);
00188 
00189         memcpy(p, str, size);
00190 
00191         *(void **)storep = p;
00192         return (0);
00193 }
00194 
00195 /*
00196  * __os_calloc --
00197  *      The calloc(3) function for DB.
00198  *
00199  * PUBLIC: int __os_calloc __P((DB_ENV *, size_t, size_t, void *));
00200  */
00201 int
00202 __os_calloc(dbenv, num, size, storep)
00203         DB_ENV *dbenv;
00204         size_t num, size;
00205         void *storep;
00206 {
00207         void *p;
00208         int ret;
00209 
00210         size *= num;
00211         if ((ret = __os_malloc(dbenv, size, &p)) != 0)
00212                 return (ret);
00213 
00214         memset(p, 0, size);
00215 
00216         *(void **)storep = p;
00217         return (0);
00218 }
00219 
00220 /*
00221  * __os_malloc --
00222  *      The malloc(3) function for DB.
00223  *
00224  * PUBLIC: int __os_malloc __P((DB_ENV *, size_t, void *));
00225  */
00226 int
00227 __os_malloc(dbenv, size, storep)
00228         DB_ENV *dbenv;
00229         size_t size;
00230         void *storep;
00231 {
00232         int ret;
00233         void *p;
00234 
00235         *(void **)storep = NULL;
00236 
00237         /* Never allocate 0 bytes -- some C libraries don't like it. */
00238         if (size == 0)
00239                 ++size;
00240 
00241 #ifdef DIAGNOSTIC
00242         /* Add room for size and a guard byte. */
00243         size += sizeof(union __db_allocinfo) + 1;
00244 #endif
00245 
00246         if (DB_GLOBAL(j_malloc) != NULL)
00247                 p = DB_GLOBAL(j_malloc)(size);
00248         else
00249                 p = malloc(size);
00250         if (p == NULL) {
00251                 /*
00252                  * Some C libraries don't correctly set errno when malloc(3)
00253                  * fails.  We'd like to 0 out errno before calling malloc,
00254                  * but it turns out that setting errno is quite expensive on
00255                  * Windows/NT in an MT environment.
00256                  */
00257                 if ((ret = __os_get_errno_ret_zero()) == 0) {
00258                         ret = ENOMEM;
00259                         __os_set_errno(ENOMEM);
00260                 }
00261                 __db_err(dbenv,
00262                     "malloc: %s: %lu", strerror(ret), (u_long)size);
00263                 return (ret);
00264         }
00265 
00266 #ifdef DIAGNOSTIC
00267         /* Overwrite memory. */
00268         memset(p, CLEAR_BYTE, size);
00269 
00270         /*
00271          * Guard bytes: if #DIAGNOSTIC is defined, we allocate an additional
00272          * byte after the memory and set it to a special value that we check
00273          * for when the memory is free'd.
00274          */
00275         ((u_int8_t *)p)[size - 1] = CLEAR_BYTE;
00276 
00277         ((union __db_allocinfo *)p)->size = size;
00278         p = &((union __db_allocinfo *)p)[1];
00279 #endif
00280         *(void **)storep = p;
00281 
00282         return (0);
00283 }
00284 
00285 /*
00286  * __os_realloc --
00287  *      The realloc(3) function for DB.
00288  *
00289  * PUBLIC: int __os_realloc __P((DB_ENV *, size_t, void *));
00290  */
00291 int
00292 __os_realloc(dbenv, size, storep)
00293         DB_ENV *dbenv;
00294         size_t size;
00295         void *storep;
00296 {
00297         int ret;
00298         void *p, *ptr;
00299 
00300         ptr = *(void **)storep;
00301 
00302         /* Never allocate 0 bytes -- some C libraries don't like it. */
00303         if (size == 0)
00304                 ++size;
00305 
00306         /* If we haven't yet allocated anything yet, simply call malloc. */
00307         if (ptr == NULL)
00308                 return (__os_malloc(dbenv, size, storep));
00309 
00310 #ifdef DIAGNOSTIC
00311         /* Add room for size and a guard byte. */
00312         size += sizeof(union __db_allocinfo) + 1;
00313 
00314         /* Back up to the real beginning */
00315         ptr = &((union __db_allocinfo *)ptr)[-1];
00316 
00317         {
00318                 size_t s;
00319 
00320                 s = ((union __db_allocinfo *)ptr)->size;
00321                 if (((u_int8_t *)ptr)[s - 1] != CLEAR_BYTE)
00322                          __os_guard(dbenv);
00323         }
00324 #endif
00325 
00326         /*
00327          * Don't overwrite the original pointer, there are places in DB we
00328          * try to continue after realloc fails.
00329          */
00330         if (DB_GLOBAL(j_realloc) != NULL)
00331                 p = DB_GLOBAL(j_realloc)(ptr, size);
00332         else
00333                 p = realloc(ptr, size);
00334         if (p == NULL) {
00335                 /*
00336                  * Some C libraries don't correctly set errno when malloc(3)
00337                  * fails.  We'd like to 0 out errno before calling malloc,
00338                  * but it turns out that setting errno is quite expensive on
00339                  * Windows/NT in an MT environment.
00340                  */
00341                 if ((ret = __os_get_errno_ret_zero()) == 0) {
00342                         ret = ENOMEM;
00343                         __os_set_errno(ENOMEM);
00344                 }
00345                 __db_err(dbenv,
00346                     "realloc: %s: %lu", strerror(ret), (u_long)size);
00347                 return (ret);
00348         }
00349 #ifdef DIAGNOSTIC
00350         ((u_int8_t *)p)[size - 1] = CLEAR_BYTE; /* Initialize guard byte. */
00351 
00352         ((union __db_allocinfo *)p)->size = size;
00353         p = &((union __db_allocinfo *)p)[1];
00354 #endif
00355 
00356         *(void **)storep = p;
00357 
00358         return (0);
00359 }
00360 
00361 /*
00362  * __os_free --
00363  *      The free(3) function for DB.
00364  *
00365  * PUBLIC: void __os_free __P((DB_ENV *, void *));
00366  */
00367 void
00368 __os_free(dbenv, ptr)
00369         DB_ENV *dbenv;
00370         void *ptr;
00371 {
00372 #ifdef DIAGNOSTIC
00373         size_t size;
00374         /*
00375          * Check that the guard byte (one past the end of the memory) is
00376          * still CLEAR_BYTE.
00377          */
00378         if (ptr == NULL)
00379                 return;
00380 
00381         ptr = &((union __db_allocinfo *)ptr)[-1];
00382         size = ((union __db_allocinfo *)ptr)->size;
00383         if (((u_int8_t *)ptr)[size - 1] != CLEAR_BYTE)
00384                  __os_guard(dbenv);
00385 
00386         /* Overwrite memory. */
00387         if (size != 0)
00388                 memset(ptr, CLEAR_BYTE, size);
00389 #endif
00390         COMPQUIET(dbenv, NULL);
00391 
00392         if (DB_GLOBAL(j_free) != NULL)
00393                 DB_GLOBAL(j_free)(ptr);
00394         else
00395                 free(ptr);
00396 }
00397 
00398 #ifdef DIAGNOSTIC
00399 /*
00400  * __os_guard --
00401  *      Complain and abort.
00402  */
00403 static void
00404 __os_guard(dbenv)
00405         DB_ENV *dbenv;
00406 {
00407         __db_err(dbenv, "Guard byte incorrect during free");
00408         abort();
00409         /* NOTREACHED */
00410 }
00411 #endif
00412 
00413 /*
00414  * __ua_memcpy --
00415  *      Copy memory to memory without relying on any kind of alignment.
00416  *
00417  *      There are places in DB that we have unaligned data, for example,
00418  *      when we've stored a structure in a log record as a DBT, and now
00419  *      we want to look at it.  Unfortunately, if you have code like:
00420  *
00421  *              struct a {
00422  *                      int x;
00423  *              } *p;
00424  *
00425  *              void *func_argument;
00426  *              int local;
00427  *
00428  *              p = (struct a *)func_argument;
00429  *              memcpy(&local, p->x, sizeof(local));
00430  *
00431  *      compilers optimize to use inline instructions requiring alignment,
00432  *      and records in the log don't have any particular alignment.  (This
00433  *      isn't a compiler bug, because it's a structure they're allowed to
00434  *      assume alignment.)
00435  *
00436  *      Casting the memcpy arguments to (u_int8_t *) appears to work most
00437  *      of the time, but we've seen examples where it wasn't sufficient
00438  *      and there's nothing in ANSI C that requires that work.
00439  *
00440  * PUBLIC: void *__ua_memcpy __P((void *, const void *, size_t));
00441  */
00442 void *
00443 __ua_memcpy(dst, src, len)
00444         void *dst;
00445         const void *src;
00446         size_t len;
00447 {
00448         return ((void *)memcpy(dst, src, len));
00449 }

Generated on Sun Dec 25 12:14:41 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2