1 #define TRACE_NAME "SharedMemoryManager"
6 #include <unordered_map>
7 #ifndef SHM_DEST // Lynn reports that this is missing on Mac OS X?!?
11 #include "TRACE/tracemf.h"
12 #include "artdaq-core/Core/SharedMemoryManager.hh"
13 #include "artdaq-core/Utilities/TraceLock.hh"
14 #include "cetlib_except/exception.h"
16 #define TLVL_DETACH 34
17 #define TLVL_DESTRUCTOR 35
18 #define TLVL_ATTACH 36
19 #define TLVL_GETBUFFER 37
20 #define TLVL_BUFFER 40
21 #define TLVL_BUFLCK 41
22 #define TLVL_READREADY 42
23 #define TLVL_WRITEREADY 46
26 #define TLVL_BUFINFO 52
29 #define TLVL_CHKBUFFER 55
31 static std::list<artdaq::SharedMemoryManager const*> instances = std::list<artdaq::SharedMemoryManager const*>();
33 static std::unordered_map<int, struct sigaction> old_actions = std::unordered_map<int, struct sigaction>();
34 static bool sighandler_init =
false;
35 static std::mutex sighandler_mutex;
37 static void signal_handler(
int signum)
40 #if TRACE_REVNUM < 1459
41 TRACE_STREAMER(TLVL_ERROR, &(
"SharedMemoryManager")[0], 0, 0, 0)
43 TRACE_STREAMER(TLVL_ERROR, TLOG2(
"SharedMemoryManager", 0), 0)
45 <<
"A signal of type " << signum <<
" was caught by SharedMemoryManager. Detaching all Shared Memory segments, then proceeding with default handlers!";
46 for (
auto ii : instances)
59 pthread_sigmask(SIG_UNBLOCK,
nullptr, &set);
60 pthread_sigmask(SIG_UNBLOCK, &set,
nullptr);
62 #if TRACE_REVNUM < 1459
63 TRACE_STREAMER(TLVL_ERROR, &(
"SharedMemoryManager")[0], 0, 0, 0)
65 TRACE_STREAMER(TLVL_ERROR, TLOG2(
"SharedMemoryManager", 0), 0)
67 <<
"Restoring default signal handler";
68 sigaction(signum, &old_actions[signum],
nullptr);
78 requested_shm_parameters_.buffer_count = buffer_count;
79 requested_shm_parameters_.buffer_size = buffer_size;
80 requested_shm_parameters_.buffer_timeout_us = buffer_timeout_us;
81 requested_shm_parameters_.destructive_read_mode = destructive_read_mode;
83 instances.push_back(
this);
86 std::lock_guard<std::mutex> lk(sighandler_mutex);
90 sighandler_init =
true;
91 std::vector<int> signals = {SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, SIGUSR2, SIGHUP};
92 for (
auto signal : signals)
94 struct sigaction old_action;
95 sigaction(signal,
nullptr, &old_action);
99 if (old_action.sa_handler != SIG_IGN)
101 struct sigaction action;
102 action.sa_handler = signal_handler;
103 sigemptyset(&action.sa_mask);
104 for (
auto sigblk : signals)
106 sigaddset(&action.sa_mask, sigblk);
111 sigaction(signal, &action,
nullptr);
113 old_actions[signal] = old_action;
121 TLOG(TLVL_DESTRUCTOR) <<
"~SharedMemoryManager called";
123 static std::mutex destructor_mutex;
124 std::lock_guard<std::mutex> lk(destructor_mutex);
125 for (
auto it = instances.begin(); it != instances.end(); ++it)
129 it = instances.erase(it);
136 std::lock_guard<std::mutex> lk(sighandler_mutex);
139 if (sighandler_init && instances.empty())
141 sighandler_init =
false;
142 for (
auto signal : old_actions)
144 sigaction(signal.first, &signal.second,
nullptr);
149 TLOG(TLVL_DESTRUCTOR) <<
"~SharedMemoryManager done";
156 if (manager_id_ == 0)
163 size_t timeout_us = timeout_usec > 0 ? timeout_usec : 1000000;
164 auto start_time = std::chrono::steady_clock::now();
166 size_t shmSize = requested_shm_parameters_.buffer_count * (requested_shm_parameters_.buffer_size +
sizeof(ShmBuffer)) +
sizeof(ShmStruct);
170 if (requested_shm_parameters_.buffer_count > 0 && requested_shm_parameters_.buffer_size > 0 && manager_id_ <= 0)
175 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
176 if (shm_segment_id_ == -1)
178 if (manager_id_ == 0)
180 TLOG(TLVL_ATTACH) <<
"Creating shared memory segment with key 0x" << std::hex << shm_key_ <<
" and size " << std::dec << shmSize;
181 shm_segment_id_ = shmget(shm_key_, shmSize, IPC_CREAT | 0666);
183 if (shm_segment_id_ == -1)
185 TLOG(TLVL_ERROR) <<
"Error creating shared memory segment with key 0x" << std::hex << shm_key_ <<
", errno=" << std::dec << errno <<
" (" << strerror(errno) <<
")";
192 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
196 TLOG(TLVL_ATTACH) <<
"shm_key == 0x" << std::hex << shm_key_ <<
", shm_segment_id == " << std::dec << shm_segment_id_;
198 if (shm_segment_id_ > -1)
201 <<
"Attached to shared memory segment with ID = " << shm_segment_id_
202 <<
" and size " << shmSize
204 shm_ptr_ =
static_cast<ShmStruct*
>(shmat(shm_segment_id_,
nullptr, 0));
206 <<
"Attached to shared memory segment at address "
207 << std::hex << static_cast<void*>(shm_ptr_) << std::dec;
208 if ((shm_ptr_ !=
nullptr) && shm_ptr_ !=
reinterpret_cast<void*
>(-1))
210 if (manager_id_ == 0)
212 if (shm_ptr_->ready_magic == 0xCAFE1111)
214 TLOG(TLVL_WARNING) <<
"Owner encountered already-initialized Shared Memory! "
215 <<
"Once the system is shut down, you can use one of the following commands "
216 <<
"to clean up this shared memory: 'ipcrm -M 0x" << std::hex << shm_key_
217 <<
"' or 'ipcrm -m " << std::dec << shm_segment_id_ <<
"'.";
220 TLOG(TLVL_ATTACH) <<
"Owner initializing Shared Memory";
221 shm_ptr_->next_id = 1;
222 shm_ptr_->next_sequence_id = 0;
223 shm_ptr_->reader_pos = 0;
224 shm_ptr_->writer_pos = 0;
225 shm_ptr_->buffer_size = requested_shm_parameters_.buffer_size;
226 shm_ptr_->buffer_count = requested_shm_parameters_.buffer_count;
227 shm_ptr_->buffer_timeout_us = requested_shm_parameters_.buffer_timeout_us;
228 shm_ptr_->destructive_read_mode = requested_shm_parameters_.destructive_read_mode;
230 buffer_ptrs_ = std::vector<ShmBuffer*>(shm_ptr_->buffer_count);
231 for (
int ii = 0; ii < static_cast<int>(requested_shm_parameters_.buffer_count); ++ii)
233 buffer_ptrs_[ii] =
reinterpret_cast<ShmBuffer*
>(
reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + ii *
sizeof(ShmBuffer));
234 if (getBufferInfo_(ii) ==
nullptr)
238 getBufferInfo_(ii)->writePos = 0;
239 getBufferInfo_(ii)->readPos = 0;
240 getBufferInfo_(ii)->sem = BufferSemaphoreFlags::Empty;
241 getBufferInfo_(ii)->sem_id = -1;
245 shm_ptr_->ready_magic = 0xCAFE1111;
249 TLOG(TLVL_ATTACH) <<
"Waiting for owner to initalize Shared Memory";
250 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); }
251 TLOG(TLVL_ATTACH) <<
"Getting ID from Shared Memory";
253 shm_ptr_->lowest_seq_id_read = 0;
254 TLOG(TLVL_ATTACH) <<
"Getting Shared Memory Size parameters";
256 requested_shm_parameters_.buffer_count = shm_ptr_->buffer_count;
257 buffer_ptrs_ = std::vector<ShmBuffer*>(shm_ptr_->buffer_count);
258 for (
int ii = 0; ii < shm_ptr_->buffer_count; ++ii)
260 buffer_ptrs_[ii] =
reinterpret_cast<ShmBuffer*
>(
reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + ii *
sizeof(ShmBuffer));
265 buffer_mutexes_ = std::vector<std::mutex>(shm_ptr_->buffer_count);
267 TLOG(TLVL_ATTACH) <<
"Initialization Complete: "
268 <<
"key: 0x" << std::hex << shm_key_
269 <<
", manager ID: " << std::dec << manager_id_
270 <<
", Buffer size: " << shm_ptr_->buffer_size
271 <<
", Buffer count: " << shm_ptr_->buffer_count;
275 TLOG(TLVL_ERROR) <<
"Failed to attach to shared memory segment "
280 TLOG(TLVL_ERROR) <<
"Failed to connect to shared memory segment with key 0x" << std::hex << shm_key_
281 <<
", errno=" << std::dec << errno <<
" (" << strerror(errno) <<
")"
283 <<
"if a stale shared memory segment needs to "
284 <<
"be cleaned up. (ipcs, ipcrm -m <segId>)";
290 TLOG(TLVL_GETBUFFER) <<
"GetBufferForReading BEGIN";
292 if (!registered_reader_)
294 shm_ptr_->reader_count++;
295 registered_reader_ =
true;
298 std::lock_guard<std::mutex> lk(search_mutex_);
300 auto rp = shm_ptr_->reader_pos.load();
302 TLOG(TLVL_GETBUFFER) <<
"GetBufferForReading lock acquired, scanning " << shm_ptr_->buffer_count <<
" buffers";
304 for (
int retry = 0; retry < 5; retry++)
309 ShmBuffer* buffer_ptr =
nullptr;
312 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
314 auto buffer = (ii + rp) % shm_ptr_->buffer_count;
316 TLOG(TLVL_GETBUFFER + 1) <<
"GetBufferForReading Checking if buffer " << buffer <<
" is stale. Shm destructive_read_mode=" << shm_ptr_->destructive_read_mode;
319 auto buf = getBufferInfo_(buffer);
325 sem = buf->sem.load();
326 sem_id = buf->sem_id.load();
328 TLOG(TLVL_GETBUFFER + 1) <<
"GetBufferForReading: Buffer " << buffer <<
": sem=" << FlagToString(sem)
329 <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << sem_id <<
", seq_id=" << buf->sequence_id <<
" )";
330 if (sem == BufferSemaphoreFlags::Full && (sem_id == -1 || sem_id == manager_id_) && (shm_ptr_->destructive_read_mode || buf->sequence_id > last_seen_id_))
332 if (buf->sequence_id < seqID)
335 seqID = buf->sequence_id;
338 if (seqID == last_seen_id_ + shm_ptr_->reader_count)
346 if (buffer_ptr !=
nullptr)
348 sem = buffer_ptr->sem.load();
349 sem_id = buffer_ptr->sem_id.load();
350 seqID = buffer_ptr->sequence_id.load();
353 TLOG(TLVL_GETBUFFER + 2) <<
"GetBufferForReading: Mode: " << std::boolalpha << shm_ptr_->destructive_read_mode <<
", seqID: " << seqID <<
", last_seen_id_: " << last_seen_id_ <<
", reader_count: " << shm_ptr_->reader_count;
355 if(shm_ptr_->destructive_read_mode && last_seen_id_ > 0 && seqID != last_seen_id_ + shm_ptr_->reader_count && seqID > last_seen_id_ - shm_ptr_->reader_count ){
356 TLOG(TLVL_GETBUFFER + 2) <<
"GetBufferForReading: Skipping due to seqID check";
359 TLOG(TLVL_GETBUFFER + 2) <<
"GetBufferForReading: After seqID check";
361 if ((buffer_ptr ==
nullptr) || (sem_id != -1 && sem_id != manager_id_) || sem != BufferSemaphoreFlags::Full)
368 TLOG(TLVL_GETBUFFER) <<
"GetBufferForReading Found buffer " << buffer_num;
369 touchBuffer_(buffer_ptr);
370 if (!buffer_ptr->sem_id.compare_exchange_strong(sem_id, manager_id_))
374 if (!buffer_ptr->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Reading))
378 if (!checkBuffer_(buffer_ptr, BufferSemaphoreFlags::Reading,
false))
380 TLOG(TLVL_GETBUFFER) <<
"GetBufferForReading: Failed to acquire buffer " << buffer_num <<
" (someone else changed manager ID while I was changing sem)";
383 buffer_ptr->readPos = 0;
384 touchBuffer_(buffer_ptr);
385 if (!checkBuffer_(buffer_ptr, BufferSemaphoreFlags::Reading,
false))
387 TLOG(TLVL_GETBUFFER) <<
"GetBufferForReading: Failed to acquire buffer " << buffer_num <<
" (someone else changed manager ID while I was touching buffer SHOULD NOT HAPPEN!)";
390 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_)
392 shm_ptr_->lowest_seq_id_read = seqID;
394 last_seen_id_ = seqID;
395 if (shm_ptr_->destructive_read_mode)
397 shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count;
400 TLOG(TLVL_GETBUFFER) <<
"GetBufferForReading returning " << buffer_num;
406 TLOG(TLVL_GETBUFFER) <<
"GetBufferForReading returning -1 because no buffers are ready";
412 TLOG(TLVL_GETBUFFER + 1) <<
"GetBufferForWriting BEGIN, overwrite=" << (overwrite ?
"true" :
"false");
414 if (!registered_writer_)
416 shm_ptr_->writer_count++;
417 registered_writer_ =
true;
420 std::lock_guard<std::mutex> lk(search_mutex_);
422 auto wp = shm_ptr_->writer_pos.load();
424 TLOG(TLVL_GETBUFFER) <<
"GetBufferForWriting lock acquired, scanning " << shm_ptr_->buffer_count <<
" buffers";
427 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
429 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
433 auto buf = getBufferInfo_(buffer);
439 auto sem = buf->sem.load();
440 auto sem_id = buf->sem_id.load();
442 if (sem == BufferSemaphoreFlags::Empty && sem_id == -1)
445 if (!buf->sem_id.compare_exchange_strong(sem_id, manager_id_))
449 if (!buf->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Writing))
453 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing,
false))
457 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
458 buf->sequence_id = ++shm_ptr_->next_sequence_id;
460 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing,
false))
465 TLOG(TLVL_GETBUFFER + 1) <<
"GetBufferForWriting returning empty buffer " << buffer;
473 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
475 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
479 auto buf = getBufferInfo_(buffer);
485 auto sem = buf->sem.load();
486 auto sem_id = buf->sem_id.load();
488 if (sem == BufferSemaphoreFlags::Full)
491 if (!buf->sem_id.compare_exchange_strong(sem_id, manager_id_))
495 if (!buf->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Writing))
499 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing,
false))
503 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
504 buf->sequence_id = ++shm_ptr_->next_sequence_id;
506 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing,
false))
511 TLOG(TLVL_GETBUFFER + 1) <<
"GetBufferForWriting returning full buffer (overwrite mode) " << buffer;
517 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
519 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
523 auto buf = getBufferInfo_(buffer);
529 auto sem = buf->sem.load();
530 auto sem_id = buf->sem_id.load();
532 if (sem == BufferSemaphoreFlags::Reading)
535 if (!buf->sem_id.compare_exchange_strong(sem_id, manager_id_))
539 if (!buf->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Writing))
543 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing,
false))
547 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
548 buf->sequence_id = ++shm_ptr_->next_sequence_id;
550 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing,
false))
555 TLOG(TLVL_GETBUFFER + 1) <<
"GetBufferForWriting clobbering reader on buffer " << buffer <<
" (overwrite mode)";
560 TLOG(TLVL_GETBUFFER + 1) <<
"GetBufferForWriting Returning -1 because no buffers are ready";
570 TLOG(TLVL_READREADY) <<
"0x" << std::hex << shm_key_ <<
" ReadReadyCount BEGIN" << std::dec;
571 std::unique_lock<std::mutex> lk(search_mutex_);
572 TLOG(TLVL_READREADY) <<
"ReadReadyCount lock acquired, scanning " << shm_ptr_->buffer_count <<
" buffers";
575 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
578 TLOG(TLVL_READREADY + 1) <<
"0x" << std::hex << shm_key_ << std::dec <<
" ReadReadyCount: Checking if buffer " << ii <<
" is stale.";
581 auto buf = getBufferInfo_(ii);
588 TLOG(TLVL_READREADY + 2) <<
"0x" << std::hex << shm_key_ << std::dec <<
" ReadReadyCount: Buffer " << ii <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" )";
590 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && (shm_ptr_->destructive_read_mode || buf->sequence_id > last_seen_id_))
593 TLOG(TLVL_READREADY + 3) <<
"0x" << std::hex << shm_key_ << std::dec <<
" ReadReadyCount: Buffer " << ii <<
" is either unowned or owned by this manager, and is marked full.";
608 TLOG(TLVL_WRITEREADY) <<
"0x" << std::hex << shm_key_ <<
" ReadReadyCount BEGIN" << std::dec;
609 std::unique_lock<std::mutex> lk(search_mutex_);
611 TLOG(TLVL_WRITEREADY) <<
"WriteReadyCount(" << overwrite <<
") lock acquired, scanning " << shm_ptr_->buffer_count <<
" buffers";
613 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
617 TLOG(TLVL_WRITEREADY + 1) <<
"0x" << std::hex << shm_key_ << std::dec <<
" WriteReadyCount: Checking if buffer " << ii <<
" is stale.";
620 auto buf = getBufferInfo_(ii);
625 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1) || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
628 TLOG(TLVL_WRITEREADY + 1) <<
"0x" << std::hex << shm_key_ << std::dec <<
" WriteReadyCount: Buffer " << ii <<
" is either empty or is available for overwrite.";
642 TLOG(TLVL_READREADY) <<
"0x" << std::hex << shm_key_ <<
" ReadyForRead BEGIN" << std::dec;
643 std::unique_lock<std::mutex> lk(search_mutex_);
646 auto rp = shm_ptr_->reader_pos.load();
648 TLOG(TLVL_READREADY) <<
"ReadyForRead lock acquired, scanning " << shm_ptr_->buffer_count <<
" buffers";
650 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
652 auto buffer = (rp + ii) % shm_ptr_->buffer_count;
655 TLOG(TLVL_READREADY + 1) <<
"0x" << std::hex << shm_key_ << std::dec <<
" ReadyForRead: Checking if buffer " << buffer <<
" is stale.";
658 auto buf = getBufferInfo_(buffer);
665 TLOG(TLVL_READREADY + 2) <<
"0x" << std::hex << shm_key_ << std::dec <<
" ReadyForRead: Buffer " << buffer <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" )"
666 <<
" seq_id=" << buf->sequence_id <<
" >? " << last_seen_id_;
669 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && (shm_ptr_->destructive_read_mode || buf->sequence_id > last_seen_id_))
671 TLOG(TLVL_READREADY + 3) <<
"0x" << std::hex << shm_key_ << std::dec <<
" ReadyForRead: Buffer " << buffer <<
" is either unowned or owned by this manager, and is marked full.";
685 TLOG(TLVL_WRITEREADY) <<
"0x" << std::hex << shm_key_ <<
" ReadyForWrite BEGIN" << std::dec;
687 std::lock_guard<std::mutex> lk(search_mutex_);
690 auto wp = shm_ptr_->writer_pos.load();
692 TLOG(TLVL_WRITEREADY) <<
"ReadyForWrite lock acquired, scanning " << shm_ptr_->buffer_count <<
" buffers";
694 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
696 auto buffer = (wp + ii) % shm_ptr_->buffer_count;
697 TLOG(TLVL_WRITEREADY + 1) <<
"0x" << std::hex << shm_key_ << std::dec <<
" ReadyForWrite: Checking if buffer " << buffer <<
" is stale.";
699 auto buf = getBufferInfo_(buffer);
704 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1) || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
706 TLOG(TLVL_WRITEREADY + 1) <<
"0x" << std::hex << shm_key_
708 <<
" WriteReadyCount: Buffer " << ii <<
" is either empty or available for overwrite.";
717 std::deque<int> output;
718 size_t buffer_count = size();
719 if (!IsValid() || buffer_count == 0)
723 TLOG(TLVL_BUFFER) <<
"GetBuffersOwnedByManager BEGIN. Locked? " << locked;
726 TLOG(TLVL_BUFLCK) <<
"GetBuffersOwnedByManager obtaining search_mutex";
727 std::lock_guard<std::mutex> lk(search_mutex_);
728 TLOG(TLVL_BUFLCK) <<
"GetBuffersOwnedByManager obtained search_mutex";
730 for (
size_t ii = 0; ii < buffer_count; ++ii)
732 auto buf = getBufferInfo_(ii);
737 if (buf->sem_id == manager_id_)
739 output.push_back(ii);
745 for (
size_t ii = 0; ii < buffer_count; ++ii)
747 auto buf = getBufferInfo_(ii);
752 if (buf->sem_id == manager_id_)
754 output.push_back(ii);
759 TLOG(TLVL_BUFFER) <<
"GetBuffersOwnedByManager: own " << output.size() <<
" / " << buffer_count <<
" buffers.";
765 TLOG(TLVL_BUFFER) <<
"BufferDataSize(" << buffer <<
") called.";
767 if (!shm_ptr_ || buffer >= shm_ptr_->buffer_count)
769 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
772 TLOG(TLVL_BUFLCK) <<
"BufferDataSize obtaining buffer_mutex for buffer " << buffer;
773 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
774 TLOG(TLVL_BUFLCK) <<
"BufferDataSize obtained buffer_mutex for buffer " << buffer;
777 auto buf = getBufferInfo_(buffer);
784 TLOG(TLVL_BUFFER) <<
"BufferDataSize: buffer " << buffer <<
", size=" << buf->writePos;
785 return buf->writePos;
790 TLOG(TLVL_POS) <<
"ResetReadPos(" << buffer <<
") called.";
792 if (buffer >= shm_ptr_->buffer_count)
794 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
797 TLOG(TLVL_BUFLCK) <<
"ResetReadPos obtaining buffer_mutex for buffer " << buffer;
798 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
799 TLOG(TLVL_BUFLCK) <<
"ResetReadPos obtained buffer_mutex for buffer " << buffer;
802 auto buf = getBufferInfo_(buffer);
803 if ((buf ==
nullptr) || buf->sem_id != manager_id_)
810 TLOG(TLVL_POS) <<
"ResetReadPos(" << buffer <<
") ended.";
815 TLOG(TLVL_POS + 1) <<
"ResetWritePos(" << buffer <<
") called.";
817 if (buffer >= shm_ptr_->buffer_count)
819 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
822 TLOG(TLVL_BUFLCK) <<
"ResetWritePos obtaining buffer_mutex for buffer " << buffer;
823 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
824 TLOG(TLVL_BUFLCK) <<
"ResetWritePos obtained buffer_mutex for buffer " << buffer;
827 auto buf = getBufferInfo_(buffer);
832 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
836 TLOG(TLVL_POS + 1) <<
"ResetWritePos(" << buffer <<
") ended.";
841 TLOG(TLVL_POS) <<
"IncrementReadPos called: buffer= " << buffer <<
", bytes to read=" << read;
843 if (buffer >= shm_ptr_->buffer_count)
845 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
848 TLOG(TLVL_BUFLCK) <<
"IncrementReadPos obtaining buffer_mutex for buffer " << buffer;
849 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
850 TLOG(TLVL_BUFLCK) <<
"IncrementReadPos obtained buffer_mutex for buffer " << buffer;
852 auto buf = getBufferInfo_(buffer);
853 if ((buf ==
nullptr) || buf->sem_id != manager_id_)
858 TLOG(TLVL_POS) <<
"IncrementReadPos: buffer= " << buffer <<
", readPos=" << buf->readPos <<
", bytes read=" << read;
859 buf->readPos = buf->readPos + read;
860 TLOG(TLVL_POS) <<
"IncrementReadPos: buffer= " << buffer <<
", New readPos is " << buf->readPos;
863 Detach(
true,
"LogicError",
"Cannot increment Read pos by 0! (buffer=" + std::to_string(buffer) +
", readPos=" + std::to_string(buf->readPos) +
", writePos=" + std::to_string(buf->writePos) +
")");
869 TLOG(TLVL_POS + 1) <<
"IncrementWritePos called: buffer= " << buffer <<
", bytes written=" << written;
871 if (buffer >= shm_ptr_->buffer_count)
873 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
876 TLOG(TLVL_BUFLCK) <<
"IncrementWritePos obtaining buffer_mutex for buffer " << buffer;
877 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
878 TLOG(TLVL_BUFLCK) <<
"IncrementWritePos obtained buffer_mutex for buffer " << buffer;
880 auto buf = getBufferInfo_(buffer);
885 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
887 if (buf->writePos + written > shm_ptr_->buffer_size)
889 TLOG(TLVL_ERROR) <<
"Requested write size is larger than the buffer size! (sz=" << std::hex << shm_ptr_->buffer_size <<
", cur + req=" << std::dec << buf->writePos + written <<
")";
892 TLOG(TLVL_POS + 1) <<
"IncrementWritePos: buffer= " << buffer <<
", writePos=" << buf->writePos <<
", bytes written=" << written;
893 buf->writePos += written;
894 TLOG(TLVL_POS + 1) <<
"IncrementWritePos: buffer= " << buffer <<
", New writePos is " << buf->writePos;
897 Detach(
true,
"LogicError",
"Cannot increment Write pos by 0!");
905 TLOG(TLVL_POS + 2) <<
"MoreDataInBuffer(" << buffer <<
") called.";
907 if (buffer >= shm_ptr_->buffer_count)
909 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
912 TLOG(TLVL_BUFLCK) <<
"MoreDataInBuffer obtaining buffer_mutex for buffer " << buffer;
913 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
914 TLOG(TLVL_BUFLCK) <<
"MoreDataInBuffer obtained buffer_mutex for buffer " << buffer;
916 auto buf = getBufferInfo_(buffer);
921 TLOG(TLVL_POS + 2) <<
"MoreDataInBuffer: buffer= " << buffer <<
", readPos=" << std::to_string(buf->readPos) <<
", writePos=" << buf->writePos;
922 return buf->readPos < buf->writePos;
927 if (buffer >= shm_ptr_->buffer_count)
929 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
932 TLOG(TLVL_BUFLCK) <<
"CheckBuffer obtaining buffer_mutex for buffer " << buffer;
933 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
934 TLOG(TLVL_BUFLCK) <<
"CheckBuffer obtained buffer_mutex for buffer " << buffer;
936 return checkBuffer_(getBufferInfo_(buffer), flags,
false);
941 if (buffer >= shm_ptr_->buffer_count)
943 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
946 TLOG(TLVL_BUFLCK) <<
"MarkBufferFull obtaining buffer_mutex for buffer " << buffer;
947 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
948 TLOG(TLVL_BUFLCK) <<
"MarkBufferFull obtained buffer_mutex for buffer " << buffer;
951 auto shmBuf = getBufferInfo_(buffer);
952 if (shmBuf ==
nullptr)
956 touchBuffer_(shmBuf);
957 if (shmBuf->sem_id == manager_id_)
959 if (shmBuf->sem != BufferSemaphoreFlags::Full)
961 shmBuf->sem = BufferSemaphoreFlags::Full;
964 shmBuf->sem_id = destination;
970 TLOG(TLVL_POS + 3) <<
"MarkBufferEmpty BEGIN, buffer=" << buffer <<
", force=" << force <<
", manager_id_=" << manager_id_;
971 if (buffer >= shm_ptr_->buffer_count)
973 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
975 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
977 auto shmBuf = getBufferInfo_(buffer);
978 if (shmBuf ==
nullptr)
984 auto ret = checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading, detachOnException);
987 touchBuffer_(shmBuf);
990 shmBuf->sem = BufferSemaphoreFlags::Full;
992 if ((force && (manager_id_ == 0 || manager_id_ == shmBuf->sem_id)) || (!force && shm_ptr_->destructive_read_mode))
994 TLOG(TLVL_POS + 3) <<
"MarkBufferEmpty Resetting buffer " << buffer <<
" to Empty state";
995 shmBuf->writePos = 0;
996 shmBuf->sem = BufferSemaphoreFlags::Empty;
997 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer) && !shm_ptr_->destructive_read_mode)
999 TLOG(TLVL_POS + 3) <<
"MarkBufferEmpty Broadcast mode; incrementing reader_pos from " << shm_ptr_->reader_pos <<
" to " << (buffer + 1) % shm_ptr_->buffer_count;
1000 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
1003 shmBuf->sem_id = -1;
1004 TLOG(TLVL_POS + 3) <<
"MarkBufferEmpty END, buffer=" << buffer <<
", force=" << force;
1009 if (buffer >= shm_ptr_->buffer_count)
1011 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
1016 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
1020 auto shmBuf = getBufferInfo_(buffer);
1021 if (shmBuf ==
nullptr)
1036 if (delta > 0xFFFFFFFF)
1038 TLOG(TLVL_RESET) <<
"Buffer has touch time in the future, setting it to current time and ignoring...";
1042 if (shm_ptr_->buffer_timeout_us == 0 || delta <= shm_ptr_->buffer_timeout_us || shmBuf->sem == BufferSemaphoreFlags::Empty)
1046 TLOG(TLVL_RESET) <<
"Buffer " << buffer <<
" at " <<
static_cast<void*
>(shmBuf) <<
" is stale, time=" <<
TimeUtils::gettimeofday_us() <<
", last touch=" << shmBuf->last_touch_time <<
", d=" << delta <<
", timeout=" << shm_ptr_->buffer_timeout_us;
1048 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing)
1053 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full && manager_id_ == 0)
1055 TLOG(TLVL_RESET) <<
"Resetting old broadcast mode buffer " << buffer <<
" (seqid=" << shmBuf->sequence_id <<
"). State: Full-->Empty";
1056 shmBuf->writePos = 0;
1057 shmBuf->sem = BufferSemaphoreFlags::Empty;
1058 shmBuf->sem_id = -1;
1059 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer))
1061 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
1066 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading)
1070 if (delta <= shm_ptr_->buffer_timeout_us)
1074 TLOG(TLVL_WARNING) <<
"Stale Read buffer " << buffer <<
" at " <<
static_cast<void*
>(shmBuf)
1075 <<
" ( " << delta <<
" / " << shm_ptr_->buffer_timeout_us <<
" us ) detected! (seqid="
1076 << shmBuf->sequence_id <<
") Resetting... Reading-->Full";
1077 shmBuf->readPos = 0;
1078 shmBuf->sem = BufferSemaphoreFlags::Full;
1079 shmBuf->sem_id = -1;
1092 struct shmid_ds info;
1093 auto sts = shmctl(shm_segment_id_, IPC_STAT, &info);
1096 TLOG(TLVL_BUFINFO) <<
"Error accessing Shared Memory info: " << errno <<
" (" << strerror(errno) <<
").";
1100 if ((info.shm_perm.mode & SHM_DEST) != 0)
1102 TLOG(TLVL_INFO) <<
"Shared Memory marked for destruction. Probably an end-of-data condition!";
1116 struct shmid_ds info;
1117 auto sts = shmctl(shm_segment_id_, IPC_STAT, &info);
1120 TLOG(TLVL_BUFINFO) <<
"Error accessing Shared Memory info: " << errno <<
" (" << strerror(errno) <<
").";
1124 return info.shm_nattch;
1129 TLOG(TLVL_WRITE) <<
"Write BEGIN";
1130 if (buffer >= shm_ptr_->buffer_count)
1132 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
1134 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
1136 auto shmBuf = getBufferInfo_(buffer);
1137 if (shmBuf ==
nullptr)
1141 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing);
1142 touchBuffer_(shmBuf);
1143 TLOG(TLVL_WRITE) <<
"Buffer Write Pos is " << std::hex << std::showbase << shmBuf->writePos <<
", write size is " << size;
1144 if (shmBuf->writePos + size > shm_ptr_->buffer_size)
1146 TLOG(TLVL_ERROR) <<
"Attempted to write more data than fits into Shared Memory, bufferSize=" << std::hex << std::showbase << shm_ptr_->buffer_size
1147 <<
",writePos=" << shmBuf->writePos <<
",writeSize=" << size;
1148 Detach(
true,
"SharedMemoryWrite",
"Attempted to write more data than fits into Shared Memory! \nRe-run with a larger buffer size!");
1151 auto pos = GetWritePos(buffer);
1152 memcpy(pos, data, size);
1153 touchBuffer_(shmBuf);
1154 shmBuf->writePos = shmBuf->writePos + size;
1156 auto last_seen = last_seen_id_.load();
1157 while (last_seen < shmBuf->sequence_id && !last_seen_id_.compare_exchange_weak(last_seen, shmBuf->sequence_id)) {}
1159 TLOG(TLVL_WRITE) <<
"Write END";
1165 if (buffer >= shm_ptr_->buffer_count)
1167 Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
1169 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]);
1171 auto shmBuf = getBufferInfo_(buffer);
1172 if (shmBuf ==
nullptr)
1176 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading);
1177 touchBuffer_(shmBuf);
1178 if (shmBuf->readPos + size > shm_ptr_->buffer_size)
1180 TLOG(TLVL_ERROR) <<
"Attempted to read more data than fits into Shared Memory, bufferSize=" << shm_ptr_->buffer_size
1181 <<
",readPos=" << shmBuf->readPos <<
",readSize=" << size;
1182 Detach(
true,
"SharedMemoryRead",
"Attempted to read more data than exists in Shared Memory!");
1185 auto pos = GetReadPos(buffer);
1186 TLOG(TLVL_READ) <<
"Before memcpy in Read(), size is " << size;
1187 memcpy(data, pos, size);
1188 TLOG(TLVL_READ) <<
"After memcpy in Read()";
1189 auto sts = checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
false);
1192 shmBuf->readPos += size;
1193 touchBuffer_(shmBuf);
1201 if (shm_ptr_ ==
nullptr)
1203 return "Not connected to shared memory";
1205 std::ostringstream ostr;
1206 ostr <<
"ShmStruct: " << std::endl
1207 <<
"Reader Position: " << shm_ptr_->reader_pos << std::endl
1208 <<
"Writer Position: " << shm_ptr_->writer_pos << std::endl
1209 <<
"Next ID Number: " << shm_ptr_->next_id << std::endl
1210 <<
"Buffer Count: " << shm_ptr_->buffer_count << std::endl
1211 <<
"Buffer Size: " << std::to_string(shm_ptr_->buffer_size) <<
" bytes" << std::endl
1212 <<
"Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl
1213 <<
"Rank of Writer: " << shm_ptr_->rank << std::endl
1214 <<
"Number of Writers: " << shm_ptr_->writer_count << std::endl
1215 <<
"Number of Readers: " << shm_ptr_->reader_count << std::endl
1216 <<
"Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::dec << std::endl
1219 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
1221 auto buf = getBufferInfo_(ii);
1227 ostr <<
"ShmBuffer " << std::dec << ii << std::endl
1228 <<
"sequenceID: " << std::to_string(buf->sequence_id) << std::endl
1229 <<
"writePos: " << std::to_string(buf->writePos) << std::endl
1230 <<
"readPos: " << std::to_string(buf->readPos) << std::endl
1231 <<
"sem: " << FlagToString(buf->sem) << std::endl
1232 <<
"Owner: " << std::to_string(buf->sem_id.load()) << std::endl
1233 <<
"Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl
1242 auto buf = getBufferInfo_(buffer);
1247 return bufferStart_(buffer) + buf->readPos;
1251 auto buf = getBufferInfo_(buffer);
1256 return bufferStart_(buffer) + buf->writePos;
1261 return bufferStart_(buffer);
1266 auto output = std::vector<std::pair<int, BufferSemaphoreFlags>>(size());
1267 for (
size_t ii = 0; ii < size(); ++ii)
1269 auto buf = getBufferInfo_(ii);
1270 output[ii] = std::make_pair(buf->sem_id.load(), buf->sem.load());
1275 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags,
bool exceptions)
1277 if (buffer ==
nullptr)
1281 Detach(
true,
"BufferNotThereException",
"Request to check buffer that does not exist!");
1285 TLOG(TLVL_CHKBUFFER) <<
"checkBuffer_: Checking that buffer " << buffer->sequence_id <<
" has sem_id " << manager_id_ <<
" (Current: " << buffer->sem_id <<
") and is in state " << FlagToString(flags) <<
" (current: " << FlagToString(buffer->sem) <<
")";
1288 if (buffer->sem != flags)
1290 Detach(
true,
"StateAccessViolation",
"Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) +
", actual " + FlagToString(buffer->sem) +
")");
1292 if (buffer->sem_id != manager_id_)
1294 Detach(
true,
"OwnerAccessViolation",
"Shared Memory buffer is not owned by this manager instance! (Expected: " + std::to_string(manager_id_) +
", Actual: " + std::to_string(buffer->sem_id) +
")");
1297 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags;
1301 TLOG(TLVL_WARNING) <<
"CheckBuffer detected issue with buffer " << buffer->sequence_id <<
"!"
1302 <<
" ID: " << buffer->sem_id <<
" (Expected " << manager_id_ <<
"), Flag: " << FlagToString(buffer->sem) <<
" (Expected " << FlagToString(flags) <<
"). "
1303 << R
"(ID -1 is okay if expected flag is "Full" or "Empty".)";
1309 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer)
1311 if ((buffer ==
nullptr) || (buffer->sem_id != -1 && buffer->sem_id != manager_id_))
1315 TLOG(TLVL_CHKBUFFER + 1) <<
"touchBuffer_: Touching buffer at " <<
static_cast<void*
>(buffer) <<
" with sequence_id " << buffer->sequence_id;
1321 TLOG(TLVL_DETACH) <<
"Detach BEGIN: throwException: " << std::boolalpha << throwException <<
", force: " << force;
1324 TLOG(TLVL_DETACH) <<
"Detach: Resetting owned buffers";
1325 auto bufs = GetBuffersOwnedByManager(
false);
1326 for (
auto buf : bufs)
1328 auto shmBuf = getBufferInfo_(buf);
1329 if (shmBuf ==
nullptr)
1333 if (shmBuf->sem == BufferSemaphoreFlags::Writing)
1335 shmBuf->sem = BufferSemaphoreFlags::Empty;
1337 else if (shmBuf->sem == BufferSemaphoreFlags::Reading)
1339 shmBuf->sem = BufferSemaphoreFlags::Full;
1341 shmBuf->sem_id = -1;
1343 if(registered_reader_) {
1344 shm_ptr_->reader_count--;
1345 registered_reader_ =
false;
1347 if(registered_writer_){
1348 shm_ptr_->writer_count--;
1349 registered_writer_ =
false;
1353 if (shm_ptr_ !=
nullptr)
1355 TLOG(TLVL_DETACH) <<
"Detach: Detaching shared memory";
1360 if ((force || manager_id_ == 0) && shm_segment_id_ > -1)
1362 TLOG(TLVL_DETACH) <<
"Detach: Marking Shared memory for removal";
1363 shmctl(shm_segment_id_, IPC_RMID,
nullptr);
1364 shm_segment_id_ = -1;
1370 if (!category.empty() && !message.empty())
1372 TLOG(TLVL_ERROR) << category <<
": " << message;
1376 throw cet::exception(category) << message;
void Detach(bool throwException=false, const std::string &category="", const std::string &message="", bool force=false)
Detach from the Shared Memory segment, optionally throwing a cet::exception with the specified proper...
bool Read(int buffer, void *data, size_t size)
Read size bytes of data from buffer into the given pointer.
void IncrementReadPos(int buffer, size_t read)
Increment the read position for a given buffer.
bool Attach(size_t timeout_usec=0)
Reconnect to the shared memory segment.
std::deque< int > GetBuffersOwnedByManager(bool locked=true)
Get the list of all buffers currently owned by this manager instance.
void ResetReadPos(int buffer)
Set the read position of the given buffer to the beginning of the buffer.
bool MoreDataInBuffer(int buffer)
Determine if more data is available to be read, based on the read position and data size...
virtual std::string toString()
Write information about the SharedMemory to a string.
size_t GetElapsedTimeMicroseconds(std::chrono::steady_clock::time_point then, std::chrono::steady_clock::time_point now=std::chrono::steady_clock::now())
Gets the number of microseconds in the given time interval
std::vector< std::pair< int, BufferSemaphoreFlags > > GetBufferReport()
Get a report on the status of each buffer.
BufferSemaphoreFlags
The BufferSemaphoreFlags enumeration represents the different possible "states" of a given shared mem...
size_t BufferDataSize(int buffer)
Get the current size of the buffer's data.
virtual ~SharedMemoryManager() noexcept
SharedMemoryManager Destructor.
The SharedMemoryManager creates a Shared Memory area which is divided into a number of fixed-size buf...
size_t ReadReadyCount()
Count the number of buffers that are ready for reading.
bool ResetBuffer(int buffer)
Resets the buffer from Reading to Full. This operation will only have an effect if performed by the o...
bool IncrementWritePos(int buffer, size_t written)
Increment the write position for a given buffer.
bool IsEndOfData() const
Determine whether the Shared Memory is marked for destruction (End of Data)
bool CheckBuffer(int buffer, BufferSemaphoreFlags flags)
Check both semaphore conditions (Mode flag and manager ID) for a given buffer.
void MarkBufferFull(int buffer, int destination=-1)
Release a buffer from a writer, marking it Full and ready for a reader.
void MarkBufferEmpty(int buffer, bool force=false, bool detachOnException=true)
Release a buffer from a reader, marking it Empty and ready to accept more data.
void ResetWritePos(int buffer)
Set the write position of the given buffer to the beginning of the buffer.
void * GetWritePos(int buffer)
Get a pointer to the current write position of the buffer.
size_t Write(int buffer, void *data, size_t size)
Write size bytes of data from the given pointer to a buffer.
void * GetReadPos(int buffer)
Get a pointer to the current read position of the buffer.
void * GetBufferStart(int buffer)
Get a pointer to the start position of the buffer.
SharedMemoryManager(uint32_t shm_key, size_t buffer_count=0, size_t buffer_size=0, uint64_t buffer_timeout_us=100 *1000000, bool destructive_read_mode=true)
SharedMemoryManager Constructor.
bool ReadyForRead()
Whether any buffer is ready for read.
int GetBufferForWriting(bool overwrite)
Finds a buffer that is ready to be written to, and reserves it for the calling manager.
uint16_t GetAttachedCount() const
Get the number of attached SharedMemoryManagers.
size_t WriteReadyCount(bool overwrite)
Count the number of buffers that are ready for writing.
uint64_t gettimeofday_us()
Get the current time of day in microseconds (from gettimeofday system call)
int GetBufferForReading()
Finds a buffer that is ready to be read, and reserves it for the calling manager. ...
virtual bool ReadyForWrite(bool overwrite)
Whether any buffer is available for write.