LCOV - code coverage report
Current view: top level - util - multi_buffer.cpp (source / functions) Hit Total Coverage
Test: CoherentDB code coverage Lines: 45 47 95.7 %
Date: 2011-02-13 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * (C) Copyright 2010 Marek Dopiera
       3             :  * 
       4             :  * This file is part of CoherentDB.
       5             :  * 
       6             :  * CoherentDB is free software: you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation, either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  * 
      11             :  * CoherentDB is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      14             :  * General Public License for more details.
      15             :  * 
      16             :  * You should have received a copy of the GNU General Public
      17             :  * License along with CoherentDB. If not, see
      18             :  * http://www.gnu.org/licenses/.
      19             :  */
      20             : 
      21             : #include <cstdlib>
      22             : #include <exception>
      23             : #include <cstring>
      24             : 
      25             : #include <debug/asserts.h>
      26             : #include <log/log.h>
      27             : #include <util/multi_buffer.h>
      28             : 
      29             : namespace coherent {
      30             : namespace util {
      31             : 
      32             : using namespace std;
      33             : using namespace coherent::debug;
      34             : 
      35             : #ifdef VALGRIND
      36             : //it sometimes has some issues with memcpy - probably memcpy aligns what it
      37             : //copies and valgrind doesn't like it
      38             : 
      39             : void memcpy(char *dst, char const * src, size_t n)
      40             : {
      41             :         for (size_t i = 0; i < n; ++i)
      42             :                 *(dst++) = *(src++);
      43             : }
      44             : #endif
      45             : 
      46             : //=========== buffer implementation ============================================
      47             : 
      48       11976 : inline char * alloc_aligned(uint32_t size, uint32_t alignment)
      49             : {
      50             :         char * mem;
      51       11976 :         if (alignment == buffer::NO_ALIGNMENT)
      52        9380 :                 mem = reinterpret_cast<char*>(malloc(size));
      53             :         else
      54        2596 :                 if (posix_memalign(reinterpret_cast<void**>(&mem), alignment, size))
      55           0 :                         mem = 0;
      56       11976 :         if (mem == 0)
      57           0 :                 throw bad_alloc();
      58       11976 :         return mem;
      59             : }
      60             : 
      61       11976 : buffer::buffer(uint32_t size, uint32_t alignment) :
      62       11976 :         data(alloc_aligned(size, alignment)),
      63       11976 :         size(size)
      64             : {
      65       11976 : }
      66             : 
      67       11976 : buffer::~buffer()
      68             : {
      69       11976 :         free(this->data);
      70       11976 : }
      71             : 
      72             : //=========== multi_buffer implementation ======================================
      73             : 
      74        1128 : multi_buffer::multi_buffer(
      75             :         buffer_list & buffers,
      76             :         uint32_t size,
      77             :         uint32_t left_off
      78             : ) :
      79             :         size(size),
      80        1128 :         left_off(left_off)
      81             : {
      82        1128 :         buffers.swap(this->buffers);
      83             : #ifndef NDEBUG
      84        1128 :         uint32_t real_size = 0;
      85       17348 :         for (
      86        1128 :                 buffer_list::const_iterator i = this->buffers.begin();
      87        8674 :                 i != this->buffers.end();
      88             :                 ++i
      89             :         )
      90        7546 :                 real_size += (*i)->get_size();
      91             : 
      92             :         d_assert(left_off + size <= real_size,
      93             :                 "invalid use, left_off=" << left_off << ", size=" << size
      94             :                 << ", real_size=" << real_size
      95             :         );
      96             : #endif
      97             : 
      98             :         d_assert(
      99             :                 this->buffers.empty()
     100             :                 || this->buffers[0]->get_size() > left_off,
     101             :                 "invalid use: buffer_size=" << this->buffers[0]->get_size() <<
     102             :                 ", left_off=" << left_off
     103             :         );
     104             :         LOG(TRACE, "Created multi_buffer size=" << size << " off=" << left_off);
     105        1128 : }
     106             : 
     107          21 : multi_buffer::multi_buffer(multi_buffer const & o) :
     108             :         buffers(o.buffers),
     109             :         size(o.size),
     110          21 :         left_off(o.left_off)
     111             : {
     112             :         LOG(TRACE, "Copied multi_buffer size=" << size << " off=" << left_off);
     113          21 : }
     114             : 
     115             : template<bool READ>
     116             : void multi_buffer::do_rw(
     117             :         char * buf,
     118             :         uint32_t req_size,
     119             :         uint32_t req_off,
     120             :         uint32_t align
     121             : )
     122             : {
     123             :         d_assert(this->size >= req_size + req_off, "invalid use, req_size=" <<
     124             :                 req_size << ", req_off=" << req_off << ", size=" << this->size
     125             :         );
     126             : 
     127             :         LOG(TRACE, "r/w to multi_buffer, size=" << req_size << ", off="
     128             :                 << req_off
     129             :         );
     130             : 
     131        5248 :         if (!req_size)
     132          23 :                 return; //perfectly legal situation
     133             :         d_assert(!this->buffers.empty(), "buffers list empty, req_size=" <<
     134             :                 req_size << ", req_off=" << req_off
     135             :         );
     136             : 
     137        5225 :         uint32_t off = 0;
     138        5225 :         uint32_t size_left = req_size;
     139             :         
     140      680345 :         for (buffer_list::iterator it = this->buffers.begin(); size_left; ++it) {
     141             :                 d_assert(it != this->buffers.end(), "too long request?");
     142             :                 uint32_t const off_in_buf =
     143      675097 :                         (it == this->buffers.begin()) ? this->left_off : 0;
     144      675097 :                 uint32_t const buf_size = (*it)->get_size() - off_in_buf;
     145             :                 d_assert(buf_size, "empty buffer? off=" << off);
     146      675097 :                 if (off + buf_size > req_off) {
     147             : 
     148      232913 :                         uint32_t const buf_start = (req_off > off) ? (req_off - off) : 0;
     149             :                         d_assert(
     150             :                                 buf_size > buf_start,
     151             :                                 "how? buf_size=" << buf_size << ", buf_start=" << buf_start
     152             :                         );
     153      232913 :                         uint32_t const size = min(size_left, buf_size - buf_start);
     154             :                         d_assert(off + buf_start >= req_off,
     155             :                                 "can't be, off=" << off << ", req_off=" << req_off
     156             :                         );
     157      232913 :                         uint32_t const out_off = off + buf_start - req_off;
     158             :                         d_assert(
     159             :                                 out_off + size <= req_size,
     160             :                                 "trying to write past the buffer, out_off=" << out_off <<
     161             :                                 ", size=" << size << ", req_size=" << req_size
     162             :                         );
     163             :                         if (READ)
     164      121309 :                                 memcpy(
     165             :                                         buf + out_off,
     166             :                                         (*it)->get_data() + off_in_buf + buf_start,
     167             :                                         size
     168             :                                 );
     169             :                         else {
     170      111604 :                                 if (!it->unique())
     171             :                                 {
     172             :                                         //ensure C-O-W
     173        8840 :                                         buffer_ptr new_buf(new buffer((*it)->get_size(), align));
     174        4420 :                                         memcpy(
     175             :                                                 new_buf->get_data(),
     176             :                                                 (*it)->get_data(),
     177             :                                                 (*it)->get_size()
     178             :                                         );
     179        4420 :                                         *it = new_buf;
     180             :                                 }
     181      111604 :                                 memcpy(
     182             :                                         (*it)->get_data() + off_in_buf + buf_start,
     183             :                                         buf + out_off,
     184             :                                         size
     185             :                                 );
     186             :                         }
     187             :                         d_assert(size_left >= size, "mismatch, size_left=" << size_left <<
     188             :                                 ", size=" << size
     189             :                         );
     190      232913 :                         size_left -= size;
     191             :                 }
     192      675097 :                 off += buf_size;
     193             :         }
     194             : }
     195             : 
     196             : template
     197             : void multi_buffer::do_rw<true>(
     198             :         char * buf,
     199             :         uint32_t size,
     200             :         uint32_t off,
     201             :         uint32_t align
     202             : );
     203             : template
     204             : void multi_buffer::do_rw<false>(
     205             :         char * buf,
     206             :         uint32_t size,
     207             :         uint32_t off,
     208             :         uint32_t align
     209             : );
     210             : 
     211             : } // namespace util
     212           9 : } // namespace coherent
     213             : 

Generated by: LCOV version 1.9