aboutsummaryrefslogtreecommitdiff
path: root/alsa/src/communication/pipe_chan.rs
blob: 1a671eafa60998eb4d2f1dc6c154f366a789244d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use std::{ffi::{c_int, c_void}, fmt::Display, error::Error};
use libc::{read, close, pipe2, O_NONBLOCK, EINTR };
use errno::{errno, set_errno, Errno}; //Why isn't this in libc?!?

/// Sends byte data to the corresponding receiver.
pub(crate) struct Sender {
    handle : FileHandle,
}
/// Receives byte data from the corresponding sender.
pub(crate) struct Receiver {
    handle : FileHandle,
}

impl Receiver {
    pub(crate) fn read_byte(&self) -> Result<Option<u8>, ReceiveError> {
        set_errno(Errno(0));
        let mut buf : u8 = 0;
        let status = unsafe {read(self.handle.get_raw(),&mut buf as *mut u8 as *mut c_void, 1)};
        if status == 0 {
            //need to check errno. if a signal interrupted, then there is no error and we just
            //retry.
            //If no error happened, then the sender has hung up and we return err.
            let e = errno();
            if e == Errno(0) {
                Err(ReceiveError::SenderHasHungUp)
            } else if e.0 == EINTR {
                self.read_byte()
            } else {
                //Not sure what to do
                todo!()
            }
        }
        else {
            todo!()
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub(crate) enum ReceiveError {
    SenderHasHungUp
}

impl Display for ReceiveError{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Read failed, Sender has closed their end of the pipe.")
    }
}

impl Error for ReceiveError {}

pub(crate) fn create_pipe_chan() -> Result<(Sender, Receiver),()> {
    let mut handles : [c_int;2] = [0;2];
    let result = unsafe { pipe2(handles.as_mut_ptr(), O_NONBLOCK) };
    if result == -1 { 
        Err(())
    } else {
        Ok((
            Sender{handle : FileHandle{raw : handles[1]}},
            Receiver{handle : FileHandle{ raw : handles[0]}}
        ))
    }
}

struct FileHandle {
    raw : c_int,
}

impl FileHandle {
    pub(crate) fn get_raw(&self) -> c_int {
        self.raw
    }
}

impl Drop for FileHandle {
    fn drop(&mut self) {
        unsafe {
            close(self.raw);
        }
    }
}