00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 #include "ink_config.h"
00040 #include <assert.h>
00041 #include <memory.h>
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 #include <sys/types.h>
00045 #include <sys/mman.h>
00046 #include "ink_atomic.h"
00047 #include "ink_queue.h"
00048 #include "ink_memory.h"
00049 #include "ink_error.h"
00050 #include "ink_assert.h"
00051 #include "ink_queue_ext.h"
00052 #include "ink_align.h"
00053 
00054 inkcoreapi volatile int64_t fastalloc_mem_in_use = 0;
00055 inkcoreapi volatile int64_t fastalloc_mem_total = 0;
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 #ifdef DEBUG
00064 #define SANITY
00065 #define DEADBEEF
00066 #endif
00067 
00068 
00069 
00070 #define MEMPROTECT_SIZE  0x200
00071 
00072 #ifdef MEMPROTECT
00073 static const int page_size = ats_pagesize();
00074 #endif
00075 
00076 ink_freelist_list *freelists = NULL;
00077 
00078 inkcoreapi volatile int64_t freelist_allocated_mem = 0;
00079 
00080 #define fl_memadd(_x_) \
00081    ink_atomic_increment(&freelist_allocated_mem, (int64_t) (_x_));
00082 
00083 void
00084 ink_freelist_init(InkFreeList **fl, const char *name, uint32_t type_size,
00085                   uint32_t chunk_size, uint32_t alignment)
00086 {
00087 #if TS_USE_RECLAIMABLE_FREELIST
00088   return reclaimable_freelist_init(fl, name, type_size, chunk_size, alignment);
00089 #else
00090   InkFreeList *f;
00091   ink_freelist_list *fll;
00092 
00093   
00094 
00095   f = (InkFreeList *)ats_memalign(alignment, sizeof(InkFreeList));
00096   fll = (ink_freelist_list *)ats_malloc(sizeof(ink_freelist_list));
00097   fll->fl = f;
00098   fll->next = freelists;
00099   freelists = fll;
00100 
00101   f->name = name;
00102   
00103   ink_assert(!(alignment & (alignment - 1)));
00104   f->alignment = alignment;
00105   f->chunk_size = chunk_size;
00106   
00107   f->type_size = INK_ALIGN(type_size, alignment);
00108   SET_FREELIST_POINTER_VERSION(f->head, FROM_PTR(0), 0);
00109 
00110   f->used = 0;
00111   f->allocated = 0;
00112   f->allocated_base = 0;
00113   f->used_base = 0;
00114   *fl = f;
00115 #endif
00116 }
00117 
00118 InkFreeList *
00119 ink_freelist_create(const char *name, uint32_t type_size, uint32_t chunk_size,
00120                     uint32_t alignment)
00121 {
00122   InkFreeList *f;
00123 
00124   ink_freelist_init(&f, name, type_size, chunk_size, alignment);
00125   return f;
00126 }
00127 
00128 #define ADDRESS_OF_NEXT(x, offset) ((void **)((char *)x + offset))
00129 
00130 #ifdef SANITY
00131 int fake_global_for_ink_queue = 0;
00132 #endif
00133 
00134 int fastmemtotal = 0;
00135 void *
00136 ink_freelist_new(InkFreeList * f)
00137 {
00138 #if TS_USE_FREELIST
00139 #if TS_USE_RECLAIMABLE_FREELIST
00140   return reclaimable_freelist_new(f);
00141 #else
00142   head_p item;
00143   head_p next;
00144   int result = 0;
00145 
00146   do {
00147     INK_QUEUE_LD(item, f->head);
00148     if (TO_PTR(FREELIST_POINTER(item)) == NULL) {
00149       uint32_t type_size = f->type_size;
00150       uint32_t i;
00151 
00152 #ifdef MEMPROTECT
00153       if (type_size >= MEMPROTECT_SIZE) {
00154         if (f->alignment < page_size)
00155           f->alignment = page_size;
00156         type_size = ((type_size + page_size - 1) / page_size) * page_size * 2;
00157       }
00158 #endif 
00159 
00160       void *newp = NULL;
00161 #ifdef DEBUG
00162       char *oldsbrk = (char *) sbrk(0), *newsbrk = NULL;
00163 #endif
00164       if (f->alignment)
00165         newp = ats_memalign(f->alignment, f->chunk_size * type_size);
00166       else
00167         newp = ats_malloc(f->chunk_size * type_size);
00168       fl_memadd(f->chunk_size * type_size);
00169 #ifdef DEBUG
00170       newsbrk = (char *) sbrk(0);
00171       ink_atomic_increment(&fastmemtotal, newsbrk - oldsbrk);
00172       
00173 
00174 #endif
00175       SET_FREELIST_POINTER_VERSION(item, newp, 0);
00176 
00177       ink_atomic_increment((int *) &f->allocated, f->chunk_size);
00178       ink_atomic_increment(&fastalloc_mem_total, (int64_t) f->chunk_size * f->type_size);
00179 
00180       
00181       for (i = 0; i < f->chunk_size; i++) {
00182         char *a = ((char *) FREELIST_POINTER(item)) + i * type_size;
00183 #ifdef DEADBEEF
00184         const char str[4] = { (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef };
00185         for (int j = 0; j < (int)type_size; j++)
00186           a[j] = str[j % 4];
00187 #endif
00188         ink_freelist_free(f, a);
00189 #ifdef MEMPROTECT
00190         if (f->type_size >= MEMPROTECT_SIZE) {
00191           a += type_size - page_size;
00192           if (mprotect(a, page_size, PROT_NONE) < 0)
00193             perror("mprotect");
00194         }
00195 #endif 
00196 
00197       }
00198       ink_atomic_increment((int *) &f->used, f->chunk_size);
00199       ink_atomic_increment(&fastalloc_mem_in_use, (int64_t) f->chunk_size * f->type_size);
00200 
00201     } else {
00202       SET_FREELIST_POINTER_VERSION(next, *ADDRESS_OF_NEXT(TO_PTR(FREELIST_POINTER(item)), 0),
00203                                    FREELIST_VERSION(item) + 1);
00204 #if TS_HAS_128BIT_CAS
00205        result = ink_atomic_cas((__int128_t*)&f->head.data, item.data, next.data);
00206 #else
00207        result = ink_atomic_cas((int64_t *) & f->head.data, item.data, next.data);
00208 #endif
00209 
00210 #ifdef SANITY
00211       if (result) {
00212         if (FREELIST_POINTER(item) == TO_PTR(FREELIST_POINTER(next)))
00213           ink_fatal(1, "ink_freelist_new: loop detected");
00214         if (((uintptr_t) (TO_PTR(FREELIST_POINTER(next)))) & 3)
00215           ink_fatal(1, "ink_freelist_new: bad list");
00216         if (TO_PTR(FREELIST_POINTER(next)))
00217           fake_global_for_ink_queue = *(int *) TO_PTR(FREELIST_POINTER(next));
00218       }
00219 #endif 
00220 
00221     }
00222   }
00223   while (result == 0);
00224   ink_assert(!((uintptr_t)TO_PTR(FREELIST_POINTER(item))&(((uintptr_t)f->alignment)-1)));
00225 
00226   ink_atomic_increment((int *) &f->used, 1);
00227   ink_atomic_increment(&fastalloc_mem_in_use, (int64_t) f->type_size);
00228 
00229   return TO_PTR(FREELIST_POINTER(item));
00230 #endif 
00231 #else // ! TS_USE_FREELIST
00232   void *newp = NULL;
00233 
00234   if (f->alignment)
00235     newp = ats_memalign(f->alignment, f->type_size);
00236   else
00237     newp = ats_malloc(f->type_size);
00238   return newp;
00239 #endif
00240 }
00241 typedef volatile void *volatile_void_p;
00242 
00243 void
00244 ink_freelist_free(InkFreeList * f, void *item)
00245 {
00246 #if TS_USE_FREELIST
00247 #if TS_USE_RECLAIMABLE_FREELIST
00248   return reclaimable_freelist_free(f, item);
00249 #else
00250   volatile_void_p *adr_of_next = (volatile_void_p *) ADDRESS_OF_NEXT(item, 0);
00251   head_p h;
00252   head_p item_pair;
00253   int result = 0;
00254 
00255   
00256 
00257 #ifdef DEADBEEF
00258   {
00259     static const char str[4] = { (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef };
00260 
00261     
00262     for (int j = 0; j < (int)f->type_size; j++)
00263       ((char*)item)[j] = str[j % 4];
00264   }
00265 #endif 
00266 
00267   while (!result) {
00268     INK_QUEUE_LD(h, f->head);
00269 #ifdef SANITY
00270     if (TO_PTR(FREELIST_POINTER(h)) == item)
00271       ink_fatal(1, "ink_freelist_free: trying to free item twice");
00272     if (((uintptr_t) (TO_PTR(FREELIST_POINTER(h)))) & 3)
00273       ink_fatal(1, "ink_freelist_free: bad list");
00274     if (TO_PTR(FREELIST_POINTER(h)))
00275       fake_global_for_ink_queue = *(int *) TO_PTR(FREELIST_POINTER(h));
00276 #endif 
00277     *adr_of_next = FREELIST_POINTER(h);
00278     SET_FREELIST_POINTER_VERSION(item_pair, FROM_PTR(item), FREELIST_VERSION(h));
00279     INK_MEMORY_BARRIER;
00280 #if TS_HAS_128BIT_CAS
00281        result = ink_atomic_cas((__int128_t*) & f->head, h.data, item_pair.data);
00282 #else
00283        result = ink_atomic_cas((int64_t *) & f->head, h.data, item_pair.data);
00284 #endif
00285   }
00286 
00287   ink_atomic_increment((int *) &f->used, -1);
00288   ink_atomic_increment(&fastalloc_mem_in_use, -(int64_t) f->type_size);
00289 #endif 
00290 #else
00291   if (f->alignment)
00292     ats_memalign_free(item);
00293   else
00294     ats_free(item);
00295 #endif
00296 }
00297 
00298 void
00299 ink_freelists_snap_baseline()
00300 {
00301 #if TS_USE_FREELIST
00302   ink_freelist_list *fll;
00303   fll = freelists;
00304   while (fll) {
00305     fll->fl->allocated_base = fll->fl->allocated;
00306     fll->fl->used_base = fll->fl->used;
00307     fll = fll->next;
00308   }
00309 #else // ! TS_USE_FREELIST
00310   
00311 #endif
00312 }
00313 
00314 void
00315 ink_freelists_dump_baselinerel(FILE * f)
00316 {
00317 #if TS_USE_FREELIST
00318   ink_freelist_list *fll;
00319   if (f == NULL)
00320     f = stderr;
00321 
00322   fprintf(f, "     allocated      |       in-use       |  count  | type size  |   free list name\n");
00323   fprintf(f, "  relative to base  |  relative to base  |         |            |                 \n");
00324   fprintf(f, "--------------------|--------------------|---------|------------|----------------------------------\n");
00325 
00326   fll = freelists;
00327   while (fll) {
00328     int a = fll->fl->allocated - fll->fl->allocated_base;
00329     if (a != 0) {
00330       fprintf(f, " %18" PRIu64 " | %18" PRIu64 " | %7u | %10u | memory/%s\n",
00331               (uint64_t)(fll->fl->allocated - fll->fl->allocated_base) * (uint64_t)fll->fl->type_size,
00332               (uint64_t)(fll->fl->used- fll->fl->used_base) * (uint64_t)fll->fl->type_size,
00333               fll->fl->used - fll->fl->used_base, fll->fl->type_size, fll->fl->name ? fll->fl->name : "<unknown>");
00334     }
00335     fll = fll->next;
00336   }
00337 #else // ! TS_USE_FREELIST
00338   (void)f;
00339 #endif
00340 }
00341 
00342 void
00343 ink_freelists_dump(FILE * f)
00344 {
00345 #if TS_USE_FREELIST
00346   ink_freelist_list *fll;
00347   if (f == NULL)
00348     f = stderr;
00349 
00350   fprintf(f, "     allocated      |        in-use      | type size  |   free list name\n");
00351   fprintf(f, "--------------------|--------------------|------------|----------------------------------\n");
00352 
00353   fll = freelists;
00354   while (fll) {
00355     fprintf(f, " %18" PRIu64 " | %18" PRIu64 " | %10u | memory/%s\n",
00356             (uint64_t)fll->fl->allocated * (uint64_t)fll->fl->type_size,
00357             (uint64_t)fll->fl->used * (uint64_t)fll->fl->type_size, fll->fl->type_size, fll->fl->name ? fll->fl->name : "<unknown>");
00358     fll = fll->next;
00359   }
00360 #else // ! TS_USE_FREELIST
00361   (void)f;
00362 #endif
00363 }
00364 
00365 
00366 void
00367 ink_atomiclist_init(InkAtomicList * l, const char *name, uint32_t offset_to_next)
00368 {
00369   l->name = name;
00370   l->offset = offset_to_next;
00371   SET_FREELIST_POINTER_VERSION(l->head, FROM_PTR(0), 0);
00372 }
00373 
00374 void *
00375 ink_atomiclist_pop(InkAtomicList * l)
00376 {
00377   head_p item;
00378   head_p next;
00379   int result = 0;
00380   do {
00381     INK_QUEUE_LD(item, l->head);
00382     if (TO_PTR(FREELIST_POINTER(item)) == NULL)
00383       return NULL;
00384     SET_FREELIST_POINTER_VERSION(next, *ADDRESS_OF_NEXT(TO_PTR(FREELIST_POINTER(item)), l->offset),
00385                                  FREELIST_VERSION(item) + 1);
00386 #if TS_HAS_128BIT_CAS
00387        result = ink_atomic_cas((__int128_t*) & l->head.data, item.data, next.data);
00388 #else
00389        result = ink_atomic_cas((int64_t *) & l->head.data, item.data, next.data);
00390 #endif
00391   }
00392   while (result == 0);
00393   {
00394     void *ret = TO_PTR(FREELIST_POINTER(item));
00395     *ADDRESS_OF_NEXT(ret, l->offset) = NULL;
00396     return ret;
00397   }
00398 }
00399 
00400 void *
00401 ink_atomiclist_popall(InkAtomicList * l)
00402 {
00403   head_p item;
00404   head_p next;
00405   int result = 0;
00406   do {
00407     INK_QUEUE_LD(item, l->head);
00408     if (TO_PTR(FREELIST_POINTER(item)) == NULL)
00409       return NULL;
00410     SET_FREELIST_POINTER_VERSION(next, FROM_PTR(NULL), FREELIST_VERSION(item) + 1);
00411 #if TS_HAS_128BIT_CAS
00412        result = ink_atomic_cas((__int128_t*) & l->head.data, item.data, next.data);
00413 #else
00414        result = ink_atomic_cas((int64_t *) & l->head.data, item.data, next.data);
00415 #endif
00416   }
00417   while (result == 0);
00418   {
00419     void *ret = TO_PTR(FREELIST_POINTER(item));
00420     void *e = ret;
00421     
00422     while (e) {
00423       void *n = TO_PTR(*ADDRESS_OF_NEXT(e, l->offset));
00424       *ADDRESS_OF_NEXT(e, l->offset) = n;
00425       e = n;
00426     }
00427     return ret;
00428   }
00429 }
00430 
00431 void *
00432 ink_atomiclist_push(InkAtomicList * l, void *item)
00433 {
00434   volatile_void_p *adr_of_next = (volatile_void_p *) ADDRESS_OF_NEXT(item, l->offset);
00435   head_p head;
00436   head_p item_pair;
00437   int result = 0;
00438   volatile void *h = NULL;
00439   do {
00440     INK_QUEUE_LD(head, l->head);
00441     h = FREELIST_POINTER(head);
00442     *adr_of_next = h;
00443     ink_assert(item != TO_PTR(h));
00444     SET_FREELIST_POINTER_VERSION(item_pair, FROM_PTR(item), FREELIST_VERSION(head));
00445     INK_MEMORY_BARRIER;
00446 #if TS_HAS_128BIT_CAS
00447        result = ink_atomic_cas((__int128_t*) & l->head, head.data, item_pair.data);
00448 #else
00449        result = ink_atomic_cas((int64_t *) & l->head, head.data, item_pair.data);
00450 #endif
00451   }
00452   while (result == 0);
00453 
00454   return TO_PTR(h);
00455 }
00456 
00457 void *
00458 ink_atomiclist_remove(InkAtomicList * l, void *item)
00459 {
00460   head_p head;
00461   void *prev = NULL;
00462   void **addr_next = ADDRESS_OF_NEXT(item, l->offset);
00463   void *item_next = *addr_next;
00464   int result = 0;
00465 
00466   
00467 
00468 
00469   INK_QUEUE_LD(head, l->head);
00470   while (TO_PTR(FREELIST_POINTER(head)) == item) {
00471     head_p next;
00472     SET_FREELIST_POINTER_VERSION(next, item_next, FREELIST_VERSION(head) + 1);
00473 #if TS_HAS_128BIT_CAS
00474        result = ink_atomic_cas((__int128_t*) & l->head.data, head.data, next.data);
00475 #else
00476        result = ink_atomic_cas((int64_t *) & l->head.data, head.data, next.data);
00477 #endif
00478 
00479     if (result) {
00480       *addr_next = NULL;
00481       return item;
00482     }
00483     INK_QUEUE_LD(head, l->head);
00484   }
00485 
00486   
00487 
00488 
00489   prev = TO_PTR(FREELIST_POINTER(head));
00490   while (prev) {
00491     void **prev_adr_of_next = ADDRESS_OF_NEXT(prev, l->offset);
00492     void *prev_prev = prev;
00493     prev = TO_PTR(*prev_adr_of_next);
00494     if (prev == item) {
00495       ink_assert(prev_prev != item_next);
00496       *prev_adr_of_next = item_next;
00497       *addr_next = NULL;
00498       return item;
00499     }
00500   }
00501   return NULL;
00502 }