Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef MEMORYBLOCKLIST_H
00025 #define MEMORYBLOCKLIST_H
00026
00027 #ifndef USE_PCH
00028 #include "debug.h"
00029 #include <glibmm/refptr.h>
00030 #include <glibmm/thread.h>
00031 #include <glibmm/dispatcher.h>
00032 #endif
00033
00034 #include "Referenceable.h"
00035
00036 namespace util {
00037
00038
00039
00040
00041
00042
00043 struct MemoryBlock : public Referenceable {
00044 private:
00045
00046 MemoryBlock(MemoryBlock const&) : Referenceable() { }
00047 MemoryBlock& operator=(MemoryBlock const&) { return* this; }
00048
00049
00050
00051
00052 protected:
00053
00054
00055 MemoryBlock() { }
00056
00057 public:
00058
00059
00060
00061
00062
00063
00064 void* operator new(size_t object_size, size_t block_size)
00065 {
00066 void* ptr = malloc(object_size + block_size);
00067 AllocTag(reinterpret_cast<char*>(ptr), "MemoryBlockNode (" << object_size << " bytes) + buffer allocation");
00068 return ptr;
00069 }
00070
00071
00072 void operator delete(void* ptr) { free(ptr); }
00073
00074
00075 };
00076
00077
00078
00079
00080
00081
00082
00083
00084 struct MemoryBlockNode : public MemoryBlock {
00085 private:
00086 size_t M_valid_bytes;
00087 Glib::RefPtr<MemoryBlockNode> M_next;
00088
00089
00090 static size_t const S_data_offset;
00091
00092 private:
00093
00094 MemoryBlockNode(void) : M_valid_bytes(0) { }
00095
00096
00097
00098
00099 public:
00100
00101
00102
00103
00104 static Glib::RefPtr<MemoryBlockNode> create(size_t size)
00105 {
00106 return Glib::RefPtr<MemoryBlockNode>(new (size) MemoryBlockNode);
00107 }
00108
00109
00110
00111 private:
00112 friend class MemoryBlockList;
00113
00114
00115
00116
00117
00118
00119 void append(Glib::RefPtr<MemoryBlockNode>& new_block, size_t valid_bytes)
00120 {
00121 new_block->M_valid_bytes = valid_bytes;
00122 M_next.swap(new_block);
00123 }
00124
00125 public:
00126
00127
00128
00129
00130 char* block_begin(void) { return reinterpret_cast<char*>(this) + S_data_offset; }
00131
00132
00133 char const* block_begin(void) const { return reinterpret_cast<char const*>(this) + S_data_offset; }
00134
00135
00136 char const* block_end(void) const { return reinterpret_cast<char const*>(this) + S_data_offset + M_valid_bytes; }
00137
00138
00139 size_t valid_bytes(void) const { return M_valid_bytes; }
00140
00141
00142 bool is_last_block(void) const { return !M_next; }
00143
00144
00145 Glib::RefPtr<MemoryBlockNode> const& next(void) const { return M_next; }
00146
00147
00148 };
00149
00150 struct MutexCondPair {
00151 Glib::Mutex mutex;
00152 Glib::Cond cond;
00153 };
00154
00155 class MemoryBlockList;
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 class MemoryBlockListIterator {
00180 public:
00181
00182
00183
00184 typedef std::input_iterator_tag iterator_category;
00185 typedef char value_type;
00186 typedef ptrdiff_t difference_type;
00187 typedef char const* pointer;
00188 typedef char const& reference;
00189
00190
00191
00192 private:
00193 MemoryBlockList* const M_buffer;
00194 Glib::RefPtr<MemoryBlockNode const> M_block;
00195 char const* M_ptr;
00196 char const* M_block_end;
00197 int M_processed_blocks;
00198
00199 public:
00200
00201
00202
00203
00204 MemoryBlockListIterator(MemoryBlockListIterator const& iter) :
00205 M_buffer(iter.M_buffer),
00206 M_block(iter.M_block),
00207 M_ptr(iter.M_ptr),
00208 M_block_end(iter.M_block_end),
00209 M_processed_blocks(iter.M_processed_blocks)
00210 { }
00211
00212
00213 MemoryBlockListIterator& operator=(MemoryBlockListIterator const& iter)
00214 {
00215 assert(M_buffer == iter.M_buffer);
00216 M_block = iter.M_block;
00217 M_ptr = iter.M_ptr;
00218 M_block_end = iter.M_block_end;
00219 M_processed_blocks = iter.M_processed_blocks;
00220 }
00221
00222
00223
00224
00225
00226
00227 friend bool operator==(MemoryBlockListIterator const& a, MemoryBlockListIterator const& b) { return a.M_ptr == b.M_ptr; }
00228 friend bool operator!=(MemoryBlockListIterator const& a, MemoryBlockListIterator const& b) { return a.M_ptr != b.M_ptr; }
00229
00230
00231
00232
00233
00234
00235 value_type const& operator*(void) const { return* M_ptr; }
00236
00237
00238
00239
00240
00241
00242
00243
00244 MemoryBlockListIterator& operator++(void)
00245 {
00246 if (G_UNLIKELY(M_ptr == M_block_end))
00247 advance_to_next_block();
00248 else
00249 ++M_ptr;
00250 return* this;
00251 }
00252
00253
00254
00255
00256 MemoryBlockListIterator(MemoryBlockList* buffer) : M_buffer(buffer), M_ptr(NULL), M_processed_blocks(0) { }
00257
00258
00259 MemoryBlockListIterator& operator=(Glib::RefPtr<MemoryBlockNode const> const& node)
00260 {
00261 assert(M_buffer);
00262 M_block = node;
00263 M_ptr = node->block_begin();
00264 M_block_end = node->block_end() - 1;
00265 M_processed_blocks = 0;
00266 }
00267
00268
00269
00270
00271 int processed_blocks(void) const { return M_processed_blocks; }
00272
00273 MemoryBlockList* buffer(void) { return M_buffer; }
00274
00275
00276
00277 private:
00278 void advance_to_next_block(void);
00279 };
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 class MemoryBlockList {
00292 public:
00293 typedef MemoryBlockListIterator iterator;
00294 typedef sigc::slot<void> SlotNeedMoreData;
00295
00296
00297
00298
00299 static int const S_max_blocks = 8;
00300
00301 private:
00302 Glib::RefPtr<MemoryBlockNode> M_last_node;
00303 iterator M_begin;
00304 int M_appended_blocks;
00305 bool M_closed;
00306 bool M_buffer_full;
00307 Glib::Dispatcher M_need_more_data;
00308 SlotNeedMoreData M_slot_need_more_data;
00309 MutexCondPair M_more_data;
00310
00311 public:
00312 MemoryBlockList(SlotNeedMoreData const& slot) : M_begin(this), M_appended_blocks(0), M_closed(false), M_buffer_full(false), M_slot_need_more_data(slot)
00313 { M_need_more_data.connect(sigc::mem_fun(*this,& MemoryBlockList::need_more_data_callback)); }
00314
00315 void append(Glib::RefPtr<MemoryBlockNode>& new_block, size_t valid_bytes)
00316 {
00317 int blocks;
00318 if (G_UNLIKELY(!M_last_node))
00319 {
00320
00321
00322
00323
00324 new_block->M_valid_bytes = valid_bytes;
00325 M_last_node.swap(new_block);
00326 M_begin = M_last_node;
00327 Dout(dc::notice, "Appending FIRST block to the list. Number of blocks is now 1");
00328 assert(M_appended_blocks == 0);
00329 M_appended_blocks = 1;
00330 blocks = 1;
00331 }
00332 else
00333 {
00334
00335
00336
00337 M_last_node->append(new_block, valid_bytes);
00338 M_last_node = M_last_node->M_next;
00339
00340 ++M_appended_blocks;
00341 blocks = M_appended_blocks - M_begin.processed_blocks();
00342 Dout(dc::notice, "Appending a new block to the list. Number of unread blocks: " << blocks);
00343
00344 M_more_data.cond.signal();
00345 }
00346
00347 if (blocks < S_max_blocks)
00348 M_slot_need_more_data();
00349 else
00350 {
00351 Dout(dc::notice, "The buffer is full!");
00352 M_more_data.mutex.lock();
00353 M_buffer_full = true;
00354
00355 M_more_data.cond.signal();
00356 M_more_data.mutex.unlock();
00357 }
00358 }
00359
00360 void close(void)
00361 {
00362 M_more_data.mutex.lock();
00363 M_closed = true;
00364
00365 M_more_data.cond.signal();
00366 M_more_data.mutex.unlock();
00367 }
00368
00369 bool closed(void) const { return M_closed; }
00370 bool full(void) const { return M_buffer_full; }
00371
00372 iterator& begin(void)
00373 {
00374
00375 while (!can_process_next_block(M_begin))
00376 wait_for_more_data(M_begin);
00377 return M_begin;
00378 }
00379 iterator end(void) const { return iterator(const_cast<MemoryBlockList*>(this)); }
00380
00381
00382 int appended_blocks(void) const { return M_appended_blocks; }
00383
00384
00385
00386 bool can_process_next_block(iterator const& iter)
00387 {
00388
00389
00390
00391
00392 return M_closed || M_appended_blocks - iter.processed_blocks() >= 2;
00393 }
00394
00395 MutexCondPair& more_data(void) { return M_more_data; }
00396
00397 Glib::Dispatcher& need_more_data(void) { return M_need_more_data; }
00398
00399 void need_more_data_callback(void);
00400
00401 void wait_for_more_data(iterator const& iter)
00402 {
00403 Dout(dc::notice, "Waiting for more data...");
00404 continue_waiting:
00405 #if 0
00406 timespec start_sleep_time_real, stop_sleep_time_real;
00407 timespec start_sleep_time_process, stop_sleep_time_process;
00408 clock_gettime(CLOCK_PROCESS_CPUTIME_ID,& start_sleep_time_process);
00409 clock_gettime(CLOCK_REALTIME,& start_sleep_time_real);
00410 #endif
00411 M_more_data.mutex.lock();
00412 if (!M_buffer_full && !M_closed)
00413 M_more_data.cond.wait(M_more_data.mutex);
00414 M_more_data.mutex.unlock();
00415 #if 0
00416 clock_gettime(CLOCK_PROCESS_CPUTIME_ID,& stop_sleep_time_process);
00417 clock_gettime(CLOCK_REALTIME,& stop_sleep_time_real);
00418 stop_sleep_time_process -= start_sleep_time_process;
00419 wait_time_thread_process += stop_sleep_time_process;
00420 stop_sleep_time_real -= start_sleep_time_real;
00421 wait_time_thread_real += stop_sleep_time_real;
00422 #endif
00423
00424
00425
00426
00427
00428 if (M_buffer_full)
00429 {
00430
00431 if (!can_process_next_block(iter))
00432 {
00433 M_need_more_data.emit();
00434 goto continue_waiting;
00435 }
00436 }
00437 Dout(dc::notice, "Got data!");
00438 }
00439 };
00440
00441 }
00442
00443 #endif // MEMORYBLOCKLIST_H