|
2 | 2 | //!
|
3 | 3 | //! See also:
|
4 | 4 | //! - [C API reference: Module coio](https://www.tarantool.io/en/doc/latest/dev_guide/reference_capi/coio/)
|
| 5 | +use std::cell::{Cell, RefCell}; |
| 6 | +use std::collections::VecDeque; |
5 | 7 | use std::convert::TryFrom;
|
6 | 8 | use std::ffi::c_void;
|
7 |
| -use std::io; |
8 |
| -use std::io::{Read, Write}; |
| 9 | +use std::io::{self, Read, Write}; |
9 | 10 | use std::mem::forget;
|
10 | 11 | use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
|
11 | 12 | use std::os::raw::c_char;
|
12 | 13 | use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
| 14 | +use std::rc::Rc; |
13 | 15 | use std::time::Duration;
|
14 | 16 |
|
15 | 17 | use failure::_core::ptr::null_mut;
|
| 18 | +use num_traits::Zero; |
16 | 19 |
|
17 | 20 | use crate::error::{Error, TarantoolError};
|
18 | 21 | use crate::ffi::tarantool as ffi;
|
19 |
| -use crate::fiber::unpack_callback; |
| 22 | +use crate::fiber::{unpack_callback, Cond}; |
20 | 23 |
|
21 | 24 | const TIMEOUT_INFINITY: f64 = 365.0 * 86400.0 * 100.0;
|
22 | 25 |
|
@@ -286,3 +289,91 @@ pub(crate) fn write(fd: RawFd, buf: &[u8], timeout: Option<Duration>) -> Result<
|
286 | 289 | Ok(result as usize)
|
287 | 290 | }
|
288 | 291 | }
|
| 292 | + |
| 293 | +/// Creates a new asynchronous channel, returning the sender/receiver halves. |
| 294 | +/// |
| 295 | +/// All data sent on the Sender will become available on the [Receiver] in the same order as it was sent, |
| 296 | +/// and no `send` will block the calling fiber, `recv` will block until a message is available. |
| 297 | +pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) { |
| 298 | + let chan = Rc::new(Chan { |
| 299 | + buffer: RefCell::new(VecDeque::with_capacity(capacity)), |
| 300 | + cond: Cond::new(), |
| 301 | + tx_count: Cell::new(1), |
| 302 | + rx_is_active: Cell::new(true), |
| 303 | + }); |
| 304 | + |
| 305 | + (Sender(chan.clone()), Receiver(chan)) |
| 306 | +} |
| 307 | + |
| 308 | +/// The sending-half of channel. |
| 309 | +/// |
| 310 | +/// Messages can be sent through this channel with `send`. Can be cloned. |
| 311 | +pub struct Sender<T>(Rc<Chan<T>>); |
| 312 | + |
| 313 | +impl<T> Sender<T> { |
| 314 | + /// Attempts to send a value on this channel, returning it back if it could not be sent. |
| 315 | + /// This method will never block. |
| 316 | + pub fn send(&self, value: T) -> Result<(), io::Error> { |
| 317 | + if !self.0.rx_is_active.get() { |
| 318 | + return Err(io::ErrorKind::NotConnected.into()); |
| 319 | + } |
| 320 | + |
| 321 | + let was_empty = { |
| 322 | + let mut buffer = self.0.buffer.borrow_mut(); |
| 323 | + let was_empty = buffer.len() == 0; |
| 324 | + buffer.push_back(value); |
| 325 | + was_empty |
| 326 | + }; |
| 327 | + |
| 328 | + if was_empty { |
| 329 | + self.0.cond.signal(); |
| 330 | + } |
| 331 | + |
| 332 | + Ok(()) |
| 333 | + } |
| 334 | +} |
| 335 | + |
| 336 | +impl<T> Clone for Sender<T> { |
| 337 | + fn clone(&self) -> Self { |
| 338 | + self.0.tx_count.set(self.0.tx_count.get() + 1); |
| 339 | + Sender(self.0.clone()) |
| 340 | + } |
| 341 | +} |
| 342 | + |
| 343 | +impl<T> Drop for Sender<T> { |
| 344 | + fn drop(&mut self) { |
| 345 | + self.0.tx_count.set(self.0.tx_count.get() - 1); |
| 346 | + self.0.cond.signal(); |
| 347 | + } |
| 348 | +} |
| 349 | + |
| 350 | +/// The receiving half of channel. |
| 351 | +pub struct Receiver<T>(Rc<Chan<T>>); |
| 352 | + |
| 353 | +impl<T> Receiver<T> { |
| 354 | + /// Attempts to wait for a value on this receiver, returning `None` if the corresponding channel has hung up. |
| 355 | + pub fn recv(&self) -> Option<T> { |
| 356 | + if self.0.buffer.borrow().len() == 0 { |
| 357 | + if self.0.tx_count.get().is_zero() { |
| 358 | + return None; |
| 359 | + } |
| 360 | + |
| 361 | + self.0.cond.wait(); |
| 362 | + } |
| 363 | + |
| 364 | + self.0.buffer.borrow_mut().pop_front() |
| 365 | + } |
| 366 | +} |
| 367 | + |
| 368 | +impl<T> Drop for Receiver<T> { |
| 369 | + fn drop(&mut self) { |
| 370 | + self.0.rx_is_active.set(false); |
| 371 | + } |
| 372 | +} |
| 373 | + |
| 374 | +struct Chan<T> { |
| 375 | + buffer: RefCell<VecDeque<T>>, |
| 376 | + cond: Cond, |
| 377 | + tx_count: Cell<usize>, |
| 378 | + rx_is_active: Cell<bool>, |
| 379 | +} |
0 commit comments