24 #ifndef MEMORYBLOCKLIST_H 25 #define MEMORYBLOCKLIST_H 29 #include <glibmm/refptr.h> 30 #include <glibmm/thread.h> 31 #include <glibmm/dispatcher.h> 43 struct MemoryBlock :
public Referenceable {
46 MemoryBlock(MemoryBlock
const&) : Referenceable() { }
47 MemoryBlock& operator=(MemoryBlock
const&) {
return*
this; }
64 void*
operator new(
size_t object_size,
size_t block_size)
66 void* ptr = malloc(object_size + block_size);
67 AllocTag(reinterpret_cast<char*>(ptr),
"MemoryBlockNode (" << object_size <<
" bytes) + buffer allocation");
72 void operator delete(
void* ptr) { free(ptr); }
84 struct MemoryBlockNode :
public MemoryBlock {
87 Glib::RefPtr<MemoryBlockNode> M_next;
90 static size_t const S_data_offset;
94 MemoryBlockNode(
void) : M_valid_bytes(0) { }
104 static Glib::RefPtr<MemoryBlockNode> create(
size_t size)
106 return Glib::RefPtr<MemoryBlockNode>(
new (size) MemoryBlockNode);
112 friend class MemoryBlockList;
119 void append(Glib::RefPtr<MemoryBlockNode>& new_block,
size_t valid_bytes)
121 new_block->M_valid_bytes = valid_bytes;
122 M_next.swap(new_block);
130 char* block_begin(
void) {
return reinterpret_cast<char*
>(
this) + S_data_offset; }
133 char const* block_begin(
void)
const {
return reinterpret_cast<char const*
>(
this) + S_data_offset; }
136 char const* block_end(
void)
const {
return reinterpret_cast<char const*
>(
this) + S_data_offset + M_valid_bytes; }
139 size_t valid_bytes(
void)
const {
return M_valid_bytes; }
142 bool is_last_block(
void)
const {
return !M_next; }
145 Glib::RefPtr<MemoryBlockNode>
const& next(
void)
const {
return M_next; }
150 struct MutexCondPair {
155 class MemoryBlockList;
179 class MemoryBlockListIterator {
184 typedef std::input_iterator_tag iterator_category;
185 typedef char value_type;
186 typedef ptrdiff_t difference_type;
187 typedef char const* pointer;
188 typedef char const& reference;
193 MemoryBlockList*
const M_buffer;
194 Glib::RefPtr<MemoryBlockNode const> M_block;
196 char const* M_block_end;
197 int M_processed_blocks;
204 MemoryBlockListIterator(MemoryBlockListIterator
const& iter) :
205 M_buffer(iter.M_buffer),
206 M_block(iter.M_block),
208 M_block_end(iter.M_block_end),
209 M_processed_blocks(iter.M_processed_blocks)
213 MemoryBlockListIterator& operator=(MemoryBlockListIterator
const& iter)
215 assert(M_buffer == iter.M_buffer);
216 M_block = iter.M_block;
218 M_block_end = iter.M_block_end;
219 M_processed_blocks = iter.M_processed_blocks;
227 friend bool operator==(MemoryBlockListIterator
const& a, MemoryBlockListIterator
const& b) {
return a.M_ptr == b.M_ptr; }
228 friend bool operator!=(MemoryBlockListIterator
const& a, MemoryBlockListIterator
const& b) {
return a.M_ptr != b.M_ptr; }
235 value_type
const& operator*(
void)
const {
return* M_ptr; }
244 MemoryBlockListIterator& operator++(
void)
246 if (G_UNLIKELY(M_ptr == M_block_end))
247 advance_to_next_block();
256 MemoryBlockListIterator(MemoryBlockList* buffer) : M_buffer(buffer), M_ptr(NULL), M_processed_blocks(0) { }
259 MemoryBlockListIterator& operator=(Glib::RefPtr<MemoryBlockNode const>
const& node)
263 M_ptr = node->block_begin();
264 M_block_end = node->block_end() - 1;
265 M_processed_blocks = 0;
271 int processed_blocks(
void)
const {
return M_processed_blocks; }
273 MemoryBlockList* buffer(
void) {
return M_buffer; }
278 void advance_to_next_block(
void);
291 class MemoryBlockList {
293 typedef MemoryBlockListIterator iterator;
294 typedef sigc::slot<void> SlotNeedMoreData;
299 static int const S_max_blocks = 8;
302 Glib::RefPtr<MemoryBlockNode> M_last_node;
304 int M_appended_blocks;
307 Glib::Dispatcher M_need_more_data;
308 SlotNeedMoreData M_slot_need_more_data;
309 MutexCondPair M_more_data;
312 MemoryBlockList(SlotNeedMoreData
const& slot) : M_begin(this), M_appended_blocks(0), M_closed(false), M_buffer_full(false), M_slot_need_more_data(slot)
313 { M_need_more_data.connect(sigc::mem_fun(*
this,& MemoryBlockList::need_more_data_callback)); }
315 void append(Glib::RefPtr<MemoryBlockNode>& new_block,
size_t valid_bytes)
318 if (G_UNLIKELY(!M_last_node))
324 new_block->M_valid_bytes = valid_bytes;
325 M_last_node.swap(new_block);
326 M_begin = M_last_node;
327 Dout(dc::notice,
"Appending FIRST block to the list. Number of blocks is now 1");
328 assert(M_appended_blocks == 0);
329 M_appended_blocks = 1;
337 M_last_node->append(new_block, valid_bytes);
338 M_last_node = M_last_node->M_next;
341 blocks = M_appended_blocks - M_begin.processed_blocks();
342 Dout(dc::notice,
"Appending a new block to the list. Number of unread blocks: " << blocks);
344 M_more_data.cond.signal();
347 if (blocks < S_max_blocks)
348 M_slot_need_more_data();
351 Dout(dc::notice,
"The buffer is full!");
352 M_more_data.mutex.lock();
353 M_buffer_full =
true;
355 M_more_data.cond.signal();
356 M_more_data.mutex.unlock();
362 M_more_data.mutex.lock();
365 M_more_data.cond.signal();
366 M_more_data.mutex.unlock();
369 bool closed(
void)
const {
return M_closed; }
370 bool full(
void)
const {
return M_buffer_full; }
372 iterator& begin(
void)
375 while (!can_process_next_block(M_begin))
376 wait_for_more_data(M_begin);
379 iterator end(
void)
const {
return iterator(const_cast<MemoryBlockList*>(
this)); }
382 int appended_blocks(
void)
const {
return M_appended_blocks; }
386 bool can_process_next_block(iterator
const& iter)
392 return M_closed || M_appended_blocks - iter.processed_blocks() >= 2;
395 MutexCondPair& more_data(
void) {
return M_more_data; }
397 Glib::Dispatcher& need_more_data(
void) {
return M_need_more_data; }
399 void need_more_data_callback(
void);
401 void wait_for_more_data(iterator
const& iter)
403 Dout(dc::notice,
"Waiting for more data...");
406 timespec start_sleep_time_real, stop_sleep_time_real;
407 timespec start_sleep_time_process, stop_sleep_time_process;
408 clock_gettime(CLOCK_PROCESS_CPUTIME_ID,& start_sleep_time_process);
409 clock_gettime(CLOCK_REALTIME,& start_sleep_time_real);
411 M_more_data.mutex.lock();
412 if (!M_buffer_full && !M_closed)
413 M_more_data.cond.wait(M_more_data.mutex);
414 M_more_data.mutex.unlock();
416 clock_gettime(CLOCK_PROCESS_CPUTIME_ID,& stop_sleep_time_process);
417 clock_gettime(CLOCK_REALTIME,& stop_sleep_time_real);
418 stop_sleep_time_process -= start_sleep_time_process;
419 wait_time_thread_process += stop_sleep_time_process;
420 stop_sleep_time_real -= start_sleep_time_real;
421 wait_time_thread_real += stop_sleep_time_real;
431 if (!can_process_next_block(iter))
433 M_need_more_data.emit();
434 goto continue_waiting;
437 Dout(dc::notice,
"Got data!");
443 #endif // MEMORYBLOCKLIST_H
This file contains the declaration of class Referenceable.