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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use std::time::Duration;

use crate::binding::{self, SemPtr, c_destroy_semaphore,c_p_semaphore_timed, c_init_semaphore, c_p_semaphore, c_v_semaphore, SEM_E_TIMEOUT, SEM_P_V_ON_UNINIT, SEM_INIT_DOUBLE_INIT};

#[derive(Debug)]
pub struct SemaphoreError {
    code:i32
}

/// Wrapper of sem_t in c. Providing Semaphore access without mut access. It is super easy to share!
/// 
/// Example:
/// ```
/// use std::sync::Arc;
/// use std::time::Duration;
/// use std::thread;
/// use classic_sync::semaphore::Semaphore;
/// let sem = Semaphore::new(3); // allows 3 concurrent access
/// let arc_sem = Arc::new(sem);
/// for i in 0..3 {
///     let sem_copy = Arc::clone(&arc_sem);
///     let tid = i;
///     thread::spawn(move || {
///         sem_copy.p();
///         println!("Now I am granted access. I should have 2 other siblings has the access at the same time!");
///         std::thread::sleep(Duration::from_secs(3));
///         // Other people can't acquire the lock even when I am sleeping.
///         sem_copy.v(); // You have to manually unlock it to release the lock
///     });
/// }
/// ```
impl SemaphoreError {
    pub fn code(&self) -> i32 {
        return self.code;
    }

    pub fn is_timeout(&self) -> bool {
        return self.code == SEM_E_TIMEOUT;
    }

    pub fn msg(&self)->String {
        if self.code == SEM_P_V_ON_UNINIT {
            "Use of uninitialized SEMAPHORE".into()
        } else if self.code == SEM_INIT_DOUBLE_INIT {
            "Can't double init SEMAPHORE".into()
        } else if self.code == SEM_E_TIMEOUT {
            "Semaphore wait timed out".into()
        } else {
            format!("SyscallError code: {}", self.code)  
        }
    }
}
impl std::fmt::Display for SemaphoreError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "SemaphoreError code :{}, message:{}", self.code, self.msg())
    }
}

impl std::error::Error for SemaphoreError {
}

type SemaphoreResult<T> = Result<T, SemaphoreError>;

impl SemPtr {
    fn init(&self, count: i32)-> i32 {
        unsafe {
            return c_init_semaphore(self, count);
        }
    }
    fn close(&self) -> i32 {
        unsafe {
            return c_destroy_semaphore(self);
        }
    }

    fn p(&self) -> i32 {
        unsafe {
            return c_p_semaphore(self);
        }
    }

    fn p_timeout(&self, nanos:i64) -> i32 {
        unsafe {
            return c_p_semaphore_timed(self, nanos);
        }
    }
    fn v(&self) -> i32 {
        unsafe {
            return c_v_semaphore(self);
        }
    }
}

#[derive(Debug)]
pub struct Semaphore {
    ptr: SemPtr,
}

fn test<T>(what:T) where
T: Send {

}
impl Semaphore {
    pub fn new(count:i32) -> Semaphore {
        let ptr = SemPtr {
            sem_ptr: 0,
        };
        let result = ptr.init(count);
        if result != 0 {
            panic!("Semaphore init error {result}");
        }
        return Semaphore {
            ptr
        };
    }

    pub fn v(&self) {
        let result = self.ptr.v();
        if result == 0 {
            return;
        }
        panic!("v() operation on semaphore can't fail");
    }

    pub fn p_timeout(&self, duration:Duration) -> bool {
        let nanos = duration.as_nanos();
        let result = self.ptr.p_timeout(nanos as i64);
        if result == 0 {
            return true;
        }
        return false;
    }

    pub fn p(&self) {
        let result = self.ptr.p();

        if result != 0 {
            panic!("p() operation didn't work");
        }
    }
}

impl Drop for Semaphore {
    fn drop(&mut self) {
        self.ptr.close();
    }
}