00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "FileDescriptorActivity.hpp"
00040 #include "../ExecutionEngine.hpp"
00041 #include "../base/TaskCore.hpp"
00042 #include "../Logger.hpp"
00043
00044
00045 #include <algorithm>
00046
00047 #ifdef WIN32
00048 #include <io.h>
00049 #include <fcntl.h>
00050 #define pipe(X) _pipe((X), 1024, _O_BINARY)
00051 #define close _close
00052 #define write _write
00053 #undef max
00054
00055 #else
00056 #include <sys/select.h>
00057 #include <unistd.h>
00058 #include <errno.h>
00059 #endif
00060
00061 #include <boost/cstdint.hpp>
00062
00063 using namespace RTT;
00064 using namespace extras;
00065 using namespace base;
00066 const char FileDescriptorActivity::CMD_BREAK_LOOP;
00067 const char FileDescriptorActivity::CMD_TRIGGER;
00068 const char FileDescriptorActivity::CMD_UPDATE_SETS;
00069
00070
00079 FileDescriptorActivity::FileDescriptorActivity(int priority, RunnableInterface* _r, const std::string& name )
00080 : Activity(priority, 0.0, _r, name)
00081 , m_running(false)
00082 , m_timeout_us(0)
00083 , m_period(0)
00084 , m_has_error(false)
00085 , m_has_timeout(false)
00086 {
00087 FD_ZERO(&m_fd_set);
00088 FD_ZERO(&m_fd_work);
00089 m_interrupt_pipe[0] = m_interrupt_pipe[1] = -1;
00090 }
00091
00101 FileDescriptorActivity::FileDescriptorActivity(int scheduler, int priority, RunnableInterface* _r, const std::string& name )
00102 : Activity(scheduler, priority, 0.0, _r, name)
00103 , m_running(false)
00104 , m_timeout_us(0)
00105 , m_period(0)
00106 , m_has_error(false)
00107 , m_has_timeout(false)
00108 {
00109 FD_ZERO(&m_fd_set);
00110 FD_ZERO(&m_fd_work);
00111 m_interrupt_pipe[0] = m_interrupt_pipe[1] = -1;
00112 }
00113
00114 FileDescriptorActivity::FileDescriptorActivity(int scheduler, int priority, Seconds period, RunnableInterface* _r, const std::string& name )
00115 : Activity(scheduler, priority, 0.0, _r, name)
00116 , m_running(false)
00117 , m_timeout_us(0)
00118 , m_period(period >= 0.0 ? period : 0.0)
00119 , m_has_error(false)
00120 , m_has_timeout(false)
00121 {
00122 FD_ZERO(&m_fd_set);
00123 FD_ZERO(&m_fd_work);
00124 m_interrupt_pipe[0] = m_interrupt_pipe[1] = -1;
00125 }
00126
00127 FileDescriptorActivity::FileDescriptorActivity(int scheduler, int priority, Seconds period, unsigned cpu_affinity, RunnableInterface* _r, const std::string& name )
00128 : Activity(scheduler, priority, 0.0, cpu_affinity, _r, name)
00129 , m_running(false)
00130 , m_timeout_us(0)
00131 , m_period(period >= 0.0 ? period : 0.0)
00132 , m_has_error(false)
00133 , m_has_timeout(false)
00134 {
00135 FD_ZERO(&m_fd_set);
00136 FD_ZERO(&m_fd_work);
00137 m_interrupt_pipe[0] = m_interrupt_pipe[1] = -1;
00138 }
00139
00140 FileDescriptorActivity::~FileDescriptorActivity()
00141 {
00142 stop();
00143 }
00144
00145 Seconds FileDescriptorActivity::getPeriod() const
00146 { return m_period; }
00147
00148 bool FileDescriptorActivity::setPeriod(Seconds p)
00149 {
00150 if (p < 0)
00151 return false;
00152 m_period = p;
00153 return true;
00154 }
00155
00156 bool FileDescriptorActivity::isRunning() const
00157 { return Activity::isRunning() && m_running; }
00158 int FileDescriptorActivity::getTimeout() const
00159 { return m_timeout_us / 1000; }
00160 int FileDescriptorActivity::getTimeout_us() const
00161 { return m_timeout_us; }
00162 void FileDescriptorActivity::setTimeout(int timeout)
00163 {
00164 setTimeout_us(timeout * 1000);
00165 }
00166 void FileDescriptorActivity::setTimeout_us(int timeout_us)
00167 {
00168 if (0 <= timeout_us)
00169 {
00170 m_timeout_us = timeout_us;
00171 }
00172 else
00173 {
00174 log(Error) << "Ignoring invalid timeout (" << timeout_us << ")" << endlog();
00175 }
00176 }
00177 void FileDescriptorActivity::watch(int fd)
00178 { RTT::os::MutexLock lock(m_lock);
00179 if (fd < 0)
00180 {
00181 log(Error) << "negative file descriptor given to FileDescriptorActivity::watch" << endlog();
00182 return;
00183 }
00184
00185 m_watched_fds.insert(fd);
00186 FD_SET(fd, &m_fd_set);
00187 triggerUpdateSets();
00188 }
00189 void FileDescriptorActivity::unwatch(int fd)
00190 { RTT::os::MutexLock lock(m_lock);
00191 m_watched_fds.erase(fd);
00192 FD_CLR(fd, &m_fd_set);
00193 triggerUpdateSets();
00194 }
00195 void FileDescriptorActivity::clearAllWatches()
00196 { RTT::os::MutexLock lock(m_lock);
00197 m_watched_fds.clear();
00198 FD_ZERO(&m_fd_set);
00199 triggerUpdateSets();
00200 }
00201 void FileDescriptorActivity::triggerUpdateSets()
00202 {
00203
00204 int i = write(m_interrupt_pipe[1], &CMD_UPDATE_SETS, 1);
00205 i = i;
00206 }
00207 bool FileDescriptorActivity::isUpdated(int fd) const
00208 { return FD_ISSET(fd, &m_fd_work); }
00209 bool FileDescriptorActivity::hasError() const
00210 { return m_has_error; }
00211 bool FileDescriptorActivity::hasTimeout() const
00212 { return m_has_timeout; }
00213 bool FileDescriptorActivity::isWatched(int fd) const
00214 { RTT::os::MutexLock lock(m_lock);
00215 return FD_ISSET(fd, &m_fd_set); }
00216
00217 bool FileDescriptorActivity::start()
00218 {
00219 if ( isActive() )
00220 return false;
00221
00222 if (pipe(m_interrupt_pipe) == -1)
00223 {
00224 log(Error) << "FileDescriptorActivity: cannot create control pipe" << endlog();
00225 return false;
00226 }
00227
00228 if (!Activity::start())
00229 {
00230 close(m_interrupt_pipe[0]);
00231 close(m_interrupt_pipe[1]);
00232 m_interrupt_pipe[0] = m_interrupt_pipe[1] = -1;
00233 log(Error) << "FileDescriptorActivity: Activity::start() failed" << endlog();
00234 return false;
00235 }
00236 return true;
00237 }
00238
00239 bool FileDescriptorActivity::trigger()
00240 {
00241 if (isActive() )
00242 return write(m_interrupt_pipe[1], &CMD_TRIGGER, 1) == 1;
00243 else
00244 return false;
00245 }
00246
00247 struct fd_watch {
00248 int& fd;
00249 fd_watch(int& fd) : fd(fd) {}
00250 ~fd_watch()
00251 {
00252 if (fd != -1)
00253 close(fd);
00254 fd = -1;
00255 };
00256 };
00257
00258 void FileDescriptorActivity::loop()
00259 {
00260 int pipe = m_interrupt_pipe[0];
00261 fd_watch watch_pipe_0(m_interrupt_pipe[0]);
00262 fd_watch watch_pipe_1(m_interrupt_pipe[1]);
00263
00264 while(true)
00265 {
00266 int max_fd;
00267 { RTT::os::MutexLock lock(m_lock);
00268 if (m_watched_fds.empty())
00269 max_fd = pipe;
00270 else
00271 max_fd = std::max(pipe, *m_watched_fds.rbegin());
00272
00273 m_fd_work = m_fd_set;
00274 }
00275 FD_SET(pipe, &m_fd_work);
00276
00277 int ret;
00278 m_running = false;
00279 if (m_timeout_us == 0)
00280 {
00281 ret = select(max_fd + 1, &m_fd_work, NULL, NULL, NULL);
00282 }
00283 else
00284 {
00285 static const int USECS_PER_SEC = 1000000;
00286 timeval timeout = { m_timeout_us / USECS_PER_SEC,
00287 m_timeout_us % USECS_PER_SEC};
00288 ret = select(max_fd + 1, &m_fd_work, NULL, NULL, &timeout);
00289 }
00290
00291 m_has_error = false;
00292 m_has_timeout = false;
00293 if (ret == -1)
00294 {
00295 log(Error) << "FileDescriptorActivity: error in select(), errno = " << errno << endlog();
00296 m_has_error = true;
00297 }
00298 else if (ret == 0)
00299 {
00300 log(Error) << "FileDescriptorActivity: timeout in select()" << endlog();
00301 m_has_timeout = true;
00302 }
00303
00304 bool do_break = false, do_trigger = true;
00305 if (ret > 0 && FD_ISSET(pipe, &m_fd_work))
00306 {
00307
00308
00309
00310 fd_set watch_pipe;
00311 timeval timeout;
00312
00313 do_trigger = false;
00314 do
00315 {
00316 boost::uint8_t code;
00317 if (read(pipe, &code, 1) == 1)
00318 {
00319 if (code == CMD_BREAK_LOOP)
00320 {
00321 do_break = true;
00322 }
00323 else if (code == CMD_UPDATE_SETS){}
00324 else
00325 do_trigger = true;
00326 }
00327
00328
00329 FD_ZERO(&watch_pipe);
00330 FD_SET(pipe, &watch_pipe);
00331 timeout.tv_sec = 0;
00332 timeout.tv_usec = 0;
00333 }
00334 while(select(pipe + 1, &watch_pipe, NULL, NULL, &timeout) > 0);
00335
00336 if (do_break)
00337 break;
00338 }
00339
00340 if (do_trigger)
00341 {
00342 try
00343 {
00344 m_running = true;
00345 step();
00346 m_running = false;
00347 }
00348 catch(...)
00349 {
00350 m_running = false;
00351 throw;
00352 }
00353 }
00354 }
00355 }
00356
00357 bool FileDescriptorActivity::breakLoop()
00358 {
00359 if (write(m_interrupt_pipe[1], &CMD_BREAK_LOOP, 1) != 1)
00360 return false;
00361
00362
00363
00364
00365 return true;
00366 }
00367
00368 void FileDescriptorActivity::step()
00369 {
00370 m_running = true;
00371 if (runner != 0)
00372 runner->step();
00373 m_running = false;
00374 }
00375
00376 bool FileDescriptorActivity::stop()
00377 {
00378
00379
00380
00381
00382
00383
00384 if ( Activity::stop() == true )
00385 {
00386 fd_watch watch_pipe_0(m_interrupt_pipe[0]);
00387 fd_watch watch_pipe_1(m_interrupt_pipe[1]);
00388 return true;
00389 }
00390 return false;
00391 }
00392