@@ -26,8 +26,6 @@ namespace tcp {
26
26
// socket specified at construction. Upon completion or error, the
27
27
// callback is called. Its lifetime is coupled with completion of the
28
28
// operation, so the called doesn't need to hold on to the instance.
29
- // It does so by storing a shared_ptr to itself (effectively a leak)
30
- // until the event loop calls back.
31
29
template <typename T>
32
30
class ReadValueOperation final
33
31
: public Handler,
@@ -36,29 +34,15 @@ class ReadValueOperation final
36
34
using callback_t =
37
35
std::function<void (std::shared_ptr<Socket>, const Error& error, T&& t)>;
38
36
39
- ReadValueOperation (
40
- std::shared_ptr<Loop> loop,
41
- std::shared_ptr<Socket> socket,
42
- callback_t fn)
43
- : loop_(std::move(loop)),
44
- socket_ (std::move(socket)),
45
- fn_(std::move(fn)) {}
37
+ ReadValueOperation (std::shared_ptr<Socket> socket, callback_t fn)
38
+ : socket_(std::move(socket)), fn_(std::move(fn)) {}
46
39
47
- void run () {
48
- // Cannot initialize leak until after the object has been
49
- // constructed, because the std::make_shared initialization
50
- // doesn't run after construction of the underlying object.
51
- leak_ = this ->shared_from_this ();
52
- // Register with loop only after we've leaked the shared_ptr,
53
- // because we unleak it when the event loop thread calls.
54
- loop_->registerDescriptor (socket_->fd (), EPOLLIN | EPOLLONESHOT, this );
40
+ void run (Loop& loop) {
41
+ loop.registerDescriptor (
42
+ socket_->fd (), EPOLLIN | EPOLLONESHOT, this ->shared_from_this ());
55
43
}
56
44
57
- void handleEvents (int events) override {
58
- // Move leaked shared_ptr to the stack so that this object
59
- // destroys itself once this function returns.
60
- auto self = std::move (this ->leak_ );
61
-
45
+ void handleEvents (Loop&, int /* events*/ ) override {
62
46
// Read T.
63
47
auto rv = socket_->read (&t_, sizeof (t_));
64
48
if (rv == -1 ) {
@@ -80,30 +64,26 @@ class ReadValueOperation final
80
64
}
81
65
82
66
private:
83
- std::shared_ptr<Loop> loop_;
84
67
std::shared_ptr<Socket> socket_;
85
68
callback_t fn_;
86
- std::shared_ptr<ReadValueOperation<T>> leak_;
87
69
88
70
T t_;
89
71
};
90
72
91
73
template <typename T>
92
74
void read (
93
- std::shared_ptr< Loop> loop,
75
+ Loop& loop,
94
76
std::shared_ptr<Socket> socket,
95
77
typename ReadValueOperation<T>::callback_t fn) {
96
- auto x = std::make_shared<ReadValueOperation<T>>(
97
- std::move (loop), std::move (socket), std::move (fn));
98
- x->run ();
78
+ auto x =
79
+ std::make_shared<ReadValueOperation<T>>( std::move (socket), std::move (fn));
80
+ x->run (loop );
99
81
}
100
82
101
83
// WriteValueOperation asynchronously writes a value of type T to the
102
84
// socket specified at construction. Upon completion or error, the
103
85
// callback is called. Its lifetime is coupled with completion of the
104
86
// operation, so the called doesn't need to hold on to the instance.
105
- // It does so by storing a shared_ptr to itself (effectively a leak)
106
- // until the event loop calls back.
107
87
template <typename T>
108
88
class WriteValueOperation final
109
89
: public Handler,
@@ -112,31 +92,15 @@ class WriteValueOperation final
112
92
using callback_t =
113
93
std::function<void (std::shared_ptr<Socket>, const Error& error)>;
114
94
115
- WriteValueOperation (
116
- std::shared_ptr<Loop> loop,
117
- std::shared_ptr<Socket> socket,
118
- T t,
119
- callback_t fn)
120
- : loop_(std::move(loop)),
121
- socket_ (std::move(socket)),
122
- fn_(std::move(fn)),
123
- t_(std::move(t)) {}
124
-
125
- void run () {
126
- // Cannot initialize leak until after the object has been
127
- // constructed, because the std::make_shared initialization
128
- // doesn't run after construction of the underlying object.
129
- leak_ = this ->shared_from_this ();
130
- // Register with loop only after we've leaked the shared_ptr,
131
- // because we unleak it when the event loop thread calls.
132
- loop_->registerDescriptor (socket_->fd (), EPOLLOUT | EPOLLONESHOT, this );
133
- }
95
+ WriteValueOperation (std::shared_ptr<Socket> socket, T t, callback_t fn)
96
+ : socket_(std::move(socket)), fn_(std::move(fn)), t_(std::move(t)) {}
134
97
135
- void handleEvents ( int events) override {
136
- // Move leaked shared_ptr to the stack so that this object
137
- // destroys itself once this function returns.
138
- auto leak = std::move ( this -> leak_ );
98
+ void run (Loop& loop) {
99
+ loop. registerDescriptor (
100
+ socket_-> fd (), EPOLLOUT | EPOLLONESHOT, this -> shared_from_this ());
101
+ }
139
102
103
+ void handleEvents (Loop&, int /* events*/ ) override {
140
104
// Write T.
141
105
auto rv = socket_->write (&t_, sizeof (t_));
142
106
if (rv == -1 ) {
@@ -154,33 +118,30 @@ class WriteValueOperation final
154
118
}
155
119
156
120
private:
157
- std::shared_ptr<Loop> loop_;
158
121
std::shared_ptr<Socket> socket_;
159
122
callback_t fn_;
160
- std::shared_ptr<WriteValueOperation<T>> leak_;
161
123
162
124
T t_;
163
125
};
164
126
165
127
template <typename T>
166
128
void write (
167
- std::shared_ptr< Loop> loop,
129
+ Loop& loop,
168
130
std::shared_ptr<Socket> socket,
169
131
T t,
170
132
typename WriteValueOperation<T>::callback_t fn) {
171
133
auto x = std::make_shared<WriteValueOperation<T>>(
172
- std::move (loop), std::move ( socket), std::move (t), std::move (fn));
173
- x->run ();
134
+ std::move (socket), std::move (t), std::move (fn));
135
+ x->run (loop );
174
136
}
175
137
176
138
class ConnectOperation final
177
139
: public Handler,
178
140
public std::enable_shared_from_this<ConnectOperation> {
179
141
public:
180
- using callback_t =
181
- std::function< void (std::shared_ptr<Socket>, const Error& error)>;
142
+ using callback_t = std::function<
143
+ void (Loop& loop, std::shared_ptr<Socket>, const Error& error)>;
182
144
ConnectOperation (
183
- std::shared_ptr<Loop> loop,
184
145
const Address& remote,
185
146
const int rank,
186
147
const int size,
@@ -190,15 +151,9 @@ class ConnectOperation final
190
151
rank_ (rank),
191
152
size_(size),
192
153
deadline_(std::chrono::steady_clock::now() + timeout),
193
- loop_(std::move(loop)),
194
154
fn_(std::move(fn)) {}
195
155
196
- void run () {
197
- // Cannot initialize leak until after the object has been
198
- // constructed, because the std::make_shared initialization
199
- // doesn't run after construction of the underlying object.
200
- leak_ = this ->shared_from_this ();
201
-
156
+ void run (Loop& loop) {
202
157
const auto & sockaddr = remote_.getSockaddr ();
203
158
204
159
// Create new socket to connect to peer.
@@ -207,29 +162,26 @@ class ConnectOperation final
207
162
socket_->noDelay (true );
208
163
socket_->connect (sockaddr);
209
164
210
- // Register with loop only after we've leaked the shared_ptr,
211
- // because we unleak it when the event loop thread calls.
212
165
// Register for EPOLLOUT, because we want to be notified when
213
166
// the connect completes. EPOLLERR is also necessary because
214
167
// connect() can fail.
215
- if (auto loop = loop_.lock ()) {
216
- loop->registerDescriptor (
217
- socket_->fd (), EPOLLOUT | EPOLLERR | EPOLLONESHOT, this );
218
- } else {
219
- fn_ (socket_, LoopError (" loop is gone" ));
220
- }
168
+ loop.registerDescriptor (
169
+ socket_->fd (),
170
+ EPOLLOUT | EPOLLERR | EPOLLONESHOT,
171
+ this ->shared_from_this ());
221
172
}
222
173
223
- void handleEvents (int events) override {
224
- // Move leaked shared_ptr to the stack so that this object
225
- // destroys itself once this function returns.
226
- auto leak = std::move (this ->leak_ );
174
+ void handleEvents (Loop& loop, int /* events*/ ) override {
175
+ // Hold a reference to this object to keep it alive until the
176
+ // callback is called.
177
+ auto leak = shared_from_this ();
178
+ loop.unregisterDescriptor (socket_->fd (), this );
227
179
228
180
int result;
229
181
socklen_t result_len = sizeof (result);
230
182
if (getsockopt (socket_->fd (), SOL_SOCKET, SO_ERROR, &result, &result_len) <
231
183
0 ) {
232
- fn_ (socket_, SystemError (" getsockopt" , errno, remote_));
184
+ fn_ (loop, socket_, SystemError (" getsockopt" , errno, remote_));
233
185
return ;
234
186
}
235
187
if (result != 0 ) {
@@ -248,16 +200,18 @@ class ConnectOperation final
248
200
socket_->sockName ().str (),
249
201
};
250
202
DebugLogger::log (debugData);
203
+
251
204
// check deadline
252
205
if (willRetry) {
253
- run ();
206
+ run (loop );
254
207
} else {
255
- fn_ (socket_, TimeoutError (" timed out connecting: " + e.what ()));
208
+ fn_ (loop, socket_, TimeoutError (" timed out connecting: " + e.what ()));
256
209
}
210
+
257
211
return ;
258
212
}
259
213
260
- fn_ (socket_, Error::kSuccess );
214
+ fn_ (loop, socket_, Error::kSuccess );
261
215
}
262
216
263
217
private:
@@ -269,16 +223,12 @@ class ConnectOperation final
269
223
270
224
int retry_{0 };
271
225
272
- // We use a weak_ptr to the loop to avoid a reference cycle when an error
273
- // occurs.
274
- std::weak_ptr<Loop> loop_;
275
226
std::shared_ptr<Socket> socket_;
276
227
callback_t fn_;
277
- std::shared_ptr<ConnectOperation> leak_;
278
228
};
279
229
280
230
void connectLoop (
281
- std::shared_ptr< Loop> loop,
231
+ Loop& loop,
282
232
const Address& remote,
283
233
const int rank,
284
234
const int size,
0 commit comments