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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::prelude::{IntoRawFd, RawFd};
use std::time::Duration;

use a653rs::bindings::PortDirection;
use a653rs::prelude::{PartitionId, StartCondition};
use memfd::{FileSeal, MemfdOptions};
use serde::{Deserialize, Serialize};

use crate::error::{ResultExt, SystemError, TypedError, TypedResult};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PartitionConstants {
    pub name: String,
    pub identifier: PartitionId,
    pub period: Duration,
    pub duration: Duration,
    pub start_condition: StartCondition,
    pub start_time_fd: RawFd,
    pub partition_mode_fd: RawFd,

    // A UNIX domain socket, that is used to send file descriptors to the partition.
    pub io_fd: RawFd,

    pub sampling: Vec<SamplingConstant>,
    pub queuing: Vec<QueuingConstant>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SamplingConstant {
    pub name: String,
    pub dir: PortDirection,
    pub msg_size: usize,
    pub fd: RawFd,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct QueuingConstant {
    pub name: String,
    pub dir: PortDirection,
    pub msg_size: usize,
    pub max_num_msg: usize,
    pub fd: RawFd,
}

impl PartitionConstants {
    pub const PARTITION_CONSTANTS_FD: &'static str = "PARTITION_CONSTANTS_FD";
    pub const PROCESSES_CGROUP: &'static str = "processes";
    pub const MAIN_PROCESS_CGROUP: &'static str = "main";
    pub const APERIODIC_PROCESS_CGROUP: &'static str = "aperiodic";
    pub const PERIODIC_PROCESS_CGROUP: &'static str = "periodic";
    pub const IPC_SENDER: &'static str = "/.inner/ipc";

    pub fn open() -> TypedResult<Self> {
        let fd = std::env::var(Self::PARTITION_CONSTANTS_FD)
            .typ(SystemError::PartitionInit)?
            .parse::<RawFd>()
            .typ(SystemError::PartitionInit)?;
        PartitionConstants::try_from(fd).typ(SystemError::PartitionInit)
    }
}

impl TryFrom<RawFd> for PartitionConstants {
    type Error = TypedError;

    fn try_from(file: RawFd) -> TypedResult<Self> {
        let mut file = File::open(format!("/proc/self/fd/{file}")).typ(SystemError::Panic)?;
        let mut buf = Vec::new();
        file.read_to_end(&mut buf).typ(SystemError::Panic)?;
        bincode::deserialize(&buf).typ(SystemError::Panic)
    }
}

impl TryFrom<PartitionConstants> for RawFd {
    type Error = TypedError;

    fn try_from(consts: PartitionConstants) -> TypedResult<Self> {
        let bytes = bincode::serialize(&consts).typ(SystemError::Panic)?;

        let mem = MemfdOptions::default()
            .close_on_exec(false)
            .allow_sealing(true)
            .create("constants")
            .typ(SystemError::Panic)?;
        mem.as_file()
            .set_len(bytes.len() as u64)
            .typ(SystemError::Panic)?;
        mem.as_file().write_all(&bytes).typ(SystemError::Panic)?;
        mem.add_seals(&[
            FileSeal::SealShrink,
            FileSeal::SealGrow,
            FileSeal::SealWrite,
            FileSeal::SealSeal,
        ])
        .typ(SystemError::Panic)?;

        Ok(mem.into_raw_fd())
    }
}