ONPOSIX  2.0
 All Classes Namespaces Files Functions Variables Enumerator Friends Macros Pages
DescriptorsMonitor.cpp
Go to the documentation of this file.
1 /*
2  * DescriptorsMonitor.cpp
3  *
4  * Copyright (C) 2012 Evidence Srl - www.evidence.eu.com
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 
22 #include "DescriptorsMonitor.hpp"
24 #include "Logger.hpp"
25 
26 namespace onposix {
27 
28 /**
29  * \brief Constructor.
30  * It just initializes the set of descriptors.
31  */
33 {
34  FD_ZERO(&descriptorSet_);
35 }
36 
37 /**
38  * \brief Destructor.
39  *
40  * It just deletes the data structure containing the association between
41  * readers and monitored descriptors.
42  * Note: it does not deletes the descriptors and the readers, because
43  * they are just pointers to classes allocated somewhere else.
44  */
46 {
47  for (std::vector<monitoredDescriptor*>::iterator i = descriptors_.begin();
48  i != descriptors_.end(); ++i)
49  delete(*i);
50 }
51 
52 /**
53  * \brief Method to start monitoring a descriptor.
54  *
55  * It is called by each class AbstractDescriptorReader that wants to be notified
56  * about a specific descriptor.
57  * @param reader class that wants to be notified
58  * @param descriptor descriptor
59  * @return true in case of success; false if the descriptor is already monitored
60  */
62  PosixDescriptor& descriptor)
63 {
64  if (FD_ISSET(descriptor.getDescriptorNumber(), &descriptorSet_)){
65  ERROR("Descriptor already monitored by some reader");
66  return false;
67  }
69  n->descriptor_ = &descriptor;
70  n->reader_ = &reader;
71  descriptors_.push_back(n);
72 
73  FD_SET(descriptor.getDescriptorNumber(), &descriptorSet_);
74 
75  if (highestDescriptor_ < descriptor.getDescriptorNumber())
77  return true;
78 }
79 
80 /**
81  * \brief Method to stop monitoring a descriptor.
82  *
83  * It is called by each class AbstractDescriptorReader that wants to stop
84  * notifications about a specific descriptor.
85  * The AbstractDescriptorReader class is not among arguments, because each
86  * descriptor can be monitored by at most one class.
87  * @param descriptor whose notifications must be stopped
88  * @return true in case of success; false if the descriptor was not monitored
89  */
91 {
92  if (!FD_ISSET(descriptor.getDescriptorNumber(), &descriptorSet_)){
93  ERROR("Descriptor was not monitored");
94  return false;
95  }
96 
97  for (std::vector<monitoredDescriptor*>::iterator i = descriptors_.begin();
98  i != descriptors_.end(); ++i)
99  if ((*i)->descriptor_->getDescriptorNumber() ==
100  descriptor.getDescriptorNumber()) {
101  delete(*i);
102  descriptors_.erase(i);
103  break;
104  }
105  FD_CLR(descriptor.getDescriptorNumber(), &descriptorSet_);
106  return true;
107 }
108 
109 /**
110  * \brief Method to wait until some descriptor becomes ready for read
111  * operations.
112  *
113  * It suspends the execution of the program until a descriptor becomes
114  * ready.
115  * @return true in case of success; false if selects() returns error
116  */
118 {
119  // Additional variable needed because select() will change the set
120  fd_set fd = descriptorSet_;
121 
122  // We need this additional variable, because this method calls
123  // AbstractDescriptorReader::dataAvailable() which in turn can call
124  // DescriptorsMonitor::startMonitoringDescriptor() to start
125  // monitoring a further descriptor. This adds new descriptors to
126  // descriptors_ within the execution of this method, messing up things.
127  std::vector<monitoredDescriptor*> checkedDescriptors = descriptors_;
128  int ret = select(highestDescriptor_+1,
129  &fd,
130  NULL,
131  NULL,
132  NULL);
133  DEBUG("Select returned!");
134  if (ret == -1){
135  // Error in select()
136  ERROR("select()");
137  return false;
138  } else if (!ret) {
139  // Timeout
140  DEBUG("Timeout()");
141  return false;
142  } else {
143  // At least one descriptor is ready for read operations
144  for (std::vector<monitoredDescriptor*>::iterator i =
145  checkedDescriptors.begin();
146  i != checkedDescriptors.end(); ++i) {
147  if (FD_ISSET((*i)->descriptor_->getDescriptorNumber(),
148  &fd)) {
149  // Notify the class
150  DEBUG("Notifying class...");
151  ((*i)->reader_)->dataAvailable(*((*i)->descriptor_));
152  }
153  }
154  return true;
155  }
156 }
157 
158 } /* onposix */