@@ -44,7 +44,7 @@ impl Permissions {
44
44
/// Determines what happens when the backend is unable to send a guest byte back
45
45
/// to a client because the client's channel is full.
46
46
#[ derive( Clone , Copy ) ]
47
- pub ( super ) enum ReadWaitDiscipline {
47
+ pub ( super ) enum FullReadChannelDiscipline {
48
48
/// The backend should block until it can send to this client.
49
49
Block ,
50
50
@@ -60,7 +60,7 @@ struct Client {
60
60
61
61
/// Determines what happens when the backend wants to send a byte and
62
62
/// [`Self::tx`] is full.
63
- read_discipline : ReadWaitDiscipline ,
63
+ read_discipline : FullReadChannelDiscipline ,
64
64
}
65
65
66
66
/// A handle held by a client that represents its connection to the backend.
@@ -185,8 +185,20 @@ impl Inner {
185
185
/// access a single serial device.
186
186
pub struct ConsoleBackend {
187
187
inner : Arc < Mutex < Inner > > ,
188
+
189
+ /// The character [`Sink`] that should receive writes to this backend.
190
+ /// Writes should not access the sink directly; instead, they should be
191
+ /// directed to [`Self::sink_buffer`]. This reference is needed because
192
+ /// [`SinkBuffer`]'s current API requires a sink to be passed into each
193
+ /// attempt to write (buffers don't own references to their sinks).
188
194
sink : Arc < dyn Sink > ,
195
+
196
+ /// The buffer that sits in front of this backend's sink. Writes to the
197
+ /// backend should be directed at the buffer, not at [`Self::sink`].
189
198
sink_buffer : Arc < SinkBuffer > ,
199
+
200
+ /// A channel used to tell the backend's reader task that the backend has
201
+ /// been closed.
190
202
done_tx : oneshot:: Sender < ( ) > ,
191
203
}
192
204
@@ -227,20 +239,26 @@ impl ConsoleBackend {
227
239
///
228
240
/// - `read_tx`: A channel to which the backend should send bytes read from
229
241
/// its device.
242
+ /// - `permissions`: The read/write permissions this client should have.
243
+ /// - `full_read_tx_discipline`: Describes what should happen if the reader
244
+ /// task ever finds that `read_tx` is full when dispatching a byte to it.
230
245
pub ( super ) fn attach_client (
231
246
self : & Arc < Self > ,
232
247
read_tx : mpsc:: Sender < u8 > ,
233
248
permissions : Permissions ,
234
- wait_discipline : ReadWaitDiscipline ,
249
+ full_read_tx_discipline : FullReadChannelDiscipline ,
235
250
) -> ClientHandle {
236
251
let mut inner = self . inner . lock ( ) . unwrap ( ) ;
237
252
let id = inner. next_client_id ( ) ;
238
- let client = Client { tx : read_tx, read_discipline : wait_discipline } ;
253
+ let client =
254
+ Client { tx : read_tx, read_discipline : full_read_tx_discipline } ;
239
255
240
256
inner. clients . insert ( id, client) ;
241
257
ClientHandle { id, backend : self . clone ( ) , permissions }
242
258
}
243
259
260
+ /// Returns the contents of this backend's history buffer. See
261
+ /// [`HistoryBuffer::contents_vec`].
244
262
pub fn history_vec (
245
263
& self ,
246
264
byte_offset : SerialHistoryOffset ,
@@ -250,6 +268,8 @@ impl ConsoleBackend {
250
268
inner. buffer . contents_vec ( byte_offset, max_bytes)
251
269
}
252
270
271
+ /// Returns the number of bytes that have ever been sent to this backend's
272
+ /// history buffer.
253
273
pub fn bytes_since_start ( & self ) -> usize {
254
274
self . inner . lock ( ) . unwrap ( ) . buffer . bytes_from_start ( )
255
275
}
@@ -293,6 +313,9 @@ mod migrate {
293
313
}
294
314
}
295
315
316
+ /// Reads bytes from the supplied `source` and dispatches them to the clients in
317
+ /// `inner`. Each backend is expected to spin up one task that runs this
318
+ /// function.
296
319
async fn read_task (
297
320
inner : Arc < Mutex < Inner > > ,
298
321
source : Arc < dyn Source > ,
@@ -322,10 +345,15 @@ async fn read_task(
322
345
323
346
let to_send = & bytes[ 0 ..bytes_read] ;
324
347
348
+ // Capture a list of all the clients who should receive this byte with
349
+ // the lock held, then drop the lock before sending to any of them. Note
350
+ // that sends to clients may block for an arbitrary length of time: the
351
+ // receiver may be relaying received bytes to a websocket, and the
352
+ // remote peer may be slow to accept them.
325
353
struct CapturedClient {
326
354
id : ClientId ,
327
355
tx : mpsc:: Sender < u8 > ,
328
- discipline : ReadWaitDiscipline ,
356
+ discipline : FullReadChannelDiscipline ,
329
357
disconnect : bool ,
330
358
}
331
359
@@ -343,19 +371,23 @@ async fn read_task(
343
371
. collect :: < Vec < CapturedClient > > ( )
344
372
} ;
345
373
374
+ // Prepare to delete any clients that are no longer active (i.e., who
375
+ // have dropped the receiver sides of their channels) or who are using
376
+ // the close-on-full-channel discipline and who have a full channel.
346
377
for byte in to_send {
347
378
for client in clients. iter_mut ( ) {
348
379
client. disconnect = match client. discipline {
349
- ReadWaitDiscipline :: Block => {
380
+ FullReadChannelDiscipline :: Block => {
350
381
client. tx . send ( * byte) . await . is_err ( )
351
382
}
352
- ReadWaitDiscipline :: Close => {
383
+ FullReadChannelDiscipline :: Close => {
353
384
client. tx . try_send ( * byte) . is_err ( )
354
385
}
355
386
}
356
387
}
357
388
}
358
389
390
+ // Clean up any clients who met the disconnection criteria.
359
391
let mut guard = inner. lock ( ) . unwrap ( ) ;
360
392
guard. buffer . consume ( to_send) ;
361
393
for client in clients. iter ( ) . filter ( |c| c. disconnect ) {
0 commit comments