A Discrete-Event Network Simulator
Home
Tutorials ▼
English
Portuguese
Docs ▼
Wiki
Manual
Models
Develop ▼
API
Bugs
API
Main Page
Related Pages
Modules
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Properties
Friends
Macros
Groups
Pages
unix-fd-reader.cc
Go to the documentation of this file.
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
3
/*
4
* Copyright (c) 2010 The Boeing Company
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 version 2 as
8
* published by the Free Software Foundation;
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
*
19
* Author: Tom Goff <thomas.goff@boeing.com>
20
*/
21
22
#include <cerrno>
23
#include <cstring>
24
#include <unistd.h>
25
#include <fcntl.h>
26
27
#include "
log.h
"
28
#include "
fatal-error.h
"
29
#include "
simple-ref-count.h
"
30
#include "
system-thread.h
"
31
#include "
simulator.h
"
32
33
#include "
unix-fd-reader.h
"
34
35
NS_LOG_COMPONENT_DEFINE
(
"FdReader"
);
36
37
namespace
ns3 {
38
39
FdReader::FdReader
()
40
: m_fd (-1), m_readCallback (0), m_readThread (0), m_stop (false),
41
m_destroyEvent ()
42
{
43
NS_LOG_FUNCTION
(
this
);
44
m_evpipe
[0] = -1;
45
m_evpipe
[1] = -1;
46
}
47
48
FdReader::~FdReader
()
49
{
50
NS_LOG_FUNCTION
(
this
);
51
Stop
();
52
}
53
54
void
FdReader::Start
(
int
fd,
Callback<void, uint8_t *, ssize_t>
readCallback)
55
{
56
NS_LOG_FUNCTION
(
this
<< fd << &readCallback);
57
int
tmp;
58
59
NS_ASSERT_MSG
(
m_readThread
== 0,
"read thread already exists"
);
60
61
// create a pipe for inter-thread event notification
62
tmp = pipe (
m_evpipe
);
63
if
(tmp == -1)
64
{
65
NS_FATAL_ERROR
(
"pipe() failed: "
<< std::strerror (errno));
66
}
67
68
// make the read end non-blocking
69
tmp = fcntl (
m_evpipe
[0], F_GETFL);
70
if
(tmp == -1)
71
{
72
NS_FATAL_ERROR
(
"fcntl() failed: "
<< std::strerror (errno));
73
}
74
if
(fcntl (
m_evpipe
[0], F_SETFL, tmp | O_NONBLOCK) == -1)
75
{
76
NS_FATAL_ERROR
(
"fcntl() failed: "
<< std::strerror (errno));
77
}
78
79
m_fd
= fd;
80
m_readCallback
= readCallback;
81
82
//
83
// We're going to spin up a thread soon, so we need to make sure we have
84
// a way to tear down that thread when the simulation stops. Do this by
85
// scheduling a "destroy time" method to make sure the thread exits before
86
// proceeding.
87
//
88
if
(!
m_destroyEvent
.
IsRunning
())
89
{
90
// hold a reference to ensure that this object is not
91
// deallocated before the destroy-time event fires
92
this->
Ref
();
93
m_destroyEvent
=
94
Simulator::ScheduleDestroy
(&
FdReader::DestroyEvent
,
this
);
95
}
96
97
//
98
// Now spin up a thread to read from the fd
99
//
100
NS_LOG_LOGIC
(
"Spinning up read thread"
);
101
102
m_readThread
= Create<SystemThread> (
MakeCallback
(&
FdReader::Run
,
this
));
103
m_readThread
->
Start
();
104
}
105
106
void
FdReader::DestroyEvent
(
void
)
107
{
108
NS_LOG_FUNCTION
(
this
);
109
Stop
();
110
this->
Unref
();
111
}
112
113
void
FdReader::Stop
(
void
)
114
{
115
NS_LOG_FUNCTION
(
this
);
116
m_stop
=
true
;
117
118
// signal the read thread
119
if
(
m_evpipe
[1] != -1)
120
{
121
char
zero
= 0;
122
ssize_t len = write (
m_evpipe
[1], &zero,
sizeof
(zero));
123
if
(len !=
sizeof
(zero))
124
NS_LOG_WARN
(
"incomplete write(): "
<< std::strerror (errno));
125
}
126
127
// join the read thread
128
if
(
m_readThread
!= 0)
129
{
130
m_readThread
->
Join
();
131
m_readThread
= 0;
132
}
133
134
// close the write end of the event pipe
135
if
(
m_evpipe
[1] != -1)
136
{
137
close (
m_evpipe
[1]);
138
m_evpipe
[1] = -1;
139
}
140
141
// close the read end of the event pipe
142
if
(
m_evpipe
[0] != -1)
143
{
144
close (
m_evpipe
[0]);
145
m_evpipe
[0] = -1;
146
}
147
148
// reset everything else
149
m_fd
= -1;
150
m_readCallback
.
Nullify
();
151
m_stop
=
false
;
152
}
153
154
// This runs in a separate thread
155
void
FdReader::Run
(
void
)
156
{
157
NS_LOG_FUNCTION
(
this
);
158
int
nfds;
159
fd_set rfds;
160
161
nfds = (
m_fd
>
m_evpipe
[0] ?
m_fd
:
m_evpipe
[0]) + 1;
162
163
FD_ZERO (&rfds);
164
FD_SET (
m_fd
, &rfds);
165
FD_SET (
m_evpipe
[0], &rfds);
166
167
for
(;;)
168
{
169
int
r;
170
fd_set readfds = rfds;
171
172
r = select (nfds, &readfds, NULL, NULL, NULL);
173
if
(r == -1 && errno != EINTR)
174
{
175
NS_FATAL_ERROR
(
"select() failed: "
<< std::strerror (errno));
176
}
177
178
if
(FD_ISSET (
m_evpipe
[0], &readfds))
179
{
180
// drain the event pipe
181
for
(;;)
182
{
183
char
buf[1024];
184
ssize_t len = read (
m_evpipe
[0], buf,
sizeof
(buf));
185
if
(len == 0)
186
{
187
NS_FATAL_ERROR
(
"event pipe closed"
);
188
}
189
if
(len < 0)
190
{
191
if
(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
192
{
193
break
;
194
}
195
else
196
{
197
NS_FATAL_ERROR
(
"read() failed: "
<< std::strerror (errno));
198
}
199
}
200
}
201
}
202
203
if
(
m_stop
)
204
{
205
// this thread is done
206
break
;
207
}
208
209
if
(FD_ISSET (
m_fd
, &readfds))
210
{
211
struct
FdReader::Data
data =
DoRead
();
212
// reading stops when m_len is zero
213
if
(data.
m_len
== 0)
214
{
215
break
;
216
}
217
// the callback is only called when m_len is positive (data
218
// is ignored if m_len is negative)
219
else
if
(data.
m_len
> 0)
220
{
221
m_readCallback
(data.
m_buf
, data.
m_len
);
222
}
223
}
224
}
225
}
226
227
}
// namespace ns3
src
core
model
unix-fd-reader.cc
Generated on Fri Dec 21 2012 19:00:33 for ns-3 by
1.8.1.2