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 <errno.h>
23
#include <
string.h
>
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
m_evpipe
[0] = -1;
44
m_evpipe
[1] = -1;
45
}
46
47
FdReader::~FdReader
()
48
{
49
Stop
();
50
}
51
52
void
FdReader::Start
(
int
fd,
Callback<void, uint8_t *, ssize_t>
readCallback)
53
{
54
int
tmp;
55
56
NS_ASSERT_MSG
(
m_readThread
== 0,
"read thread already exists"
);
57
58
// create a pipe for inter-thread event notification
59
tmp = pipe (
m_evpipe
);
60
if
(tmp == -1)
61
{
62
NS_FATAL_ERROR
(
"pipe() failed: "
<< strerror (errno));
63
}
64
65
// make the read end non-blocking
66
tmp = fcntl (
m_evpipe
[0], F_GETFL);
67
if
(tmp == -1)
68
{
69
NS_FATAL_ERROR
(
"fcntl() failed: "
<< strerror (errno));
70
}
71
if
(fcntl (
m_evpipe
[0], F_SETFL, tmp | O_NONBLOCK) == -1)
72
{
73
NS_FATAL_ERROR
(
"fcntl() failed: "
<< strerror (errno));
74
}
75
76
m_fd
= fd;
77
m_readCallback
= readCallback;
78
79
//
80
// We're going to spin up a thread soon, so we need to make sure we have
81
// a way to tear down that thread when the simulation stops. Do this by
82
// scheduling a "destroy time" method to make sure the thread exits before
83
// proceeding.
84
//
85
if
(!
m_destroyEvent
.
IsRunning
())
86
{
87
// hold a reference to ensure that this object is not
88
// deallocated before the destroy-time event fires
89
this->
Ref
();
90
m_destroyEvent
=
91
Simulator::ScheduleDestroy
(&
FdReader::DestroyEvent
,
this
);
92
}
93
94
//
95
// Now spin up a thread to read from the fd
96
//
97
NS_LOG_LOGIC
(
"Spinning up read thread"
);
98
99
m_readThread
= Create<SystemThread> (
MakeCallback
(&
FdReader::Run
,
this
));
100
m_readThread
->
Start
();
101
}
102
103
void
FdReader::DestroyEvent
(
void
)
104
{
105
Stop
();
106
this->
Unref
();
107
}
108
109
void
FdReader::Stop
(
void
)
110
{
111
m_stop
=
true
;
112
113
// signal the read thread
114
if
(
m_evpipe
[1] != -1)
115
{
116
char
zero
= 0;
117
ssize_t len = write (
m_evpipe
[1], &zero,
sizeof
(zero));
118
if
(len !=
sizeof
(zero))
119
NS_LOG_WARN
(
"incomplete write(): "
<< strerror (errno));
120
}
121
122
// join the read thread
123
if
(
m_readThread
!= 0)
124
{
125
m_readThread
->
Join
();
126
m_readThread
= 0;
127
}
128
129
// close the write end of the event pipe
130
if
(
m_evpipe
[1] != -1)
131
{
132
close (
m_evpipe
[1]);
133
m_evpipe
[1] = -1;
134
}
135
136
// close the read end of the event pipe
137
if
(
m_evpipe
[0] != -1)
138
{
139
close (
m_evpipe
[0]);
140
m_evpipe
[0] = -1;
141
}
142
143
// reset everything else
144
m_fd
= -1;
145
m_readCallback
.
Nullify
();
146
m_stop
=
false
;
147
}
148
149
// This runs in a separate thread
150
void
FdReader::Run
(
void
)
151
{
152
int
nfds;
153
fd_set rfds;
154
155
nfds = (
m_fd
>
m_evpipe
[0] ?
m_fd
:
m_evpipe
[0]) + 1;
156
157
FD_ZERO (&rfds);
158
FD_SET (
m_fd
, &rfds);
159
FD_SET (
m_evpipe
[0], &rfds);
160
161
for
(;;)
162
{
163
int
r;
164
fd_set readfds = rfds;
165
166
r = select (nfds, &readfds, NULL, NULL, NULL);
167
if
(r == -1 && errno != EINTR)
168
{
169
NS_FATAL_ERROR
(
"select() failed: "
<< strerror (errno));
170
}
171
172
if
(FD_ISSET (
m_evpipe
[0], &readfds))
173
{
174
// drain the event pipe
175
for
(;;)
176
{
177
char
buf[1024];
178
ssize_t len = read (
m_evpipe
[0], buf,
sizeof
(buf));
179
if
(len == 0)
180
{
181
NS_FATAL_ERROR
(
"event pipe closed"
);
182
}
183
if
(len < 0)
184
{
185
if
(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
186
{
187
break
;
188
}
189
else
190
{
191
NS_FATAL_ERROR
(
"read() failed: "
<< strerror (errno));
192
}
193
}
194
}
195
}
196
197
if
(
m_stop
)
198
{
199
// this thread is done
200
break
;
201
}
202
203
if
(FD_ISSET (
m_fd
, &readfds))
204
{
205
struct
FdReader::Data
data =
DoRead
();
206
// reading stops when m_len is zero
207
if
(data.
m_len
== 0)
208
{
209
break
;
210
}
211
// the callback is only called when m_len is positive (data
212
// is ignored if m_len is negative)
213
else
if
(data.
m_len
> 0)
214
{
215
m_readCallback
(data.
m_buf
, data.
m_len
);
216
}
217
}
218
}
219
}
220
221
}
// namespace ns3
src
core
model
unix-fd-reader.cc
Generated on Tue Oct 9 2012 16:45:35 for ns-3 by
1.8.1.2