00001
00002
00003
00004
00005
00016 #if HAVE_CONFIG_H
00017 #include <config.h>
00018 #endif
00019
00020 #include <assert.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <stddef.h>
00025 #include <yaz/xmalloc.h>
00026 #include <yaz/nmem.h>
00027 #include <yaz/log.h>
00028
00029 #ifdef WIN32
00030 #include <windows.h>
00031 #endif
00032
00033 #define NMEM_CHUNK (4*1024)
00034
00035 struct nmem_block
00036 {
00037 char *buf;
00038 size_t size;
00039 size_t top;
00040 struct nmem_block *next;
00041 };
00042
00043 struct nmem_control
00044 {
00045 int total;
00046 struct nmem_block *blocks;
00047 struct nmem_control *next;
00048 };
00049
00050 struct align {
00051 char x;
00052 union {
00053 char c;
00054 short s;
00055 int i;
00056 long l;
00057 #if HAVE_LONG_LONG
00058 long long ll;
00059 #endif
00060 float f;
00061 double d;
00062 } u;
00063 };
00064
00065 #define NMEM_ALIGN (offsetof(struct align, u))
00066
00067 static int log_level = 0;
00068 static int log_level_initialized = 0;
00069
00070 static void free_block(struct nmem_block *p)
00071 {
00072 xfree(p->buf);
00073 xfree(p);
00074 if (log_level)
00075 yaz_log (log_level, "nmem free_block p=%p", p);
00076 }
00077
00078
00079
00080
00081 static struct nmem_block *get_block(size_t size)
00082 {
00083 struct nmem_block *r;
00084 size_t get = NMEM_CHUNK;
00085
00086 if (log_level)
00087 yaz_log (log_level, "nmem get_block size=%ld", (long) size);
00088
00089
00090 if (get < size)
00091 get = size;
00092 if(log_level)
00093 yaz_log (log_level, "nmem get_block alloc new block size=%ld",
00094 (long) get);
00095
00096 r = (struct nmem_block *) xmalloc(sizeof(*r));
00097 r->buf = (char *)xmalloc(r->size = get);
00098 r->top = 0;
00099 return r;
00100 }
00101
00102 void nmem_reset(NMEM n)
00103 {
00104 struct nmem_block *t;
00105
00106 yaz_log (log_level, "nmem_reset p=%p", n);
00107 if (!n)
00108 return;
00109 while (n->blocks)
00110 {
00111 t = n->blocks;
00112 n->blocks = n->blocks->next;
00113 free_block(t);
00114 }
00115 n->total = 0;
00116 }
00117
00118 void *nmem_malloc(NMEM n, int size)
00119 {
00120 struct nmem_block *p;
00121 char *r;
00122
00123 if (!n)
00124 {
00125 yaz_log (YLOG_FATAL, "calling nmem_malloc with an null pointer");
00126 abort ();
00127 }
00128 p = n->blocks;
00129 if (!p || p->size < size + p->top)
00130 {
00131 p = get_block(size);
00132 p->next = n->blocks;
00133 n->blocks = p;
00134 }
00135 r = p->buf + p->top;
00136
00137 p->top += (size + (NMEM_ALIGN - 1)) & ~(NMEM_ALIGN - 1);
00138 n->total += size;
00139 return r;
00140 }
00141
00142 int nmem_total(NMEM n)
00143 {
00144 return n->total;
00145 }
00146
00147 NMEM nmem_create(void)
00148 {
00149 NMEM r;
00150 if (!log_level_initialized)
00151 {
00152 log_level = yaz_log_module_level("nmem");
00153 log_level_initialized = 1;
00154 }
00155
00156 r = (struct nmem_control *)xmalloc(sizeof(*r));
00157
00158 r->blocks = 0;
00159 r->total = 0;
00160 r->next = 0;
00161
00162 return r;
00163 }
00164
00165 void nmem_destroy(NMEM n)
00166 {
00167 if (!n)
00168 return;
00169
00170 nmem_reset(n);
00171 xfree(n);
00172 }
00173
00174 void nmem_transfer (NMEM dst, NMEM src)
00175 {
00176 struct nmem_block *t;
00177 while ((t = src->blocks))
00178 {
00179 src->blocks = t->next;
00180 t->next = dst->blocks;
00181 dst->blocks = t;
00182 }
00183 dst->total += src->total;
00184 src->total = 0;
00185 }
00186
00187 int yaz_errno(void)
00188 {
00189 return errno;
00190 }
00191
00192 void yaz_set_errno(int v)
00193 {
00194 errno = v;
00195 }
00196
00197 void yaz_strerror(char *buf, int max)
00198 {
00199 #ifdef WIN32
00200 DWORD err;
00201 #endif
00202 char *cp;
00203 if (!log_level_initialized)
00204 {
00205 log_level = yaz_log_module_level("nmem");
00206 log_level_initialized = 1;
00207 }
00208
00209 #ifdef WIN32
00210 err = GetLastError();
00211 if (err)
00212 {
00213 FormatMessage(
00214 FORMAT_MESSAGE_FROM_SYSTEM,
00215 NULL,
00216 err,
00217 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00218 (LPTSTR) buf,
00219 max-1,
00220 NULL);
00221 }
00222 else
00223 *buf = '\0';
00224 #else
00225
00226 #if HAVE_STRERROR_R
00227 *buf = '\0';
00228 strerror_r(errno, buf, max);
00229
00230 if (*buf == '\0')
00231 strcpy(buf, strerror(yaz_errno()));
00232 #else
00233 strcpy(buf, strerror(yaz_errno()));
00234 #endif
00235
00236 #endif
00237 if ((cp = strrchr(buf, '\n')))
00238 *cp = '\0';
00239 if ((cp = strrchr(buf, '\r')))
00240 *cp = '\0';
00241 }
00242
00243
00244
00245
00246
00247
00248
00249