| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2011, Google Inc. | 
|  | 2 // All rights reserved. | 
|  | 3 // | 
|  | 4 // Redistribution and use in source and binary forms, with or without | 
|  | 5 // modification, are permitted provided that the following conditions are | 
|  | 6 // met: | 
|  | 7 // | 
|  | 8 //     * Redistributions of source code must retain the above copyright | 
|  | 9 // notice, this list of conditions and the following disclaimer. | 
|  | 10 //     * Redistributions in binary form must reproduce the above | 
|  | 11 // copyright notice, this list of conditions and the following disclaimer | 
|  | 12 // in the documentation and/or other materials provided with the | 
|  | 13 // distribution. | 
|  | 14 //     * Neither the name of Google Inc. nor the names of its | 
|  | 15 // contributors may be used to endorse or promote products derived from | 
|  | 16 // this software without specific prior written permission. | 
|  | 17 // | 
|  | 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | 29 | 
|  | 30 // --- | 
|  | 31 // Author: Rebecca Shapiro <bxx@google.com> | 
|  | 32 // | 
|  | 33 // This file contains functions that implement doubly linked and | 
|  | 34 // singly linked lists.  The singly linked lists are null terminated, | 
|  | 35 // use raw pointers to link neighboring elements, and these pointers | 
|  | 36 // are stored at the start of each element, independently of the | 
|  | 37 // elements's size.  Because pointers are stored within each element, | 
|  | 38 // each element must be large enough to store two raw pointers if | 
|  | 39 // doubly linked lists are employed, or one raw pointer if singly | 
|  | 40 // linked lists are employed.  On machines with 64 bit pointers, this | 
|  | 41 // means elements must be at least 16 bytes in size for doubly linked | 
|  | 42 // list support, and 8 bytes for singly linked list support.  No | 
|  | 43 // attempts are made to preserve the data in elements stored in the | 
|  | 44 // list. | 
|  | 45 // | 
|  | 46 // Given a machine with pointers of size N (on a 64bit machine N=8, on | 
|  | 47 // a 32bit machine, N=4), the list pointers are stored in the | 
|  | 48 // following manner: | 
|  | 49 // -In doubly linked lists, the |next| pointer is stored in the first N | 
|  | 50 // bytes of the node and the |previous| pointer is writtend into the | 
|  | 51 // second N bytes. | 
|  | 52 // -In singly linked lists, the |next| pointer is stored in the first N | 
|  | 53 // bytes of the node. | 
|  | 54 // | 
|  | 55 // For both types of lists: when a pop operation is performed on a non | 
|  | 56 // empty list, the new list head becomes that which is pointed to by | 
|  | 57 // the former head's |next| pointer.  If the list is doubly linked, the | 
|  | 58 // new head |previous| pointer gets changed from pointing to the former | 
|  | 59 // head to NULL. | 
|  | 60 | 
|  | 61 | 
|  | 62 #ifdef TCMALLOC_USE_DOUBLYLINKED_FREELIST | 
|  | 63 | 
|  | 64 #include <stddef.h> | 
|  | 65 #include "internal_logging.h" //for ASSERT | 
|  | 66 | 
|  | 67 #define MEMORY_CHECK(v1, v2) \ | 
|  | 68   if (v1 != v2) CRASH("Memory corruption detected.\n") | 
|  | 69 | 
|  | 70 namespace { | 
|  | 71 // Returns value of the |previous| pointer w/out running a sanity | 
|  | 72 // check. | 
|  | 73 inline void *FL_Previous_No_Check(void *t) { | 
|  | 74   return reinterpret_cast<void**>(t)[1]; | 
|  | 75 } | 
|  | 76 | 
|  | 77 // Returns value of the |next| pointer w/out running a sanity check. | 
|  | 78 inline void *FL_Next_No_Check(void *t) { | 
|  | 79   return reinterpret_cast<void**>(t)[0]; | 
|  | 80 } | 
|  | 81 | 
|  | 82 void *FL_Previous(void *t) { | 
|  | 83   void *previous = FL_Previous_No_Check(t); | 
|  | 84   if (previous) { | 
|  | 85     MEMORY_CHECK(FL_Next_No_Check(previous), t); | 
|  | 86   } | 
|  | 87   return previous; | 
|  | 88 } | 
|  | 89 | 
|  | 90 inline void FL_SetPrevious(void *t, void *n) { | 
|  | 91   reinterpret_cast<void**>(t)[1] = n; | 
|  | 92 } | 
|  | 93 | 
|  | 94 inline void FL_SetNext(void *t, void *n) { | 
|  | 95   reinterpret_cast<void**>(t)[0] = n; | 
|  | 96 } | 
|  | 97 | 
|  | 98 } // namespace | 
|  | 99 | 
|  | 100 namespace tcmalloc { | 
|  | 101 | 
|  | 102 void *FL_Next(void *t) { | 
|  | 103   void *next = FL_Next_No_Check(t); | 
|  | 104   if (next) { | 
|  | 105     MEMORY_CHECK(FL_Previous_No_Check(next), t); | 
|  | 106   } | 
|  | 107   return next; | 
|  | 108 } | 
|  | 109 | 
|  | 110 // Makes the element at |t| a singleton doubly linked list. | 
|  | 111 void FL_Init(void *t) { | 
|  | 112   FL_SetPrevious(t, NULL); | 
|  | 113   FL_SetNext(t, NULL); | 
|  | 114 } | 
|  | 115 | 
|  | 116 // Pushes element to a linked list whose first element is at | 
|  | 117 // |*list|. When this call returns, |list| will point to the new head | 
|  | 118 // of the linked list. | 
|  | 119 void FL_Push(void **list, void *element) { | 
|  | 120   void *old = *list; | 
|  | 121   if (old == NULL) { // Builds singleton list. | 
|  | 122     FL_Init(element); | 
|  | 123   } else { | 
|  | 124     ASSERT(FL_Previous_No_Check(old) == NULL); | 
|  | 125     FL_SetNext(element, old); | 
|  | 126     FL_SetPrevious(old, element); | 
|  | 127     FL_SetPrevious(element, NULL); | 
|  | 128   } | 
|  | 129   *list = element; | 
|  | 130 } | 
|  | 131 | 
|  | 132 // Pops the top element off the linked list whose first element is at | 
|  | 133 // |*list|, and updates |*list| to point to the next element in the | 
|  | 134 // list.  Returns the address of the element that was removed from the | 
|  | 135 // linked list.  |list| must not be NULL. | 
|  | 136 void *FL_Pop(void **list) { | 
|  | 137   void *result = *list; | 
|  | 138   ASSERT(FL_Previous_No_Check(result) == NULL); | 
|  | 139   *list = FL_Next(result); | 
|  | 140   if (*list != NULL) { | 
|  | 141     FL_SetPrevious(*list, NULL); | 
|  | 142   } | 
|  | 143   return result; | 
|  | 144 } | 
|  | 145 | 
|  | 146 // Remove |n| elements from linked list at whose first element is at | 
|  | 147 // |*head|.  |head| will be modified to point to the new head. | 
|  | 148 // |start| will point to the first node of the range, |end| will point | 
|  | 149 // to the last node in the range. |n| must be <= FL_Size(|*head|) | 
|  | 150 // If |n| > 0, |head| must not be NULL. | 
|  | 151 void FL_PopRange(void **head, int n, void **start, void **end) { | 
|  | 152   if (n == 0) { | 
|  | 153     *start = NULL; | 
|  | 154     *end = NULL; | 
|  | 155     return; | 
|  | 156   } | 
|  | 157 | 
|  | 158   *start = *head; // Remember the first node in the range. | 
|  | 159   void *tmp = *head; | 
|  | 160   for (int i = 1; i < n; ++i) { // Find end of range. | 
|  | 161     tmp = FL_Next(tmp); | 
|  | 162   } | 
|  | 163   *end = tmp; // |end| now set to point to last node in range. | 
|  | 164   *head = FL_Next(*end); | 
|  | 165   FL_SetNext(*end, NULL); // Unlink range from list. | 
|  | 166 | 
|  | 167   if (*head ) { // Fixup popped list. | 
|  | 168     FL_SetPrevious(*head, NULL); | 
|  | 169   } | 
|  | 170 } | 
|  | 171 | 
|  | 172 // Pushes the nodes in the list begginning at |start| whose last node | 
|  | 173 // is |end| into the linked list at |*head|. |*head| is updated to | 
|  | 174 // point be the new head of the list.  |head| must not be NULL. | 
|  | 175 void FL_PushRange(void **head, void *start, void *end) { | 
|  | 176   if (!start) return; | 
|  | 177 | 
|  | 178   // Sanity checking of ends of list to push is done by calling | 
|  | 179   // FL_Next and FL_Previous. | 
|  | 180   FL_Next(start); | 
|  | 181   FL_Previous(end); | 
|  | 182   ASSERT(FL_Previous_No_Check(start) == NULL); | 
|  | 183   ASSERT(FL_Next_No_Check(end) == NULL); | 
|  | 184 | 
|  | 185   if (*head) { | 
|  | 186     MEMORY_CHECK(FL_Previous_No_Check(*head), NULL); | 
|  | 187     FL_SetNext(end, *head); | 
|  | 188     FL_SetPrevious(*head, end); | 
|  | 189   } | 
|  | 190   *head = start; | 
|  | 191 } | 
|  | 192 | 
|  | 193 // Calculates the size of the list that begins at |head|. | 
|  | 194 size_t FL_Size(void *head){ | 
|  | 195   int count = 0; | 
|  | 196   if (head) { | 
|  | 197     MEMORY_CHECK(FL_Previous_No_Check(head), NULL); | 
|  | 198   } | 
|  | 199   while (head) { | 
|  | 200     count++; | 
|  | 201     head = FL_Next(head); | 
|  | 202   } | 
|  | 203   return count; | 
|  | 204 } | 
|  | 205 | 
|  | 206 } // namespace tcmalloc | 
|  | 207 | 
|  | 208 #else | 
|  | 209 #include "linked_list.h" // for SLL_SetNext | 
|  | 210 | 
|  | 211 namespace { | 
|  | 212 | 
|  | 213 inline void FL_SetNext(void *t, void *n) { | 
|  | 214   tcmalloc::SLL_SetNext(t,n); | 
|  | 215 } | 
|  | 216 | 
|  | 217 } | 
|  | 218 | 
|  | 219 #endif // TCMALLOC_USE_DOUBLYLINKED_FREELIST | 
| OLD | NEW | 
|---|