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 }