Menu

RawStorage.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002 *
00003 * Copyright (c) 2010 Philipp Werner <philipp.werner@st.ovgu.de>
00004 * All rights reserved.
00005 *
00006 *    Redistribution and use in source and binary forms, with or without
00007 *    modification, are permitted provided that the following conditions
00008 *    are met:
00009 *
00010 *    * Redistributions of source code must retain the above copyright
00011 *      notice, this list of conditions and the following disclaimer.
00012 *
00013 *    * Redistributions in binary form must reproduce the above copyright
00014 *      notice, this list of conditions and the following disclaimer in
00015 *      the documentation and/or other materials provided with the
00016 *      distribution.
00017 *
00018 *    * Neither the name of the copyright holders nor the names of
00019 *      contributors may be used to endorse or promote products derived
00020 *      from this software without specific prior written permission.
00021 *
00022 *
00023 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00024 *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00025 *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00026 *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027 *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028 *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029 *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030 *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031 *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032 *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033 *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 *
00036 * $Id$
00037 *
00038 ******************************************************************************/
00039 
00040 #ifndef __RAWSTORAGE_H_8AC69FC602CD2C__
00041 #define __RAWSTORAGE_H_8AC69FC602CD2C__
00042 
00043 
00044 #include <stdint.h>
00045 
00046 #include "debug.h"
00047 #include "config/type_traits/SmallestUnsignedTypeSelector.h"
00048 
00049 
00050 namespace object {
00051 
00073     template <uint64_t size>
00074     class RawStorage {
00075         public:
00077             typedef typename SmallestUnsignedTypeSelector<size>::type SizeT;
00078 
00079         protected:
00081             uint8_t data [size];
00082 
00084             SizeT first_allocated;
00085 
00087             struct AllocInfo {
00089                 SizeT block_length;
00090 
00092                 SizeT next_allocated;
00093             };
00094 
00096             AllocInfo * get_ai(SizeT offset) {
00097                 return reinterpret_cast<AllocInfo *>(data + offset);
00098             }
00099 
00107             SizeT * find_first_fit(SizeT bytes, SizeT & to_allocate) {
00108                 if (!bytes || bytes > size - sizeof(AllocInfo))
00109                     return 0;
00110 
00111                 if (bytes + sizeof(AllocInfo) <= first_allocated) {
00112                     // Allocation at the beginning
00113                     to_allocate = 0;
00114                     return &first_allocated;
00115                 } else {
00116                     // Allocation behind allocated blocks
00117 
00118                     // Add AllocInfo sizes only once (not in each comparison)
00119                     bytes += 2 * sizeof(AllocInfo);
00120 
00121                     // Check empty blocks between allocated ones
00122                     SizeT curr_ai = first_allocated;
00123                     AllocInfo * ai = get_ai(curr_ai);
00124                     while (curr_ai < size) {
00125 
00126                         if (curr_ai + ai->block_length + bytes <= ai->next_allocated) {
00127                             to_allocate = curr_ai + sizeof(AllocInfo) + ai->block_length;
00128                             return &ai->next_allocated;
00129                         }
00130 
00131                         curr_ai = ai->next_allocated;
00132                         ai = get_ai(curr_ai);
00133                     }
00134 
00135                     // If this assert fails there is a bug in this code or a buffer overflow
00136                     // in the code using the memory.
00137                     FAMOUSO_ASSERT(curr_ai == size);
00138 
00139                     // No block fits
00140                     return 0;
00141                 }
00142             }
00143 
00150             SizeT * find_allocated_block(uint8_t * p) {
00151                 p -= sizeof(AllocInfo);
00152 
00153                 SizeT * prev_ai_na_p = &first_allocated;
00154                 AllocInfo * ai = get_ai(first_allocated);
00155                 while (*prev_ai_na_p < size) {
00156 
00157                     if (ai == reinterpret_cast<AllocInfo *>(p))
00158                         return prev_ai_na_p;
00159 
00160                     prev_ai_na_p = &ai->next_allocated;
00161                     ai = get_ai(ai->next_allocated);
00162                 }
00163 
00164                 // If this assert fails there is a bug in this code or a buffer overflow
00165                 // in the code using the memory.
00166                 FAMOUSO_ASSERT(*prev_ai_na_p == size);
00167 
00168                 return 0;
00169             }
00170 
00171         public:
00173             RawStorage() : first_allocated(size) {
00174             }
00175 
00181             uint8_t * alloc(SizeT bytes) {
00182                 SizeT * next_allocated;
00183                 SizeT to_allocate;
00184                 uint8_t * mem;
00185 
00186                 // Find first fitting empty block. Returns NULL pointer if there is none.
00187                 next_allocated = find_first_fit(bytes, to_allocate);
00188 
00189                 if (next_allocated) {
00190                     // Create memory management information for newly allocated block
00191                     AllocInfo * ai = get_ai(to_allocate);
00192                     ai->block_length = bytes;
00193                     ai->next_allocated = *next_allocated;
00194 
00195                     // Update memory management information (of previous block / global)
00196                     *next_allocated = to_allocate;
00197 
00198                     // Return pointer to allocated memory block
00199                     mem = reinterpret_cast<uint8_t *>(ai) + sizeof(AllocInfo);
00200 
00201 #ifdef RAWSTORAGE_LOG_USAGE
00202                     ::logging::log::emit() << PROGMEMSTRING("RawStorage: alloc ")
00203                         << ::logging::log::dec << (int)(bytes)
00204                         << PROGMEMSTRING(" bytes  ->  offset ") << (int)to_allocate
00205                         << ::logging::log::hex << PROGMEMSTRING(", address ")
00206                         << reinterpret_cast<unsigned long>(mem) << ::logging::log::endl;
00207 #endif
00208                 } else {
00209                     // Not enough free memory
00210                     mem = 0;
00211 #ifdef RAWSTORAGE_LOG_USAGE
00212                     ::logging::log::emit() << PROGMEMSTRING("RawStorage: alloc ")
00213                         << ::logging::log::dec << (int)(bytes)
00214                         << PROGMEMSTRING(" bytes failed") << ::logging::log::endl;
00215 
00216 #endif
00217                 }
00218 
00219 #ifdef RAWSTORAGE_FULL_MEM_INFO
00220                 print_mem_info();
00221 #endif
00222 
00223                 return mem;
00224             }
00225 
00232             void free(uint8_t * p) {
00233                 SizeT * next_allocated = find_allocated_block(p);
00234 
00235                 // Check if we found a block (if pointer p is valid)
00236                 FOR_FAMOUSO_ASSERT_ONLY(bool valid_pointer = next_allocated);
00237 #ifdef RAWSTORAGE_LOG_USAGE
00238                 if (!valid_pointer) {
00239                     ::logging::log::emit() << PROGMEMSTRING("RawStorage: free address ")
00240                     << ::logging::log::hex << reinterpret_cast<unsigned long>(p)
00241                     << PROGMEMSTRING(" failed. Not alloced or freed previously.")
00242                     << ::logging::log::endl;
00243                 }
00244 #endif
00245                 FAMOUSO_ASSERT(valid_pointer);
00246 
00247                 // Alloc info to be freed... do not overwrite it
00248                 AllocInfo * ai_to_free = get_ai(*next_allocated);
00249 
00250                 // Update memory management information (of previous block / global)
00251                 *next_allocated = ai_to_free->next_allocated;
00252 
00253 #ifdef RAWSTORAGE_LOG_USAGE
00254                 ::logging::log::emit() << PROGMEMSTRING("RawStorage: free address ")
00255                     << ::logging::log::hex << reinterpret_cast<unsigned long>(p)
00256                         << PROGMEMSTRING(", offset ") << ::logging::log::dec
00257                         << (int)(p - data - sizeof(AllocInfo))
00258                         << PROGMEMSTRING(" (") << (int)ai_to_free->block_length
00259                         << PROGMEMSTRING(" bytes)") << ::logging::log::endl;
00260 #endif
00261 #ifdef RAWSTORAGE_FULL_MEM_INFO
00262                 print_mem_info();
00263 #endif
00264             }
00265 
00272             SizeT get_length(uint8_t * p) {
00273                 AllocInfo * ai = get_ai(p - data - sizeof(AllocInfo));
00274                 return ai->block_length;
00275             }
00276 
00277 #ifdef RAWSTORAGE_FULL_MEM_INFO
00278         private:
00279 
00281             void print_empty(SizeT first, SizeT last) {
00282                 ::logging::log::emit() << ::logging::log::tab
00283                     << ::logging::log::dec << (int)first << '-'
00284                     << (int)last << PROGMEMSTRING(" Empty") << ::logging::log::endl;
00285             }
00286 
00288             void print_ai(SizeT first) {
00289                 AllocInfo * ai = get_ai(first);
00290                 SizeT last = first + sizeof(AllocInfo) + ai->block_length - 1;
00291                 ::logging::log::emit() << ::logging::log::tab
00292                     << ::logging::log::dec << (int)first << '-' << (int)last
00293                     << ::logging::log::hex << PROGMEMSTRING(" Allocated (address=")
00294                     << reinterpret_cast<unsigned long>(data + first + sizeof(AllocInfo))
00295                     << ::logging::log::dec << PROGMEMSTRING(", length=")
00296                     << (int)ai->block_length
00297                     << PROGMEMSTRING(", next_allocated=") << (int)ai->next_allocated
00298                     << ')' << ::logging::log::endl;
00299 
00300             }
00301 
00302         public:
00304             void print_mem_info() {
00305                 ::logging::log::emit() << PROGMEMSTRING("RawStorage: size=")
00306                     << size << PROGMEMSTRING(", sizeof(SizeT)=") << sizeof(SizeT)
00307                     << PROGMEMSTRING(", first_allocated=") << (int)first_allocated
00308                     << ::logging::log::endl;
00309 
00310                 if (first_allocated != 0)
00311                     print_empty(0, first_allocated - 1);
00312 
00313                 SizeT curr_ai = first_allocated;
00314                 AllocInfo * ai = get_ai(curr_ai);
00315                 while (curr_ai < size) {
00316 
00317                     print_ai(curr_ai);
00318 
00319                     SizeT behind = curr_ai + sizeof(AllocInfo) + ai->block_length;
00320                     if (behind != ai->next_allocated)
00321                         print_empty(behind, ai->next_allocated - 1);
00322 
00323                     curr_ai = ai->next_allocated;
00324                     ai = get_ai(curr_ai);
00325                 }
00326                 FAMOUSO_ASSERT(curr_ai == size);
00327 
00328                 ::logging::log::emit() << ::logging::log::endl;
00329             }
00330 #endif
00331     };
00332 
00333 
00334 
00335 
00336 } // namespace object
00337 
00338 
00339 #endif // __RAWSTORAGE_H_8AC69FC602CD2C__
00340