RTXI  2.4
The Real-Time eXperiment Interface Documentation
atomic_fifo.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 Georgia Institute of Technology, University of Utah, Weill Cornell Medical College
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17  */
18 
19 #include <debug.h>
20 #include <iostream>
21 #include <atomic_fifo.h>
22 #include <string.h>
23 
25  : head(0), tail(0), fifoSize(s)
26 {
27  data = new char[fifoSize];
28 }
29 
31 {
32  if(data) delete[] data;
33 }
34 
35 bool AtomicFifo::write(const void *buffer,size_t itemSize) // It is an absolute requirement only one thread calls write
36 {
37  // Uses sequential consistent memory order, all atomic operations are
38  // guaranteed not to be reordered within the same thread
39  const auto current_tail = tail.load(std::memory_order_seq_cst);
40 
41  if( itemSize >= fifoSize - ((fifoSize + current_tail - head.load(std::memory_order_seq_cst)) % fifoSize) )
42  {
43  ERROR_MSG("AtomicFifo::write : fifo full, data lost\n");
44  return false;
45  }
46 
47  if(itemSize > fifoSize - current_tail) // If needed, data is split between end and beginning of fifo
48  {
49  size_t m = fifoSize - current_tail;
50  memcpy(data + current_tail, buffer, m); // Copy first part of data
51  memcpy(data, reinterpret_cast<const char *>(buffer) + m, itemSize - m); // Copy last part of data
52  }
53  else
54  memcpy(data + current_tail, buffer, itemSize);
55 
56  tail.store(increment(current_tail, itemSize));
57 
58  return true;
59 }
60 
61 bool AtomicFifo::read(void *buffer,size_t itemSize) // It is an absolute requirement only one thread calls read
62 {
63  // Uses strictest memory order, atomic operations are guaranteed not to be
64  // reordered within the same thread
65  const auto current_head = head.load(std::memory_order_seq_cst);
66 
67  // Check if there is data to be read, and it is at least as large as item size
68  // Left side of logical returns number of bytes available to be read
69  if( ((fifoSize + tail.load(std::memory_order_seq_cst) - current_head) % fifoSize) < itemSize )
70  {
71  return false; // no data to be read
72  }
73 
74  // Copy data from fifo to buffer
75  if(fifoSize - current_head < itemSize) // If data is split between end and beginning of fifo
76  {
77  size_t m = fifoSize - current_head;
78  memcpy(buffer, data + current_head, m); // Retrieve first part of data
79  memcpy(reinterpret_cast<char *>(buffer) + m, data, itemSize - m ); // Retrieve last part of data
80  }
81  else
82  memcpy(buffer, data + current_head, itemSize);
83 
84  head.store(increment(current_head, itemSize));
85 
86  return true;
87 }
88 
89 size_t AtomicFifo::increment(size_t current_ptr, size_t itemSize) const
90 {
91  return (current_ptr + itemSize) % fifoSize;
92 }
93 
95 {
96  return (tail.is_lock_free() && head.is_lock_free());
97 }
ERROR_MSG
void ERROR_MSG(const std::string &errmsg,...)
Definition: debug.cpp:27
AtomicFifo::write
bool write(const void *buffer, size_t itemSize)
Definition: atomic_fifo.cpp:35
AtomicFifo::AtomicFifo
AtomicFifo(size_t)
Definition: atomic_fifo.cpp:24
AtomicFifo::isLockFree
bool isLockFree() const
Definition: atomic_fifo.cpp:94
AtomicFifo::~AtomicFifo
~AtomicFifo(void)
Definition: atomic_fifo.cpp:30
atomic_fifo.h
AtomicFifo::read
bool read(void *buffer, size_t itemSize)
Definition: atomic_fifo.cpp:61
debug.h