00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <eyedbconfig.h>
00025
00026 #include <sys/types.h>
00027 #include <sys/time.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <errno.h>
00031 #include <unistd.h>
00032 #include <pthread.h>
00033 #include <sys/mman.h>
00034 #include <stdarg.h>
00035
00036 #include <eyedblib/m_mem.h>
00037 #include <eyedblib/log.h>
00038 #include <eyedblib/iassert.h>
00039 #include <lib/m_mem_p.h>
00040
00041 struct m_Map {
00042 caddr_t *p;
00043 caddr_t addr;
00044 size_t size;
00045 int prot, flags, fildes;
00046 off_t off;
00047 u_int ref;
00048 char locked;
00049 void (*gtrig)(void *client_data);
00050 void *client_data;
00051 char *file;
00052 int startns, endns;
00053 m_Map *prev, *next;
00054 };
00055
00056 static pthread_mutex_t m_mp;
00057 static int init_done;
00058 static m_Map *m_head;
00059 static size_t m_tmsize, m_maxsize;
00060
00061 static const u_int ONE_K = 1024;
00062 static const size_t m_min_maxsize = ONE_K * ONE_K * ONE_K;
00063 static u_int m_ref = 0x100;
00064
00065 static int m_getunlocked()
00066 {
00067 int cnt = 0;
00068 m_Map *m;
00069
00070 m = m_head;
00071
00072 while (m) {
00073 if (!m->locked)
00074 cnt++;
00075 m = m->next;
00076 }
00077
00078 return cnt;
00079 }
00080
00081
00082
00083 static int m_garbage(m_Map *rm)
00084 {
00085 m_Map *km = rm;
00086
00087 pthread_mutex_lock(&m_mp);
00088
00089 if (!rm) {
00090 u_int ref = 0xffffffff;
00091 m_Map *m;
00092 m = m_head;
00093
00094 while(m) {
00095 if (m->ref < ref && !m->locked) {
00096 ref = m->ref;
00097 rm = m;
00098 }
00099 m = m->next;
00100 }
00101
00102 }
00103
00104 if (rm) {
00105 m_tmsize -= rm->size;
00106
00107 if (rm->prev)
00108 rm->prev->next = rm->next;
00109 if (rm->next)
00110 rm->next->prev = rm->prev;
00111
00112 if (rm == m_head)
00113 m_head = rm->next;
00114
00115 pthread_mutex_unlock(&m_mp);
00116
00117 if (!km && rm->gtrig)
00118 rm->gtrig(rm->client_data);
00119
00120 IDB_LOG(IDB_LOG_MMAP_DETAIL,
00121 ("m_garbage: unmapping %p for size %u\n", *rm->p, rm->size));
00122
00123 if (munmap(*rm->p, rm->size)) {
00124 utlog("munmap(%p, %d)\n", *rm->p, rm->size);
00125
00126 abort();
00127 }
00128
00129 *rm->p = 0;
00130
00131
00132 free(rm->file);
00133 free(rm);
00134
00135
00136
00137
00138
00139
00140
00141
00142 return 0;
00143 }
00144
00145 pthread_mutex_unlock(&m_mp);
00146 IDB_LOG(IDB_LOG_MMAP_DETAIL, ("m_garbage failed!\n"));
00147
00148 return 1;
00149 }
00150
00151 static void m_insert(m_Map *m)
00152 {
00153 pthread_mutex_lock(&m_mp);
00154
00155 m->next = m_head;
00156 m->prev = 0;
00157
00158 if (m_head)
00159 m_head->prev = m;
00160
00161 m->ref = ++m_ref;
00162 m_head = m;
00163
00164 m_tmsize += m->size;
00165
00166 pthread_mutex_unlock(&m_mp);
00167 }
00168
00169
00170
00171
00172
00173
00174
00175 #ifdef USE_MADVISE
00176 static int must_madvise;
00177 #endif
00178
00179 void m_init(void)
00180 {
00181 pthread_mutexattr_t mattr;
00182
00183 if (init_done)
00184 return;
00185
00186 pthread_mutexattr_init(&mattr);
00187
00188 #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
00189 pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE);
00190 #endif
00191
00192 pthread_mutex_init(&m_mp, &mattr);
00193
00194 #ifdef USE_MADVISE
00195 must_madvise = getenv("EYEDB_MADVISE") ? 1 : 0;
00196 #endif
00197
00198 init_done = 1;
00199 }
00200
00201 static void reduce_memory(size_t size)
00202 {
00203 if (!m_maxsize)
00204 return;
00205
00206 bool must_reduced = false;
00207 while (size + m_tmsize > m_maxsize) {
00208 must_reduced = true;
00209 IDB_LOG(IDB_LOG_MMAP_DETAIL,
00210 ("must reduced total size: %llu\n", m_tmsize));
00211 if (m_garbage(0))
00212 break;
00213 }
00214 if (must_reduced)
00215 IDB_LOG(IDB_LOG_MMAP_DETAIL, ("reduced: %llu\n", m_tmsize));
00216 }
00217
00218 void m_gtrig_set(m_Map *m, void (*gtrig)(void *client_data), void *client_data)
00219 {
00220 m->gtrig = gtrig;
00221 m->client_data = client_data;
00222 }
00223
00224 m_Map *m_mmap(caddr_t addr, size_t size, int prot, int flags,
00225 int fildes, off_t off, caddr_t *p, const char *file,
00226 off_t startns, off_t endns)
00227 {
00228 if (!init_done)
00229 m_init();
00230
00231 IDB_LOG(IDB_LOG_MMAP_DETAIL,
00232 ("mapping attempt file=\"%s\" size=%lu prot=%p "
00233 "flags=%p fd=%d offset=%u",
00234 file, size, prot, flags, fildes, off));
00235
00236 errno = 0;
00237
00238 if (endns > 0)
00239 IDB_LOG_X(IDB_LOG_MMAP_DETAIL, (" startns=%d endns=%d\n", startns, endns));
00240 else
00241 IDB_LOG_X(IDB_LOG_MMAP_DETAIL, ("\n"));
00242
00243 reduce_memory(size);
00244
00245
00246 #if 0
00247
00248 while (!is_enough_place(size))
00249 if (m_garbage(0))
00250 break;
00251
00252 #endif
00253
00254 for (unsigned int ntries = 0;; ntries++) {
00255 if ((*p = (caddr_t)mmap(addr, size, prot, flags, fildes, off)) != MAP_FAILED) {
00256 m_Map *m = (m_Map *)calloc(sizeof(m_Map), 1);
00257
00258 assert(m);
00259 m->p = p;
00260 m->addr = addr;
00261 m->size = size;
00262 m->prot = prot;
00263 m->flags = flags;
00264 m->fildes = fildes;
00265 m->off = off;
00266 m->file = strdup(file);
00267 m->startns = startns;
00268 m->endns = endns;
00269
00270 m_insert(m);
00271
00272 IDB_LOG(IDB_LOG_MMAP,
00273 ("segment mapped file=\"%s\" segment=[%p, %p[ "
00274 "size=%lu prot=%p flags=%p fd=%d offset=%u",
00275 file, *p, (*p)+size, size, prot, flags, fildes, off));
00276
00277 if (endns > 0)
00278 IDB_LOG_X(IDB_LOG_MMAP,
00279 (" startns=%d endns=%d\n", startns, endns));
00280 else
00281 IDB_LOG_X(IDB_LOG_MMAP, ("\n"));
00282
00283 #ifdef USE_MADVISE
00284 if (must_madvise && madvise(*p, size, MADV_RANDOM)) {
00285 IDB_LOG(IDB_LOG_MMAP,
00286 ("madvise failed for %p %d\n", *p, size));
00287 perror("madvise");
00288 }
00289 #endif
00290 return m;
00291 }
00292
00293 IDB_LOG(IDB_LOG_MMAP_DETAIL,
00294 ("mapping failed file=\"%s\" size=%lu prot=%p flags=%p "
00295 "fd=%d offset=%u attempt=#%d\n",
00296 file, size, prot, flags, fildes, off, ntries));
00297
00298
00299
00300 if (endns > 0)
00301 IDB_LOG_X(IDB_LOG_MMAP_DETAIL,
00302 (" startns=%d endns=%d\n", startns, endns));
00303 else
00304 IDB_LOG_X(IDB_LOG_MMAP, ("\n"));
00305
00306 if (m_garbage(0))
00307 break;
00308 }
00309
00310 *p = 0;
00311
00312 IDB_LOG((eyedblib::LogMask)~0,
00313 ("mapping *definitively* failed file=\"%s\""
00314 "size=%lu prot=%p flags=%p fd=%d offset=%u startns=%d endns=%d\n",
00315 file, *p, (*p)+size, size, prot, flags, fildes, off, startns, endns));
00316
00317
00318
00319
00320
00321 return 0;
00322 }
00323
00324 void m_lock(m_Map *m)
00325 {
00326 m->locked = 1;
00327 }
00328
00329 void m_unlock(m_Map *m)
00330 {
00331 m->locked = 0;
00332 }
00333
00334 void m_access(m_Map *m)
00335 {
00336 m->ref = ++m_ref;
00337 }
00338
00339 int m_munmap(m_Map *map, caddr_t addr, size_t size)
00340 {
00341 IDB_LOG(IDB_LOG_MMAP,
00342 ("segment unmapped file=\"%s\" segment=[%p, %p[ "
00343 "size=%lu prot=%p flags=%p fd=%d offset=%u "
00344 "startns=%d endns=%d\n",
00345 map->file, *map->p, (*map->p)+map->size, map->size, map->prot,
00346 map->flags, map->fildes, map->off,
00347 map->startns, map->endns));
00348
00349
00350
00351 if (map->size != size) {
00352 IDB_LOG(IDB_LOG_MMAP,
00353 ("warning unmap size differ : %lu %lu",
00354 map->size, size));
00355 }
00356
00357
00358 return m_garbage(map);
00359 }
00360
00361 void *m_malloc(size_t size)
00362 {
00363 void *p;
00364
00365 if (!init_done)
00366 m_init();
00367
00368 if (!size)
00369 size = 4;
00370
00371 while (!(p = malloc(size)))
00372 if (errno != ENOMEM || m_garbage(0))
00373 m_abort_msg("malloc(%lu) failed [errno %d]\n", size, errno);
00374
00375 return p;
00376 }
00377
00378 void *m_calloc(size_t nelem, size_t elsize)
00379 {
00380 void *p;
00381
00382 if (!init_done)
00383 m_init();
00384
00385 while (!(p = calloc(nelem, elsize)))
00386 if (errno != ENOMEM || m_garbage(0))
00387 m_abort_msg("calloc(%d, %lu) failed [errno %d]\n", nelem, elsize,
00388 errno);
00389
00390 return p;
00391 }
00392
00393 void *m_realloc(void *ptr, size_t size)
00394 {
00395 void *p;
00396
00397 if (!init_done)
00398 m_init();
00399
00400 while (!(p = realloc(ptr, size)))
00401 if (errno != ENOMEM || m_garbage(0))
00402 m_abort_msg("realloc(%p, %lu) failed [errno %d]\n", ptr, size,
00403 errno);
00404
00405 return p;
00406 }
00407
00408 void m_free(void *ptr)
00409 {
00410 free(ptr);
00411 }
00412
00413 void m_abort_msg(const char *fmt, ...)
00414 {
00415 va_list ap;
00416 va_start(ap, fmt);
00417 m_maptrace(std::cerr);
00418 vfprintf(stderr, fmt, ap);
00419 m_abort();
00420 va_end(ap);
00421 }
00422
00423 void m_abort()
00424 {
00425 m_mmaps_garbage();
00426 abort();
00427 }
00428
00429 void m_mmaps_garbage()
00430 {
00431 m_Map *m = m_head, *next;
00432
00433 while (m) {
00434 next = m->next;
00435 m_garbage(m);
00436 m = next;
00437 }
00438 }
00439
00440 void m_maptrace(std::ostream &os)
00441 {
00442 m_Map *m = m_head;
00443
00444 os << "----------------------- eyedb memory map manager ---------------------\n";
00445
00446 while (m) {
00447 os << " addr " << *m->p << " size " << m->size << "[" <<
00448 (m->size/ONE_K) << " kb\n";
00449 m = m->next;
00450 }
00451
00452 os << " total memory used: " << (m_tmsize/ONE_K) << " kb\n";
00453 if (m_maxsize)
00454 os << " maximum memory size: " << (m_maxsize/ONE_K) << " kb\n";
00455
00456 }
00457
00458 size_t m_get_totalsize()
00459 {
00460 return m_tmsize;
00461 }
00462
00463 void m_set_maxsize(size_t maxsize)
00464 {
00465 m_maxsize = maxsize;
00466 if (m_maxsize != 0 && m_maxsize < m_min_maxsize)
00467 m_maxsize = m_min_maxsize;
00468
00469 reduce_memory(0);
00470 }
00471
00472 size_t m_get_maxsize()
00473 {
00474 return m_maxsize;
00475 }