MemoryBlockList.cc
Go to the documentation of this file.
1 // cwchessboard -- A C++ chessboard tool set
2 //
3 //! @file MemoryBlockList.cc This file contains the implementation of class MemoryBlockList.
4 //
5 // Copyright (C) 2010, by
6 //
7 // Carlo Wood, Run on IRC <carlo@alinoe.com>
8 // RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
9 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 2 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 
24 #ifndef USE_PCH
25 #include "sys.h"
26 #include <glib.h>
27 #endif
28 
29 #include "MemoryBlockList.h"
30 
31 namespace util {
32 
33 // Let the data start at the first multiple of sizeof(size_t) after the MemoryBlockNode object.
34 size_t const MemoryBlockNode::S_data_offset = (sizeof(MemoryBlockNode) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1);
35 
36 void MemoryBlockList::need_more_data_callback(void)
37 {
38  // Create and read at most one new block per 'buffer full' incident.
39  // If multiple new blocks have been processed in the mean time,
40  // then the call to read_async_ready will trigger subsequent reads.
41  if (!M_buffer_full)
42  return;
43  M_buffer_full = false;
44  M_slot_need_more_data();
45 }
46 
47 void MemoryBlockListIterator::advance_to_next_block(void)
48 {
49  // Count the number of fully processed blocks.
50  ++M_processed_blocks;
51  Dout(dc::notice, "Finished processing of block " << M_processed_blocks);
52  if (G_UNLIKELY(M_block->is_last_block()))
53  {
54  // We should never even have been processing the last block,
55  // unless the buffer was already closed.
56  assert(M_buffer->closed());
57 
58  // This might free the memory of this block, if no other iterator is pointing at it.
59  Dout(dc::notice, "Setting M_block to NULL.");
60  M_block.reset();
61 
62  // We're done. Set the iterator to past-the-end and return.
63  M_ptr = NULL;
64  return;
65  }
66  else
67  {
68  M_block = M_block->next();
69  M_ptr = M_block->block_begin();
70  M_block_end = M_block->block_end() - 1;
71  }
72  if (M_buffer->full() && M_buffer->appended_blocks() - M_processed_blocks <= MemoryBlockList::S_max_blocks / 2)
73  {
74  Dout(dc::notice, "Requesting more data!");
75  M_buffer->need_more_data().emit();
76  }
77  // If M_buffer->full() was just false but around here the main thread
78  // sets it to true, then that means that the number of remaining blocks
79  // in the buffer is much larger than the threshold and the previous
80  // condition would have failed anyway. What would happen then is that
81  // the next condition is definitely false (because there ARE blocks to
82  // be processed), the next block in the buffer will be processed and
83  // we'll recheck the above condition. Hence, there is no race condition.
84  while (!M_buffer->can_process_next_block(*this))
85  {
86  // If can_process_next_block returned false (so we get here)
87  // then the buffer has less than 2 blocks is thus not full (yet).
88  // If now we manage to get into a sleeping state before the
89  // buffer is full then everything works. But, if right here
90  // the buffer is filled -- which causes an attempt to wake
91  // up this thread, but we're not inside wait() yet... and
92  // then we enter wait(), then we have a hang.
93  // Therefore it is needed to lock the mutex then test if
94  // the buffer is full and only if NOT we may really sleep.
95  // In the main thread then we may only mark that the buffer is
96  // full and emit the wake up signal if this mutex is not locked.
97  // The locking and extra buffer full test is done inside wait_for_more_data().
98 
99  // This is triggered when a new block is appended, either when there are at least two blocks,
100  // or when the last block was appended (the buffer was closed).
101  M_buffer->wait_for_more_data(*this);
102  }
103 }
104 
105 } // namespace util
This file contains the declaration of class MemoryBlockList.

Copyright © 2006 - 2010 Carlo Wood.  All rights reserved.