RTXI  3.0.0
The Real-Time eXperiment Interface Reference Manual
fifo_posix.cpp
Go to the documentation of this file.
1 /*
2  The Real-Time eXperiment Interface (RTXI)
3  Copyright (C) 2011 Georgia Institute of Technology, University of Utah,
4  Will Cornell Medical College
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 #include <array>
22 
23 #include "fifo.hpp"
24 
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <sys/eventfd.h>
28 #include <sys/poll.h>
29 #include <unistd.h>
30 
31 #include "debug.hpp"
32 
33 // Generic posix fifo based on pipes
34 namespace RT::OS
35 {
36 class posixFifo : public RT::OS::Fifo
37 {
38 public:
39  explicit posixFifo(size_t size);
40  posixFifo(const posixFifo& fifo) = delete;
41  posixFifo& operator=(const posixFifo& fifo) = delete;
42  posixFifo(posixFifo&&) = default;
43  posixFifo& operator=(posixFifo&&) = default;
44  ~posixFifo() override;
45 
46  size_t getCapacity() override;
47  int64_t read(void* buf, size_t data_size) override;
48  int64_t write(void* buf, size_t data_size) override;
49  int64_t readRT(void* buf, size_t data_size) override;
50  int64_t writeRT(void* buf, size_t data_size) override;
51  void poll() override;
52  void close() override;
53  int getErrorCode() const;
54 
55 private:
56  std::array<int, 2> ui_to_rt {};
57  std::array<int, 2> rt_to_ui {};
58 
59  size_t fifo_capacity = 0;
60  int close_event_fd;
61  std::array<struct pollfd, 2> xbuf_poll_fd {};
62  bool closed = false;
63  int errcode = 0;
64 };
65 } // namespace RT::OS
66 
68  : fifo_capacity(size)
69  , errcode(pipe2(this->rt_to_ui.data(), O_CLOEXEC))
70 {
71  if (this->errcode != 0) {
72  ERROR_MSG("RT::OS::posixFifo : Unable to create RT to UI buffer");
73  return;
74  }
75  this->errcode = pipe2(this->ui_to_rt.data(), O_CLOEXEC);
76  if (this->errcode != 0) {
77  ERROR_MSG("RT::OS::posixFifo : Unable to create UI to RT buffer");
78  return;
79  }
80  // Make sure the reads/writes are nonblock to match api behavior
81  fcntl(this->rt_to_ui[0], F_SETFL, O_NONBLOCK);
82  fcntl(this->rt_to_ui[1], F_SETFL, O_NONBLOCK);
83  fcntl(this->ui_to_rt[0], F_SETFL, O_NONBLOCK);
84  fcntl(this->rt_to_ui[1], F_SETFL, O_NONBLOCK);
85 
86  // We can set the size of the pipe. Again we try to match api behavior
87  fcntl(this->rt_to_ui[1], F_SETPIPE_SZ, size);
88  fcntl(this->ui_to_rt[1], F_SETPIPE_SZ, size);
89 
90  // setup polling mechanism (polling only supported from ui read side)
91  this->xbuf_poll_fd[0].fd = this->rt_to_ui[0];
92  this->xbuf_poll_fd[0].events = POLLIN;
93  this->close_event_fd = eventfd(0, EFD_NONBLOCK);
94  this->xbuf_poll_fd[1].fd = this->close_event_fd;
95  this->xbuf_poll_fd[1].events = POLLIN;
96 }
97 
99 {
100  ::close(rt_to_ui[0]);
101  ::close(rt_to_ui[1]);
102  ::close(ui_to_rt[0]);
103  ::close(ui_to_rt[1]);
104 }
105 
106 int64_t RT::OS::posixFifo::read(void* buf, size_t data_size)
107 {
108  return ::read(rt_to_ui[0], buf, data_size);
109 }
110 
111 int64_t RT::OS::posixFifo::write(void* buf, size_t data_size)
112 {
113  return ::write(ui_to_rt[1], buf, data_size);
114 }
115 
116 int64_t RT::OS::posixFifo::readRT(void* buf, size_t data_size)
117 {
118  return ::read(ui_to_rt[0], buf, data_size);
119 }
120 
121 int64_t RT::OS::posixFifo::writeRT(void* buf, size_t data_size)
122 {
123  return ::write(rt_to_ui[1], buf, data_size);
124 }
125 
127 {
128  this->errcode = ::poll(this->xbuf_poll_fd.data(), 2, -1);
129  if (errcode < 0) {
130  std::string errbuff(255, '\0');
131  ERROR_MSG("RT::OS::FIFO(evl)::poll : returned with failure code {} : ",
132  errcode);
133  ERROR_MSG("{}", strerror_r(this->errcode, errbuff.data(), errbuff.size()));
134  } else if ((this->xbuf_poll_fd[1].revents & POLLIN) != 0) {
135  this->closed = true;
136  }
137 }
138 
140 {
141  std::array<int64_t, 1> buf = {1};
142  this->closed = true;
143  ::write(this->close_event_fd, buf.data(), sizeof(int64_t));
144 }
145 
147 {
148  return this->fifo_capacity;
149 }
150 
152 {
153  return this->errcode;
154 }
155 
156 int RT::OS::getFifo(std::unique_ptr<Fifo>& fifo, size_t fifo_size)
157 {
158  auto tmp_fifo = std::make_unique<RT::OS::posixFifo>(fifo_size);
159  const int errcode = tmp_fifo->getErrorCode();
160  if (errcode != 0) {
161  std::string errbuff(255, '\0');
162  ERROR_MSG("RT::OS::posixFifo : {}",
163  strerror_r(errcode, errbuff.data(), errbuff.size()));
164  } else {
165  fifo = std::move(tmp_fifo);
166  }
167  return errcode;
168 }
int getErrorCode() const
Definition: fifo_posix.cpp:151
size_t getCapacity() override
Definition: fifo_posix.cpp:146
~posixFifo() override
Definition: fifo_posix.cpp:98
posixFifo(posixFifo &&)=default
posixFifo & operator=(const posixFifo &fifo)=delete
int64_t write(void *buf, size_t data_size) override
Definition: fifo_posix.cpp:111
int64_t read(void *buf, size_t data_size) override
Definition: fifo_posix.cpp:106
posixFifo(const posixFifo &fifo)=delete
void close() override
Definition: fifo_posix.cpp:139
posixFifo & operator=(posixFifo &&)=default
int64_t readRT(void *buf, size_t data_size) override
Definition: fifo_posix.cpp:116
void poll() override
Definition: fifo_posix.cpp:126
int64_t writeRT(void *buf, size_t data_size) override
Definition: fifo_posix.cpp:121
posixFifo(size_t size)
Definition: fifo_posix.cpp:67
void ERROR_MSG(const std::string &errmsg, Args... args)
Definition: debug.hpp:36
Definition: fifo.cpp:31
int getFifo(std::unique_ptr< Fifo > &fifo, size_t fifo_size)
Definition: fifo.cpp:194