ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dce-poll.cc
Go to the documentation of this file.
1 #include "ns3/log.h"
2 #include "ns3/nstime.h"
3 #include "dce-poll.h"
4 #include "sys/dce-select.h"
5 #include "wait-queue.h"
6 #include "file-usage.h"
7 #include "utils.h"
8 #include "dce-manager.h"
9 #include "process.h"
10 #include "errno.h"
11 #include <map>
12 
13 
14 NS_LOG_COMPONENT_DEFINE ("PollSelect");
15 
16 using namespace ns3;
17 
18 int dce_poll (struct pollfd *fds, nfds_t nfds, int timeout)
19 {
20  int count = -1;
21  int timed_out = 0;
22  Time endtime;
23  // key fd
24  std::map <int, FileUsage*> toUnRef;
25  Thread *current = Current ();
26  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fds << nfds << timeout);
27  PollTable *table = new PollTable ();
28  PollTable *currentTable = table;
29 
30  NS_ASSERT (current != 0);
31 
32  if (0 == timeout)
33  {
34  currentTable = 0;
35  timed_out = 1;
36  }
37  else if (timeout > 0)
38  {
39  endtime = Now () + MilliSeconds (timeout);
40  }
41 
42  for (uint32_t i = 0; i < nfds; ++i)
43  {
44  // initialize all outgoing events.
45  fds[i].revents = 0;
46  }
47  while (true)
48  {
49  int validFd = 0;
50  count = 0;
51  for (uint32_t i = 0; i < nfds; ++i)
52  {
53  if (CheckFdExists (current->process, fds[i].fd, true))
54  {
55  validFd++;
56  UnixFd *unixFd = 0;
57  FileUsage *fu = current->process->openFiles[fds[i].fd];
58 
59  if (currentTable)
60  {
61  unixFd = fu->GetFileInc ();
62  toUnRef[fds[i].fd] = fu;
63  currentTable->SetEventMask (fds[i].events | POLLERR | POLLHUP);
64  }
65  else
66  {
67  unixFd = fu->GetFile ();
68  }
69 
70  int mask = unixFd->Poll (currentTable);
71 
72  mask &= (fds[i].events | POLLERR | POLLHUP);
73  fds[i].revents = mask;
74  if (mask)
75  {
76  count++;
77  currentTable = 0;
78  }
79  }
80  }
81  currentTable = 0; // Register only first time.
82 
83  if (count || timed_out)
84  {
85  break;
86  }
87 
88  if (timeout != 0)
89  {
90  if (timeout < 0)
91  {
92  current->pollTable = table;
93  table->Wait (Seconds (0));
94  current->pollTable = 0;
95  }
96  else
97  {
98  Time diff = endtime - Now ();
99  if (diff.IsStrictlyPositive ())
100  {
101  current->pollTable = table;
102  table->Wait (diff);
103  current->pollTable = 0;
104  }
105  else
106  {
107  break;
108  }
109  }
110  }
111  }
112 
113  table->FreeWait ();
114  delete (table);
115 
116  for (std::map <int, FileUsage*>::iterator i = toUnRef.begin ();
117  i != toUnRef.end (); ++i)
118  {
119  i->second->DecUsage ();
120  }
121 
122  // Try to break infinite loop in poll with a 0 timeout !
123  if ((0 == count) && (0 == timeout))
124  {
125  UtilsAdvanceTime (current);
126  }
127 
128  return count;
129 }
130 
131 int dce_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
132  struct timeval *timeout)
133 {
134  Thread *current = Current ();
135  NS_LOG_FUNCTION (current << UtilsGetNodeId () << nfds << timeout);
136  NS_ASSERT (current != 0);
137  std::map <int, int> eventByFd;
138 
139  if (nfds == -1)
140  {
141  current->err = EINVAL;
142  return -1;
143  }
144  if (readfds == 0 && writefds == 0 && exceptfds == 0)
145  {
146  current->err = EINVAL;
147  return -1;
148  }
149  if (timeout)
150  {
151  if (timeout->tv_sec < 0 || timeout->tv_usec < 0)
152  {
153  current->err = EINVAL;
154  return -1;
155  }
156  }
157  for (int fd = 0; fd < nfds; fd++)
158  {
159  int event = 0;
160 
161  if (readfds != 0 && FD_ISSET (fd, readfds))
162  {
163  event |= POLLIN;
164  }
165  if (writefds != 0 && FD_ISSET (fd, writefds))
166  {
167  event |= POLLOUT;
168  }
169  if (exceptfds != 0 && FD_ISSET (fd, exceptfds))
170  {
171  event |= POLLPRI;
172  }
173 
174  if (event)
175  {
176  if (!CheckFdExists (current->process, fd, true))
177  {
178  current->err = EBADF;
179  return -1;
180  }
181  eventByFd[fd] = event;
182  }
183  }
184  nfds = eventByFd.size ();
185 
186  // select(2):
187  // Some code calls select() with all three sets empty, nfds zero, and a
188  // non-NULL timeout as a fairly portable way to sleep with subsecond
189  // precision.
190  // 130825: this condition will be passed by dce_poll ()
191 
192  struct pollfd pollFd[nfds];
193  int j = 0;
194 
195  for (std::map<int, int>::iterator i = eventByFd.begin (); i != eventByFd.end (); ++i)
196  {
197  pollFd[j].events = (*i).second;
198  pollFd[j].fd = (*i).first;
199  pollFd[j++].revents = 0;
200  }
201 
202  int pollTo = -1;
203 
204  if (timeout)
205  {
206  pollTo = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
207  }
208 
209  int pollRet = dce_poll (pollFd, nfds, pollTo);
210 
211  if (readfds)
212  {
213  FD_ZERO (readfds);
214  }
215  if (writefds)
216  {
217  FD_ZERO (writefds);
218  }
219  if (exceptfds)
220  {
221  FD_ZERO (exceptfds);
222  }
223 
224  if (pollRet > 0)
225  {
226  pollRet = 0;
227  for (j = 0; j < nfds; j++)
228  {
229  if (readfds && ((POLLIN & pollFd[j].revents) || (POLLHUP & pollFd[j].revents)
230  || (POLLERR & pollFd[j].revents)))
231  {
232  FD_SET (pollFd[j].fd, readfds);
233  pollRet++;
234  }
235  if (writefds && (POLLOUT & pollFd[j].revents))
236  {
237  FD_SET (pollFd[j].fd, writefds);
238  pollRet++;
239  }
240  if (exceptfds && (POLLPRI & pollFd[j].revents))
241  {
242  FD_SET (pollFd[j].fd, exceptfds);
243  pollRet++;
244  }
245  }
246  }
247  return pollRet;
248 }