• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

ink_queue.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /*****************************************************************************
00025   ink_queue.cc (This used to be ink_queue.c)
00026 
00027   This implements an atomic push/pop queue, and the freelist memory
00028   pools that are built from it.
00029 
00030   The change from ink_queue.cc to ink_queue.c resulted in some changes
00031   in access and store of 64 bit values. This is standardized by using
00032   the INK_QUEUE_LD64 macro which loads the version before the pointer
00033   (independent of endianness of native architecture) on 32 bit platforms
00034   or loads the 64 bit quantity directory on the DECs.
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  * SANITY and DEADBEEF are compute-intensive memory debugging to
00059  * help in diagnosing freelist corruption.  We turn them off in
00060  * release builds.
00061  */
00062 
00063 #ifdef DEBUG
00064 #define SANITY
00065 #define DEADBEEF
00066 #endif
00067 
00068 // #define MEMPROTECT 1
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   /* its safe to add to this global list because ink_freelist_init()
00094      is only called from single-threaded initialization code. */
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   /* quick test for power of 2 */
00103   ink_assert(!(alignment & (alignment - 1)));
00104   f->alignment = alignment;
00105   f->chunk_size = chunk_size;
00106   // Make sure we align *all* the objects in the allocation, not just the first one
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 /* MEMPROTECT */
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       /*      printf("fastmem %d, %d, %d\n", f->chunk_size * type_size,
00173          newsbrk - oldsbrk, fastmemtotal); */
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       /* free each of the new elements */
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 /* MEMPROTECT */
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 /* SANITY */
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 /* TS_USE_RECLAIMABLE_FREELIST */
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   // ink_assert(!((long)item&(f->alignment-1))); XXX - why is this no longer working? -bcall
00256 
00257 #ifdef DEADBEEF
00258   {
00259     static const char str[4] = { (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef };
00260 
00261     // set the entire item to DEADBEEF
00262     for (int j = 0; j < (int)f->type_size; j++)
00263       ((char*)item)[j] = str[j % 4];
00264   }
00265 #endif /* DEADBEEF */
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 /* SANITY */
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 /* TS_USE_RECLAIMABLE_FREELIST */
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   // TODO?
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     /* fixup forward pointers */
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    * first, try to pop it if it is first
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    * then, go down the list, trying to remove it
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 }

Generated by  doxygen 1.7.1