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

HdrHeap.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 
00026    HdrBuf.cc
00027 
00028    Description:
00029 
00030 
00031  ****************************************************************************/
00032 
00033 #include "libts.h"
00034 #include "HdrHeap.h"
00035 #include "URL.h"
00036 #include "MIME.h"
00037 #include "HTTP.h"
00038 #include "I_EventSystem.h"
00039 
00040 #define MAX_LOST_STR_SPACE 1024
00041 
00042 Allocator hdrHeapAllocator("hdrHeap", HDR_HEAP_DEFAULT_SIZE);
00043 static HdrHeap proto_heap;
00044 
00045 Allocator strHeapAllocator("hdrStrHeap", HDR_STR_HEAP_DEFAULT_SIZE);
00046 static HdrStrHeap str_proto_heap;
00047 
00048 /*-------------------------------------------------------------------------
00049   -------------------------------------------------------------------------*/
00050 
00051 void
00052 obj_describe(HdrHeapObjImpl * obj, bool recurse)
00053 {
00054   static const char *obj_names[] = { "EMPTY", "RAW", "URL", "HTTP_HEADER", "MIME_HEADER", "FIELD_BLOCK" };
00055 
00056   Debug("http", "%s %p: [T: %d, L: %4d, OBJFLAGS: %X]  ",
00057         obj_names[obj->m_type], obj, obj->m_type, obj->m_length, obj->m_obj_flags);
00058 
00059   extern void url_describe(HdrHeapObjImpl * obj, bool recurse);
00060   extern void http_hdr_describe(HdrHeapObjImpl * obj, bool recurse);
00061   extern void mime_hdr_describe(HdrHeapObjImpl * obj, bool recurse);
00062   extern void mime_field_block_describe(HdrHeapObjImpl * obj, bool recurse);
00063 
00064   switch (obj->m_type) {
00065   case HDR_HEAP_OBJ_EMPTY:
00066     break;
00067   case HDR_HEAP_OBJ_RAW:
00068     break;
00069   case HDR_HEAP_OBJ_MIME_HEADER:
00070     mime_hdr_describe(obj, recurse);
00071     break;
00072   case HDR_HEAP_OBJ_FIELD_BLOCK:
00073     mime_field_block_describe(obj, recurse);
00074     break;
00075   case HDR_HEAP_OBJ_HTTP_HEADER:
00076     http_hdr_describe(obj, recurse);
00077     break;
00078   case HDR_HEAP_OBJ_URL:
00079     url_describe(obj, recurse);
00080     break;
00081   default:
00082     break;
00083   }
00084 }
00085 
00086 /*-------------------------------------------------------------------------
00087   -------------------------------------------------------------------------*/
00088 
00089 inline void
00090 HdrHeap::init()
00091 {
00092   m_data_start = m_free_start = ((char *) this) + HDR_HEAP_HDR_SIZE;
00093   m_magic = HDR_BUF_MAGIC_ALIVE;
00094   m_writeable = true;
00095 
00096   m_next = NULL;
00097   m_free_size = m_size - HDR_HEAP_HDR_SIZE;
00098 
00099   // We need to clear m_ptr directly since it's garbage and
00100   //  using the operator functions will to free() what ever
00101   //  garbage it is pointing to
00102   m_read_write_heap.m_ptr = NULL;
00103 
00104   for (int i = 0; i < HDR_BUF_RONLY_HEAPS; i++) {
00105     m_ronly_heap[i].m_heap_start = NULL;
00106     m_ronly_heap[i].m_ref_count_ptr.m_ptr = NULL;
00107     m_ronly_heap[i].m_locked = false;
00108     m_ronly_heap[i].m_heap_len = 0;
00109   }
00110   m_lost_string_space = 0;
00111 
00112   ink_assert(m_free_size > 0);
00113 }
00114 
00115 HdrHeap *
00116 new_HdrHeap(int size)
00117 {
00118   HdrHeap *h;
00119   if (size <= HDR_HEAP_DEFAULT_SIZE) {
00120     size = HDR_HEAP_DEFAULT_SIZE;
00121     h = (HdrHeap *)(THREAD_ALLOC(hdrHeapAllocator, this_ethread()));
00122   } else {
00123     h = (HdrHeap *)ats_malloc(size);
00124   }
00125 
00126 //    Debug("hdrs", "Allocated header heap in size %d", size);
00127 
00128   // Patch vritual function table ptr
00129   *((void **) h) = *((void **) &proto_heap);
00130 
00131   h->m_size = size;
00132   h->init();
00133 
00134 
00135   return h;
00136 }
00137 
00138 HdrStrHeap *
00139 new_HdrStrHeap(int requested_size)
00140 {
00141   // The callee is asking for a string heap to be created
00142   //  that can allocate at least size bytes.  As such we,
00143   //  need to include the size of the string heap header in
00144   //  our calculations
00145 
00146   int alloc_size = requested_size + sizeof(HdrStrHeap);
00147 
00148   HdrStrHeap *sh;
00149   if (alloc_size <= HDR_STR_HEAP_DEFAULT_SIZE) {
00150     alloc_size = HDR_STR_HEAP_DEFAULT_SIZE;
00151     sh = (HdrStrHeap *)(THREAD_ALLOC(strHeapAllocator, this_ethread()));
00152   } else {
00153     alloc_size = ROUND(alloc_size, HDR_STR_HEAP_DEFAULT_SIZE*2);
00154     sh = (HdrStrHeap *)ats_malloc(alloc_size);
00155   }
00156 
00157 //    Debug("hdrs", "Allocated string heap in size %d", alloc_size);
00158 
00159   // Patch virtual function table ptr
00160   *((void **) sh) = *((void **) &str_proto_heap);
00161 
00162   sh->m_heap_size = alloc_size;
00163   sh->m_free_size = alloc_size - STR_HEAP_HDR_SIZE;
00164   sh->m_free_start = ((char *) sh) + STR_HEAP_HDR_SIZE;
00165   sh->m_refcount = 0;
00166 
00167   ink_assert(sh->m_free_size > 0);
00168 
00169   return sh;
00170 }
00171 
00172 void
00173 HdrHeap::destroy()
00174 {
00175   if (m_next) {
00176     m_next->destroy();
00177   }
00178 
00179   m_read_write_heap = NULL;
00180   for (int i = 0; i < HDR_BUF_RONLY_HEAPS; i++)
00181     m_ronly_heap[i].m_ref_count_ptr = NULL;
00182 
00183   if (m_size == HDR_HEAP_DEFAULT_SIZE) {
00184     THREAD_FREE(this, hdrHeapAllocator, this_thread());
00185   } else {
00186     ats_free(this);
00187   }
00188 }
00189 
00190 HdrHeapObjImpl *
00191 HdrHeap::allocate_obj(int nbytes, int type)
00192 {
00193   char *new_space;
00194   HdrHeapObjImpl *obj;
00195 
00196   ink_assert(m_writeable);
00197 
00198   nbytes = ROUND(nbytes, HDR_PTR_SIZE);
00199 
00200   if (nbytes > (int)HDR_MAX_ALLOC_SIZE) {
00201     ink_assert(!"alloc too big");
00202     return NULL;
00203   }
00204 
00205   HdrHeap *h = this;
00206 
00207 
00208   while (1) {
00209     if ((unsigned) nbytes <= (h->m_free_size)) {
00210       new_space = h->m_free_start;
00211       h->m_free_start += nbytes;
00212       h->m_free_size -= nbytes;
00213 
00214       obj = (HdrHeapObjImpl *) new_space;
00215       obj_init_header(obj, type, nbytes, 0);
00216       ink_assert(obj_is_aligned(obj));
00217 
00218       return obj;
00219 
00220     }
00221 
00222     if (h->m_next == NULL) {
00223       // Allocate our next pointer heap
00224       //   twice as large as this one so
00225       //   number of pointer heaps is O(log n)
00226       //   with regard to number of bytes allocated
00227       h->m_next = new_HdrHeap(h->m_size * 2);
00228     }
00229 
00230     h = h->m_next;
00231   }
00232 }
00233 
00234 void
00235 HdrHeap::deallocate_obj(HdrHeapObjImpl * obj)
00236 {
00237   ink_assert(m_writeable);
00238   obj->m_type = HDR_HEAP_OBJ_EMPTY;
00239 }
00240 
00241 
00242 char *
00243 HdrHeap::allocate_str(int nbytes)
00244 {
00245   int last_size = 0;
00246   char *new_space = NULL;
00247   ink_assert(m_writeable);
00248 
00249   // INKqa08287 - We could get infinite build up
00250   //   of dead strings on header merge.  To prevent
00251   //   this we keep track of the dead string space
00252   //   and force a heap coalesce if it is too large.
00253   //   Ideally this should be done on free_string()
00254   //   but I already no that this code path is
00255   //   safe for forcing a str coalesce so I'm doing
00256   //   it here for sanity's sake
00257   if (m_lost_string_space > (int)MAX_LOST_STR_SPACE) {
00258     goto FAILED;
00259   }
00260 
00261 
00262 RETRY:
00263   // First check to see if we have a read/write
00264   //   string heap
00265   if (!m_read_write_heap) {
00266     int next_size = (last_size * 2) - STR_HEAP_HDR_SIZE;
00267     next_size = next_size > nbytes ? next_size : nbytes;
00268     m_read_write_heap = new_HdrStrHeap(next_size);
00269   }
00270   // Try to allocate of our read/write string heap
00271   new_space = m_read_write_heap->allocate(nbytes);
00272 
00273   if (new_space) {
00274     return new_space;
00275   }
00276 
00277   last_size = m_read_write_heap->m_heap_size;
00278 
00279   // Our existing rw str heap doesn't have sufficient
00280   //  capacity.  We need to move the current rw heap
00281   //  out of the way and create a new one
00282   if (demote_rw_str_heap() == 0) {
00283     goto RETRY;
00284   }
00285 
00286 FAILED:
00287   // We failed to demote.  We'll have to coalesce
00288   //  the heaps
00289   coalesce_str_heaps();
00290   goto RETRY;
00291 
00292 }
00293 
00294 // char* HdrHeap::expand_str(const char* old_str, int old_len, int new_len)
00295 //
00296 //   Attempt to grow an already allocated string.  For this to work,
00297 //      the string  has to be the last one in the read-write string
00298 //      heap and there has to be enough space that string heap
00299 //   If expansion succeeds, we return old_str.  If it fails, we
00300 //      return NULL
00301 //
00302 char *
00303 HdrHeap::expand_str(const char *old_str, int old_len, int new_len)
00304 {
00305   if (m_read_write_heap && m_read_write_heap->contains(old_str))
00306     return m_read_write_heap->expand((char *)old_str, old_len, new_len);
00307 
00308   return NULL;
00309 }
00310 
00311 // char* HdrHeap::duplicate_str(char* str, int nbytes)
00312 //
00313 //  Allocates a new string and copies the old data.
00314 //  Returns the new string pointer.
00315 //
00316 char *
00317 HdrHeap::duplicate_str(const char *str, int nbytes)
00318 {
00319   HeapGuard guard(this, str); // Don't let the source get de-allocated.
00320   char *new_str = allocate_str(nbytes);
00321 
00322   memcpy(new_str, str, nbytes);
00323   return (new_str);
00324 }
00325 
00326 
00327 // int HdrHeap::demote_rw_str_heap()
00328 //
00329 //  Returns 0 on success and non-zero failure
00330 //   Failure means all the read only heap slots
00331 //   were full
00332 //
00333 int
00334 HdrHeap::demote_rw_str_heap()
00335 {
00336   // First, see if we have any open slots for read
00337   //  only heaps
00338   for (int i = 0; i < HDR_BUF_RONLY_HEAPS; i++) {
00339     if (m_ronly_heap[i].m_heap_start == NULL) {
00340       // We've found a slot
00341       m_ronly_heap[i].m_ref_count_ptr = m_read_write_heap;
00342       m_ronly_heap[i].m_heap_start = (char *) m_read_write_heap.m_ptr;
00343       m_ronly_heap[i].m_heap_len = m_read_write_heap->m_heap_size - m_read_write_heap->m_free_size;
00344 
00345 //          Debug("hdrs", "Demoted rw heap of %d size", m_read_write_heap->m_heap_size);
00346       m_read_write_heap = NULL;
00347       return 0;
00348     }
00349   }
00350 
00351   // No open slots
00352   return 1;
00353 }
00354 
00355 // void HdrHeap::coalesce_heaps()
00356 //
00357 //    Take existing stringheaps and combine them to free up
00358 //      slots in the heap array
00359 //
00360 //  FIX ME: Should we combine a subset of the heaps
00361 //     or all of them?  Current plan is combine all heaps
00362 //     since saves doing bounds checks every string.  At
00363 //     expense of doing far more copying
00364 //
00365 void
00366 HdrHeap::coalesce_str_heaps(int incoming_size)
00367 {
00368   int new_heap_size = incoming_size;
00369   ink_assert(incoming_size >= 0);
00370   ink_assert(m_writeable);
00371 
00372   new_heap_size += required_space_for_evacuation();
00373 
00374   HdrStrHeap *new_heap = new_HdrStrHeap(new_heap_size);
00375   evacuate_from_str_heaps(new_heap);
00376   m_lost_string_space = 0;
00377 
00378   // At this point none of the currently used string
00379   //  heaps are needed since everything is in the
00380   //  new string heap.  So deallocate all the old heaps
00381   m_read_write_heap = new_heap;
00382 
00383   int heaps_removed = 0;
00384   for (int j = 0; j < HDR_BUF_RONLY_HEAPS; j++) {
00385     if (m_ronly_heap[j].m_heap_start != NULL && m_ronly_heap[j].m_locked == false) {
00386       m_ronly_heap[j].m_ref_count_ptr = NULL;
00387       m_ronly_heap[j].m_heap_start = NULL;
00388       m_ronly_heap[j].m_heap_len = 0;
00389       heaps_removed++;
00390     }
00391   }
00392 
00393   // This function is presumed to free up read only
00394   //   string heap slots or be for incoming heaps
00395   //   If we don't have any free heaps, we are screwed
00396   ink_assert(heaps_removed > 0 || incoming_size > 0 || m_ronly_heap[0].m_heap_start == NULL);
00397 }
00398 
00399 void
00400 HdrHeap::evacuate_from_str_heaps(HdrStrHeap * new_heap)
00401 {
00402 //    printf("Str Evac\n");
00403   // Loop over the objects in heap and call the evacuation
00404   //  function in each one
00405   HdrHeap *h = this;
00406   ink_assert(m_writeable);
00407 
00408   while (h) {
00409     char *data = h->m_data_start;
00410 
00411     while (data < h->m_free_start) {
00412       HdrHeapObjImpl *obj = (HdrHeapObjImpl *) data;
00413 
00414       switch (obj->m_type) {
00415       case HDR_HEAP_OBJ_URL:
00416         ((URLImpl *) obj)->move_strings(new_heap);
00417         break;
00418       case HDR_HEAP_OBJ_HTTP_HEADER:
00419         ((HTTPHdrImpl *) obj)->move_strings(new_heap);
00420         break;
00421       case HDR_HEAP_OBJ_MIME_HEADER:
00422         ((MIMEHdrImpl *) obj)->move_strings(new_heap);
00423         break;
00424       case HDR_HEAP_OBJ_FIELD_BLOCK:
00425         ((MIMEFieldBlockImpl *) obj)->move_strings(new_heap);
00426         break;
00427       case HDR_HEAP_OBJ_EMPTY:
00428       case HDR_HEAP_OBJ_RAW:
00429         // Nothing to do
00430         break;
00431       default:
00432         ink_release_assert(0);
00433       }
00434 
00435       data = data + obj->m_length;
00436     }
00437 
00438     h = h->m_next;
00439 
00440   }
00441 }
00442 
00443 size_t
00444 HdrHeap::required_space_for_evacuation()
00445 {
00446   size_t ret = 0;
00447   HdrHeap *h = this;
00448   while (h) {
00449     char *data = h->m_data_start;
00450 
00451     while (data < h->m_free_start) {
00452       HdrHeapObjImpl *obj = (HdrHeapObjImpl *) data;
00453 
00454       switch (obj->m_type) {
00455       case HDR_HEAP_OBJ_URL:
00456         ret += ((URLImpl *) obj)->strings_length();
00457         break;
00458       case HDR_HEAP_OBJ_HTTP_HEADER:
00459         ret += ((HTTPHdrImpl *) obj)->strings_length();
00460         break;
00461       case HDR_HEAP_OBJ_MIME_HEADER:
00462         ret += ((MIMEHdrImpl *) obj)->strings_length();
00463         break;
00464       case HDR_HEAP_OBJ_FIELD_BLOCK:
00465         ret += ((MIMEFieldBlockImpl *) obj)->strings_length();
00466         break;
00467       case HDR_HEAP_OBJ_EMPTY:
00468       case HDR_HEAP_OBJ_RAW:
00469         // Nothing to do
00470         break;
00471       default:
00472         ink_release_assert(0);
00473       }
00474       data = data + obj->m_length;
00475     }
00476     h = h->m_next;
00477   }
00478   return ret;
00479 }
00480 
00481 void
00482 HdrHeap::sanity_check_strs()
00483 {
00484   int num_heaps = 0;
00485   struct HeapCheck heaps[HDR_BUF_RONLY_HEAPS + 1];
00486 
00487   // Build up a string check table
00488   if (m_read_write_heap) {
00489     heaps[num_heaps].start = ((char *) m_read_write_heap.m_ptr) + sizeof(HdrStrHeap);
00490 
00491     int heap_size = m_read_write_heap->m_heap_size - (sizeof(HdrStrHeap) + m_read_write_heap->m_free_size);
00492 
00493     heaps[num_heaps].end = heaps[num_heaps].start + heap_size;
00494     num_heaps++;
00495   }
00496 
00497   for (int i = 0; i < HDR_BUF_RONLY_HEAPS; i++) {
00498     if (m_ronly_heap[i].m_heap_start != NULL) {
00499       heaps[num_heaps].start = m_ronly_heap[i].m_heap_start;
00500       heaps[num_heaps].end = m_ronly_heap[i].m_heap_start + m_ronly_heap[i].m_heap_len;
00501       num_heaps++;
00502     }
00503   }
00504 
00505 
00506   // Loop over the objects in heap call the check
00507   //   function on each one
00508   HdrHeap *h = this;
00509 
00510   while (h) {
00511     char *data = h->m_data_start;
00512 
00513     while (data < h->m_free_start) {
00514       HdrHeapObjImpl *obj = (HdrHeapObjImpl *) data;
00515 
00516       switch (obj->m_type) {
00517       case HDR_HEAP_OBJ_URL:
00518         ((URLImpl *) obj)->check_strings(heaps, num_heaps);
00519         break;
00520       case HDR_HEAP_OBJ_HTTP_HEADER:
00521         ((HTTPHdrImpl *) obj)->check_strings(heaps, num_heaps);
00522         break;
00523       case HDR_HEAP_OBJ_MIME_HEADER:
00524         ((MIMEHdrImpl *) obj)->check_strings(heaps, num_heaps);
00525         break;
00526       case HDR_HEAP_OBJ_FIELD_BLOCK:
00527         ((MIMEFieldBlockImpl *) obj)->check_strings(heaps, num_heaps);
00528         break;
00529       case HDR_HEAP_OBJ_EMPTY:
00530       case HDR_HEAP_OBJ_RAW:
00531         // Nothing to do
00532         break;
00533       default:
00534         ink_release_assert(0);
00535       }
00536 
00537       data = data + obj->m_length;
00538     }
00539 
00540     h = h->m_next;
00541 
00542   }
00543 }
00544 
00545 
00546 // int HdrHeap::marshal_length()
00547 //
00548 //  Determines what the length of a buffer needs to
00549 //   be to marshal this header
00550 //
00551 int
00552 HdrHeap::marshal_length()
00553 {
00554   int len;
00555 
00556   // If there is more than one HdrHeap block, we'll
00557   //  coalesce the HdrHeap blocks together so we
00558   //  only need one block header
00559   len = HDR_HEAP_HDR_SIZE;
00560   HdrHeap *h = this;
00561 
00562   while (h) {
00563     len += (int) (h->m_free_start - h->m_data_start);
00564     h = h->m_next;
00565   }
00566 
00567   // Since when we unmarshal, we won't have a writable string
00568   //  heap, we can drop the header on the read/write
00569   //  string heap
00570   if (m_read_write_heap) {
00571     len += m_read_write_heap->m_heap_size - (sizeof(HdrStrHeap) + m_read_write_heap->m_free_size);
00572   }
00573 
00574   for (int j = 0; j < HDR_BUF_RONLY_HEAPS; j++) {
00575     if (m_ronly_heap[j].m_heap_start != NULL) {
00576       len += m_ronly_heap[j].m_heap_len;
00577     }
00578   }
00579 
00580   len = ROUND(len, HDR_PTR_SIZE);
00581   return len;
00582 }
00583 
00584 #ifdef HDR_HEAP_CHECKSUMS
00585 static uint32_t
00586 compute_checksum(void *buf, int len)
00587 {
00588   uint32_t cksum = 0;
00589 
00590   while (len > 4) {
00591     cksum += *((uint32_t *) buf);
00592     buf = ((char *) buf) + 4;
00593     len -= 4;
00594   }
00595 
00596   if (len > 0) {
00597     uint32_t tmp = 0;
00598     memcpy((char *) &tmp, buf, len);
00599     cksum += tmp;
00600   }
00601 
00602   return cksum;
00603 }
00604 #endif
00605 
00606 
00607 // int HdrHeap::marshal(char* buf, int len)
00608 //
00609 //   Creates a marshalled representation of the contents
00610 //     of HdrHeap.  The marshalled representation is ususable
00611 //     as a read-only HdrHeap after an unmarshal operation which
00612 //     only swizzles offsets to pointer.  Special care needs to be
00613 //     taken not to mess up the alignment of objects in
00614 //     the heap to make this representation usable in the read-only
00615 //     form
00616 //
00617 int
00618 HdrHeap::marshal(char *buf, int len)
00619 {
00620   ink_assert((((uintptr_t) buf) & HDR_PTR_ALIGNMENT_MASK) == 0);
00621 
00622   HdrHeap *marshal_hdr = (HdrHeap *) buf;
00623   char *b = buf + HDR_HEAP_HDR_SIZE;
00624 
00625   // Variables for the ptr translation table
00626   int ptr_xl_size = 2;
00627   MarshalXlate static_table[2];
00628   MarshalXlate *ptr_xlation = static_table;
00629 
00630   // Let's start by skipping over the header block
00631   //  and copying the pointer blocks to marshalled
00632   //  buffer
00633   int ptr_heap_size = 0;
00634   int str_size = 0;
00635   int ptr_heaps = 0;
00636   int str_heaps = 0;
00637 
00638   // Variables used later on.  Sunpro doesn't like
00639   //   bypassing initializations with gotos
00640   int used;
00641   int i;
00642 
00643   HdrHeap *unmarshal_hdr = this;
00644 
00645   do {
00646     int copy_size = (int) (unmarshal_hdr->m_free_start - unmarshal_hdr->m_data_start);
00647 
00648     if (copy_size > len) {
00649       goto Failed;
00650     }
00651     memcpy(b, unmarshal_hdr->m_data_start, copy_size);
00652 
00653     // Expand ptr xlation table if necessary - shameless hackery
00654     if (ptr_heaps >= ptr_xl_size) {
00655       MarshalXlate *tmp_xl = (MarshalXlate *) alloca(sizeof(MarshalXlate) * ptr_xl_size * 2);
00656       memcpy(tmp_xl, ptr_xlation, sizeof(MarshalXlate) * ptr_xl_size);
00657       ptr_xlation = tmp_xl;
00658       ptr_xl_size *= 2;
00659     }
00660     // Add translation table entry for pointer heaps
00661     //   FIX ME - possible offset overflow issues?
00662     ptr_xlation[ptr_heaps].start = unmarshal_hdr->m_data_start;
00663     ptr_xlation[ptr_heaps].end = unmarshal_hdr->m_free_start;
00664     ptr_xlation[ptr_heaps].offset = unmarshal_hdr->m_data_start - (b - buf);
00665 
00666     ptr_heap_size += copy_size;
00667     b += copy_size;
00668     len -= copy_size;
00669     ptr_heaps++;
00670 
00671     unmarshal_hdr = unmarshal_hdr->m_next;
00672   } while (unmarshal_hdr);
00673 
00674   // Now that we've got the pointer blocks marshaled
00675   //  we can fill in the header on marshalled block
00676   marshal_hdr->m_free_start = NULL;
00677   marshal_hdr->m_data_start = (char *) HDR_HEAP_HDR_SIZE;       // offset
00678   marshal_hdr->m_magic = HDR_BUF_MAGIC_MARSHALED;
00679   marshal_hdr->m_writeable = false;
00680   marshal_hdr->m_size = ptr_heap_size + HDR_HEAP_HDR_SIZE;
00681   marshal_hdr->m_next = NULL;
00682   marshal_hdr->m_free_size = 0;
00683   marshal_hdr->m_read_write_heap.m_ptr = NULL;
00684   marshal_hdr->m_lost_string_space = this->m_lost_string_space;
00685 
00686   // We'have one read-only string heap after marshalling
00687   marshal_hdr->m_ronly_heap[0].m_heap_start = (char *)(intptr_t)marshal_hdr->m_size;     // offset
00688   marshal_hdr->m_ronly_heap[0].m_ref_count_ptr.m_ptr = NULL;
00689 
00690   for (int i = 1; i < HDR_BUF_RONLY_HEAPS; i++)
00691     marshal_hdr->m_ronly_heap[i].m_heap_start = NULL;
00692 
00693   // Next order of business is to copy over string heaps
00694   //   As we are copying over the string heaps, build
00695   //   translation table for string marshaling in the heap
00696   //   objects
00697   //
00698   // FIX ME - really ought to check to see if lost_string_space
00699   //   is too big and only copy over live strings if it is.  May
00700   //   not be too much of a problem since I've prevented too much
00701   //   lost string space both in string alloc and inherit
00702   MarshalXlate str_xlation[HDR_BUF_RONLY_HEAPS + 1];
00703 
00704   if (m_read_write_heap) {
00705     char *copy_start = ((char *) m_read_write_heap.m_ptr) + sizeof(HdrStrHeap);
00706     int nto_copy = m_read_write_heap->m_heap_size - (sizeof(HdrStrHeap) + m_read_write_heap->m_free_size);
00707 
00708     if (nto_copy > len) {
00709       goto Failed;
00710     }
00711 
00712     memcpy(b, copy_start, nto_copy);
00713 
00714     // FIX ME - possible offset overflow issues?
00715     str_xlation[str_heaps].start = copy_start;
00716     str_xlation[str_heaps].end = copy_start + nto_copy;
00717     str_xlation[str_heaps].offset = copy_start - (b - buf);
00718 
00719     b += nto_copy;
00720     len -= nto_copy;
00721     str_size += nto_copy;
00722     str_heaps++;
00723   }
00724 
00725   for (i = 0; i < HDR_BUF_RONLY_HEAPS; i++) {
00726     if (m_ronly_heap[i].m_heap_start != NULL) {
00727       if (m_ronly_heap[i].m_heap_len > len) {
00728         goto Failed;
00729       }
00730 
00731       memcpy(b, m_ronly_heap[i].m_heap_start, m_ronly_heap[i].m_heap_len);
00732 
00733       // Add translation table entry for string heaps
00734       //   FIX ME - possible offset overflow issues?
00735       str_xlation[str_heaps].start = m_ronly_heap[i].m_heap_start;
00736       str_xlation[str_heaps].end = m_ronly_heap[i].m_heap_start + m_ronly_heap[i].m_heap_len;
00737       str_xlation[str_heaps].offset = str_xlation[str_heaps].start - (b - buf);
00738       ink_assert(str_xlation[str_heaps].start <= str_xlation[str_heaps].end);
00739 
00740       str_heaps++;
00741       b += m_ronly_heap[i].m_heap_len;
00742       len -= m_ronly_heap[i].m_heap_len;
00743       str_size += m_ronly_heap[i].m_heap_len;
00744     }
00745   }
00746 
00747   // Patch the str heap len
00748   marshal_hdr->m_ronly_heap[0].m_heap_len = str_size;
00749 
00750   // Take our translation tables and loop over the objects
00751   //    and call the object marshal function to patch live
00752   //    strings pointers & live object pointers to offsets
00753   {
00754     char *obj_data = ((char *) marshal_hdr) + HDR_HEAP_HDR_SIZE;
00755     char *mheap_end = ((char *) marshal_hdr) + marshal_hdr->m_size;
00756 
00757     while (obj_data < mheap_end) {
00758       HdrHeapObjImpl *obj = (HdrHeapObjImpl *) obj_data;
00759       ink_assert(obj_is_aligned(obj));
00760 
00761       switch (obj->m_type) {
00762       case HDR_HEAP_OBJ_URL:
00763         if (((URLImpl *) obj)->marshal(str_xlation, str_heaps) < 0) {
00764           goto Failed;
00765         }
00766         break;
00767       case HDR_HEAP_OBJ_HTTP_HEADER:
00768         if (((HTTPHdrImpl *) obj)->marshal(ptr_xlation, ptr_heaps, str_xlation, str_heaps) < 0) {
00769           goto Failed;
00770         }
00771         break;
00772       case HDR_HEAP_OBJ_FIELD_BLOCK:
00773         if (((MIMEFieldBlockImpl *) obj)->marshal(ptr_xlation, ptr_heaps, str_xlation, str_heaps) < 0) {
00774           goto Failed;
00775         }
00776         break;
00777       case HDR_HEAP_OBJ_MIME_HEADER:
00778         if (((MIMEHdrImpl *) obj)->marshal(ptr_xlation, ptr_heaps, str_xlation, str_heaps)) {
00779           goto Failed;
00780         }
00781         break;
00782       case HDR_HEAP_OBJ_EMPTY:
00783       case HDR_HEAP_OBJ_RAW:
00784         // Check to make sure we aren't stuck
00785         //   in an infinite loop
00786         if (obj->m_length <= 0) {
00787           ink_assert(0);
00788           goto Failed;
00789         }
00790         // Nothing to do
00791         break;
00792       default:
00793         ink_release_assert(0);
00794       }
00795 
00796       obj_data = obj_data + obj->m_length;
00797     }
00798   }
00799 
00800   // Add up the total bytes used
00801   used = ptr_heap_size + str_size + HDR_HEAP_HDR_SIZE;
00802   used = ROUND(used, HDR_PTR_SIZE);
00803 
00804 #ifdef HDR_HEAP_CHECKSUMS
00805   {
00806     uint32_t chksum = compute_checksum(buf, used);
00807     marshal_hdr->m_free_start = (char *) chksum;
00808   }
00809 #endif
00810 
00811   return used;
00812 
00813 Failed:
00814   marshal_hdr->m_magic = HDR_BUF_MAGIC_CORRUPT;
00815   return -1;
00816 }
00817 
00818 
00819 // bool HdrHeap::check_marshalled(char* buf, int buf_length) {
00820 //
00821 //   Takes in marshalled buffer and verifies whether stuff appears
00822 //     to be sane.  Returns true is sane.  Returns false if corrupt
00823 //
00824 bool
00825 HdrHeap::check_marshalled(uint32_t buf_length)
00826 {
00827   if (this->m_magic != HDR_BUF_MAGIC_MARSHALED) {
00828     return false;
00829   }
00830 
00831   if (this->m_size < (uint32_t) HDR_HEAP_HDR_SIZE) {
00832     return false;
00833   }
00834 
00835   if (this->m_size != (uintptr_t) this->m_ronly_heap[0].m_heap_start) {
00836     return false;
00837   }
00838 
00839   if ((uintptr_t) (this->m_size + m_ronly_heap[0].m_heap_start) > buf_length) {
00840     return false;
00841   }
00842 
00843   if (this->m_writeable != false) {
00844     return false;
00845   }
00846 
00847   if (this->m_free_size != 0) {
00848     return false;
00849   }
00850 
00851   if (this->m_ronly_heap[0].m_heap_start == NULL) {
00852     return false;
00853   }
00854 
00855   return true;
00856 }
00857 
00858 // int HdrHeap::unmarshal(int buf_length, int obj_type,
00859 //                       HdrHeapObjImpl** found_obj,
00860 //                       RefCountObj* block_ref) {
00861 //
00862 //   Takes a marshalled representation and swizzles offsets
00863 //     so they become live pointers and make the heap usable.
00864 //     Sets *found_obj to first occurance of object of
00865 //     type obj_type in the heap
00866 //
00867 //   Return value is the number of bytes unmarshalled or -1
00868 //     if error.  Caller is responsible for memory
00869 //     management policy
00870 //
00871 int
00872 HdrHeap::unmarshal(int buf_length, int obj_type, HdrHeapObjImpl ** found_obj, RefCountObj * block_ref)
00873 {
00874   bool obj_found = false;
00875 
00876   // Check out this heap and make sure it is OK
00877   if (m_magic != HDR_BUF_MAGIC_MARSHALED) {
00878     ink_assert(!"HdrHeap::unmarshal bad magic");
00879     return -1;
00880   }
00881 
00882   int unmarshal_size = this->unmarshal_size();
00883   if (unmarshal_size > buf_length) {
00884     ink_assert(!"HdrHeap::unmarshal truncated header");
00885     return -1;
00886   }
00887 #ifdef HDR_HEAP_CHECKSUMS
00888   if (m_free_start != NULL) {
00889     uint32_t stored_sum = (uint32_t) m_free_start;
00890     m_free_start = NULL;
00891     int sum_len = ROUND(unmarshal_size, HDR_PTR_SIZE);
00892     uint32_t new_sum = compute_checksum((void *) this, sum_len);
00893 
00894     if (stored_sum != new_sum) {
00895       fprintf(stderr, "WARNING: Unmarshal checksum comparison failed\n");
00896       dump_heap(unmarshal_size);
00897       ink_assert(!"HdrHeap::unmarshal checksum failure");
00898       return -1;
00899     }
00900   }
00901 #else
00902   // Because checksums could have been enabled in the past
00903   //   and then be turned off without clearing the cache,
00904   //   always reset our variable we use for checksumming
00905   m_free_start = NULL;
00906 #endif
00907 
00908   ink_release_assert(m_writeable == false);
00909   ink_release_assert(m_free_size == 0);
00910   ink_release_assert(m_ronly_heap[0].m_heap_start != NULL);
00911 
00912   ink_assert(m_free_start == NULL);
00913 
00914   // Convert Heap offsets to pointers
00915   m_data_start = ((char *) this) + (intptr_t) m_data_start;
00916   m_free_start = ((char *) this) + m_size;
00917   m_ronly_heap[0].m_heap_start = ((char *) this) + (intptr_t) m_ronly_heap[0].m_heap_start;
00918 
00919   // Crazy Invarient - If we are sitting in a ref counted block,
00920   //   the HdrHeap lifetime is externally determined.  Whoever
00921   //   unmarshalls us should keep the block around as long as
00922   //   they want to use the header.  However, the strings can
00923   //   live beyond the heap life time because they are copied
00924   //   by reference into other header heap therefore we need
00925   //   to the set the refcount ptr for the strings.  We don't
00926   //   actually increase the refcount here since for the header
00927   //   the lifetime is explicit but copies will increase
00928   //   the refcount
00929   if (block_ref) {
00930     m_ronly_heap[0].m_ref_count_ptr.m_ptr = block_ref;
00931   }
00932   // Loop over objects and swizzle there pointer to
00933   //  live offsets
00934   char *obj_data = m_data_start;
00935   intptr_t offset = (intptr_t) this;
00936 
00937   while (obj_data < m_free_start) {
00938     HdrHeapObjImpl *obj = (HdrHeapObjImpl *) obj_data;
00939     ink_assert(obj_is_aligned(obj));
00940 
00941     if (obj->m_type == (unsigned) obj_type && obj_found == false) {
00942       *found_obj = obj;
00943     }
00944 
00945     switch (obj->m_type) {
00946     case HDR_HEAP_OBJ_HTTP_HEADER:
00947       ((HTTPHdrImpl *) obj)->unmarshal(offset);
00948       break;
00949     case HDR_HEAP_OBJ_URL:
00950       ((URLImpl *) obj)->unmarshal(offset);
00951       break;
00952     case HDR_HEAP_OBJ_FIELD_BLOCK:
00953       ((MIMEFieldBlockImpl *) obj)->unmarshal(offset);
00954       break;
00955     case HDR_HEAP_OBJ_MIME_HEADER:
00956       ((MIMEHdrImpl *) obj)->unmarshal(offset);
00957       break;
00958     case HDR_HEAP_OBJ_EMPTY:
00959       // Nothing to do
00960       break;
00961     default:
00962       fprintf(stderr,
00963               "WARNING: Unmarshal failed due to unknow obj type %d after %d bytes",
00964               (int) obj->m_type, (int)(obj_data - (char *) this));
00965       dump_heap(unmarshal_size);
00966       return -1;
00967     }
00968 
00969     obj_data = obj_data + obj->m_length;
00970   }
00971 
00972   m_magic = HDR_BUF_MAGIC_ALIVE;
00973 
00974   unmarshal_size = ROUND(unmarshal_size, HDR_PTR_SIZE);
00975   return unmarshal_size;
00976 }
00977 
00978 inline int
00979 HdrHeap::attach_str_heap(char *h_start, int h_len, RefCountObj * h_ref_obj, int *index)
00980 {
00981   // Loop over existing entries to see if this one is already present
00982   for (int z = 0; z < *index; z++) {
00983     if (m_ronly_heap[z].m_heap_start == h_start) {
00984       ink_assert(m_ronly_heap[z].m_ref_count_ptr._ptr() == h_ref_obj);
00985 
00986       // The lengths could be different because our copy could be
00987       //   read-only and the copy we are attaching from could be
00988       //   read-write and have expanded since the last time
00989       //   to was attached
00990       if (h_len > m_ronly_heap[z].m_heap_len)
00991         m_ronly_heap[z].m_heap_len = h_len;
00992       return 1;
00993     }
00994   }
00995 
00996   if (*index >= HDR_BUF_RONLY_HEAPS) {
00997     return 0;
00998   }
00999 
01000   m_ronly_heap[*index].m_ref_count_ptr = h_ref_obj;
01001   m_ronly_heap[*index].m_heap_start = h_start;
01002   m_ronly_heap[*index].m_heap_len = h_len;
01003   m_ronly_heap[*index].m_locked = false;
01004   *index = *index + 1;
01005 
01006   return 1;
01007 }
01008 
01009 
01010 // void HdrHeap::inhertit_string_heaps(const HdrHeap* inherit_from)
01011 //
01012 //    Inherits all of inherit_from's string heaps as read-only
01013 //     string heaps
01014 //
01015 void
01016 HdrHeap::inherit_string_heaps(const HdrHeap * inherit_from)
01017 {
01018   // if heaps are the same, this is a no-op
01019   if (inherit_from == (const HdrHeap *) this)
01020     return;
01021 
01022   int index, result;
01023   int first_free = HDR_BUF_RONLY_HEAPS; // default is out of array bounds
01024   int free_slots = 0;
01025   int inherit_str_size = 0;
01026   ink_assert(m_writeable);
01027 
01028   // Find the number of free heap slots & the first open index
01029   for (index = 0; index < HDR_BUF_RONLY_HEAPS; index++) {
01030     if (m_ronly_heap[index].m_heap_start == NULL) {
01031       if (first_free == HDR_BUF_RONLY_HEAPS) {
01032         first_free = index;
01033       }
01034       free_slots++;
01035     }
01036   }
01037 
01038   // Find out if we have enough slots
01039   if (inherit_from->m_read_write_heap) {
01040     free_slots--;
01041     inherit_str_size = inherit_from->m_read_write_heap->m_heap_size;
01042   }
01043   for (index = 0; index < HDR_BUF_RONLY_HEAPS; index++) {
01044     if (inherit_from->m_ronly_heap[index].m_heap_start != NULL) {
01045       free_slots--;
01046       inherit_str_size += inherit_from->m_ronly_heap[index].m_heap_len;
01047     } else {
01048       // Heaps are allocated from the front of the array, so if
01049       //  we hit a NULL, we know we can stop
01050       break;
01051     }
01052   }
01053 
01054   // Find out if we are building up too much lost space
01055   int new_lost_space = m_lost_string_space + inherit_from->m_lost_string_space;
01056 
01057   if (free_slots < 0 || new_lost_space > (int)MAX_LOST_STR_SPACE) {
01058     // Not enough free slots.  We need to force a coalesce of
01059     //  string heaps for both old heaps and the inherited from heaps.
01060     // Coalesce can't know the inherited str size so we pass it
01061     //  it in so that it can allocate a new read-write string heap
01062     //  large enough (INKqa07513).
01063     // INVARIENT: inherit_str_heaps can only be called after
01064     //  all the objects the callee wants to inherit strings for
01065     //  are put into the heap
01066     coalesce_str_heaps(inherit_str_size);
01067   } else {
01068     // Copy over read/write string heap if it exists
01069     if (inherit_from->m_read_write_heap) {
01070       int str_size = inherit_from->m_read_write_heap->m_heap_size -
01071         STR_HEAP_HDR_SIZE - inherit_from->m_read_write_heap->m_free_size;
01072       result = attach_str_heap(((char *) inherit_from->m_read_write_heap.m_ptr) + STR_HEAP_HDR_SIZE,
01073                                str_size, inherit_from->m_read_write_heap, &first_free);
01074       ink_release_assert(result != 0);
01075     }
01076     // Copy over read only string heaps
01077     for (int i = 0; i < HDR_BUF_RONLY_HEAPS; i++) {
01078       if (inherit_from->m_ronly_heap[i].m_heap_start) {
01079         result = attach_str_heap(inherit_from->m_ronly_heap[i].m_heap_start,
01080                                  inherit_from->m_ronly_heap[i].m_heap_len,
01081                                  inherit_from->m_ronly_heap[i].m_ref_count_ptr.m_ptr, &first_free);
01082         ink_release_assert(result != 0);
01083       }
01084     }
01085 
01086     m_lost_string_space += inherit_from->m_lost_string_space;
01087   }
01088 
01089   return;
01090 }
01091 
01092 // void HdrHeap::dump_heap(int len)
01093 //
01094 //   Debugging function to dump the heap in hex
01095 void
01096 HdrHeap::dump_heap(int len)
01097 {
01098   int count = 0;
01099   char *tmp = (char *) this;
01100   char *end;
01101   uint32_t content;
01102 
01103   if (len < 0) {
01104     len = m_size;
01105   }
01106   end = ((char *) this) + len;
01107 
01108   fprintf(stderr, "---- Dumping header heap @ 0x%" PRIx64 " - len %d ------", (uint64_t) ((ptrdiff_t) this), len);
01109 
01110   while (tmp < end) {
01111     if (count % 4 == 0) {
01112       fprintf(stderr, "\n0x%" PRIx64 ": ", (uint64_t) ((ptrdiff_t) tmp));
01113     }
01114     count++;
01115 
01116     // Load the content
01117     if (end - tmp > 4) {
01118       content = *((uint32_t *) tmp);
01119     } else {
01120       // Less than 4 bytes available so just
01121       //   grab the bytes we need
01122       content = 0;
01123       memcpy(&content, tmp, (end - tmp));
01124     }
01125 
01126     fprintf(stderr, "0x%x ", content);
01127     tmp += 4;
01128   }
01129 
01130   fprintf(stderr, "\n-------------- End header heap dump -----------\n");
01131 }
01132 
01133 
01134 void
01135 HdrStrHeap::free()
01136 {
01137   if (m_heap_size == HDR_STR_HEAP_DEFAULT_SIZE) {
01138     THREAD_FREE(this, strHeapAllocator, this_thread());
01139   } else {
01140     ats_free(this);
01141   }
01142 }
01143 
01144 // char* HdrStrHeap::allocate(int nbytes)
01145 //
01146 //   Allocates nbytes from the str heap
01147 //   Return NULL on allocation failure
01148 //
01149 char *
01150 HdrStrHeap::allocate(int nbytes)
01151 {
01152   char *new_space;
01153 
01154   if (m_free_size >= (unsigned) nbytes) {
01155     new_space = m_free_start;
01156     m_free_start += nbytes;
01157     m_free_size -= nbytes;
01158     return new_space;
01159   } else {
01160     return NULL;
01161   }
01162 }
01163 
01164 // char* HdrStrHeap::expand(char* ptr, int old_size, int new_size)
01165 //
01166 //   Try to expand str in the heap.  If we succeed to
01167 //     we return ptr, otherwise we return NULL
01168 //
01169 char *
01170 HdrStrHeap::expand(char *ptr, int old_size, int new_size)
01171 {
01172   unsigned int expand_size = new_size - old_size;
01173 
01174   ink_assert(ptr >= ((char *) this) + STR_HEAP_HDR_SIZE);
01175   ink_assert(ptr < ((char *) this) + m_heap_size);
01176 
01177   if (ptr + old_size == m_free_start && expand_size <= m_free_size) {
01178     m_free_start += expand_size;
01179     m_free_size -= expand_size;
01180     return ptr;
01181   } else {
01182     return NULL;
01183   }
01184 }
01185 
01186 
01187 
01188 StrHeapDesc::StrHeapDesc()
01189 {
01190   m_heap_start = NULL;
01191   m_heap_len = 0;
01192   m_locked = false;
01193 }
01194 
01195 struct StrTest
01196 {
01197   char *ptr;
01198   int len;
01199 };
01200 
01201 #if TS_HAS_TESTS
01202 #include <ts/TestBox.h>
01203 REGRESSION_TEST(HdrHeap_Coalesce)(RegressionTest* t, int /* atype ATS_UNUSED */, int*  pstatus) {
01204   *pstatus = REGRESSION_TEST_PASSED;
01205   /*
01206    * This test is designed to test numerous pieces of the HdrHeaps including allocations,
01207    * demotion of rw heaps to ronly heaps, and finally the coalesce and evacuate behaviours.
01208    */
01209 
01210   // The amount of space we will need to overflow the StrHdrHeap is HDR_STR_HEAP_DEFAULT_SIZE - STR_HEAP_HDR_SIZE
01211   size_t next_rw_heap_size = HDR_STR_HEAP_DEFAULT_SIZE;
01212   size_t next_required_overflow_size = next_rw_heap_size - STR_HEAP_HDR_SIZE;
01213   char buf[next_required_overflow_size];
01214   for(unsigned int i = 0; i < sizeof(buf); ++i) {
01215     buf[i] = ('a' + (i % 26));
01216   }
01217 
01218   TestBox tb(t, pstatus);
01219   HdrHeap *heap = new_HdrHeap();
01220   URLImpl *url = url_create(heap);
01221 
01222   tb.check(heap->m_read_write_heap.m_ptr == NULL, "Checking that we have no rw heap.");
01223   url_path_set(heap,url, buf, next_required_overflow_size, true);
01224   tb.check(heap->m_read_write_heap->m_free_size == 0, "Checking that we've completely consumed the rw heap");
01225   for (int i = 0; i < HDR_BUF_RONLY_HEAPS; ++i) {
01226     tb.check(heap->m_ronly_heap[i].m_heap_start == (char*)NULL, "Checking ronly_heap[%d] is NULL", i);
01227   }
01228 
01229   // Now we have no ronly heaps in use and a completely full rwheap, so we will test that
01230   // we demote to ronly heaps HDR_BUF_RONLY_HEAPS times.
01231   for (int ronly_heap = 0; ronly_heap < HDR_BUF_RONLY_HEAPS; ++ronly_heap) {
01232     next_rw_heap_size = 2 * heap->m_read_write_heap->m_heap_size;
01233     next_required_overflow_size = next_rw_heap_size - STR_HEAP_HDR_SIZE;
01234     char buf2[next_required_overflow_size];
01235     for(unsigned int i = 0; i < sizeof(buf2); ++i) {
01236       buf2[i] = ('a' + (i % 26));
01237     }
01238 
01239     URLImpl *url2 = url_create(heap);
01240     url_path_set(heap,url2,buf2,next_required_overflow_size, true);
01241 
01242     tb.check(heap->m_read_write_heap->m_heap_size == (uint32_t)next_rw_heap_size, "Checking the current rw heap is %d bytes", (int)next_rw_heap_size);
01243     tb.check(heap->m_read_write_heap->m_free_size == 0, "Checking that we've completely consumed the rw heap");
01244     tb.check(heap->m_ronly_heap[ronly_heap].m_heap_start != NULL, "Checking that we properly demoted the previous rw heap");
01245     for (int i = ronly_heap + 1; i < HDR_BUF_RONLY_HEAPS; ++i) {
01246       tb.check(heap->m_ronly_heap[i].m_heap_start == NULL, "Checking ronly_heap[%d] is NULL", i);
01247     }
01248   }
01249 
01250   // We will rerun these checks after we introduce a non-copied string to make sure we didn't already coalesce
01251   for (int i = 0; i < HDR_BUF_RONLY_HEAPS; ++i) {
01252     tb.check(heap->m_ronly_heap[i].m_heap_start != (char*)NULL, "Pre non-copied string: Checking ronly_heap[%d] is NOT NULL", i);
01253   }
01254 
01255   // Now if we add a url object that contains only non-copied strings it shouldn't affect the size of the rwheap
01256   // since it doesn't require allocating any storage on this heap.
01257   char buf3[next_required_overflow_size];
01258   for(unsigned int i = 0; i < sizeof(buf); ++i) {
01259     buf3[i] = ('a' + (i % 26));
01260   }
01261 
01262   URLImpl *aliased_str_url = url_create(heap);
01263   url_path_set(heap, aliased_str_url, buf3, next_required_overflow_size, false); // don't copy this string
01264   tb.check(aliased_str_url->m_len_path == next_required_overflow_size, "Checking that the aliased string shows having proper length");
01265   tb.check(aliased_str_url->m_ptr_path == buf3, "Checking that the aliased string is correctly pointing at buf");
01266 
01267 
01268   for (int i = 0; i < HDR_BUF_RONLY_HEAPS; ++i) {
01269     tb.check(heap->m_ronly_heap[i].m_heap_start != (char*)NULL, "Post non-copied string: Checking ronly_heap[%d] is NOT NULL", i);
01270   }
01271   tb.check(heap->m_read_write_heap->m_free_size == 0, "Checking that we've completely consumed the rw heap");
01272   tb.check(heap->m_next == NULL, "Checking that we dont have any chained heaps");
01273 
01274   // Now at this point we have a completely full rw_heap and no ronly heap slots, so any allocation would have to result
01275   // in a coalesce, and to validate that we don't reintroduce TS-2766 we have an aliased string, so when it tries to
01276   // coalesce it used to sum up the size of the ronly heaps and the rw heap which is incorrect because we never
01277   // copied the above string onto the heap. The new behaviour fixed in TS-2766 will make sure that this non copied
01278   // string is accounted for, in the old implementation it would result in an allocation failure.
01279 
01280 
01281   char *str = heap->allocate_str(1); // this will force a coalese.
01282   tb.check(str != NULL, "Checking that 1 byte allocated string is not NULL");
01283 
01284   // Now we need to validate that aliased_str_url has a path that isn't NULL, if it's NULL then the
01285   // coalesce is broken and didn't properly determine the size, if it's not null then everything worked as expected.
01286   tb.check(aliased_str_url->m_len_path == next_required_overflow_size, "Checking that the aliased string shows having proper length");
01287   tb.check(aliased_str_url->m_ptr_path != NULL, "Checking that the aliased string was properly moved during coalsece and evacuation");
01288   tb.check(aliased_str_url->m_ptr_path != buf3, "Checking that the aliased string was properly moved during coalsece and evacuation (not pointing at buf3)");
01289 
01290   // Clean up
01291   heap->destroy();
01292 }
01293 #endif

Generated by  doxygen 1.7.1