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
/// System V semaphore control operations
///
/// # Examples
///
/// ```
/// use std::thread;
/// use std::time::Duration;
///
/// pub struct BinarySemaphore {
/// key: i32,
/// semid: i32,
/// is_producer: bool,
/// }
///
/// impl BinarySemaphore {
/// const SEM_NUM: i32 = 0;
/// const FIRST_SEM: u16 = 0;
/// const SEM_MAX_VAL: i32 = 1;
/// const SEM_OP_RESERVE: i16 = -1;
/// const SEM_OP_RELEASE: i16 = 1;
///
/// pub fn new(key: i32, is_producer: bool) -> Result<Self, nc::Errno> {
/// let semid =
/// unsafe { nc::semget(key, 1, nc::IPC_CREAT | (nc::S_IRUSR | nc::S_IWUSR) as i32)? };
///
/// let ret = unsafe {
/// let arg = Self::SEM_MAX_VAL as usize;
/// nc::semctl(semid, Self::SEM_NUM, nc::SETVAL, arg)
/// };
///
/// if let Err(errno) = ret {
/// let _ret = unsafe { nc::semctl(semid, nc::IPC_RMID, 0, 0) };
/// return Err(errno);
/// }
///
/// Ok(Self {
/// key,
/// semid,
/// is_producer,
/// })
/// }
///
/// pub fn reserve(&mut self) -> Result<(), nc::Errno> {
/// let mut ops = [nc::sembuf_t {
/// sem_num: Self::FIRST_SEM,
/// sem_op: Self::SEM_OP_RESERVE,
/// sem_flg: 0,
/// }];
///
/// loop {
/// let ret = unsafe { nc::semop(self.semid, &mut ops) };
/// match ret {
/// Ok(_) => return Ok(()),
/// Err(nc::EINTR) => continue,
/// Err(errno) => return Err(errno),
/// }
/// }
/// }
///
/// pub fn release(&mut self) -> Result<(), nc::Errno> {
/// let mut ops = [nc::sembuf_t {
/// sem_num: Self::FIRST_SEM,
/// sem_op: Self::SEM_OP_RELEASE,
/// sem_flg: 0,
/// }];
/// unsafe { nc::semop(self.semid, &mut ops) }
/// }
///
/// #[must_use]
/// #[inline]
/// pub const fn key(&self) -> i32 {
/// self.key
/// }
///
/// #[must_use]
/// #[inline]
/// pub const fn is_producer(&self) -> bool {
/// self.is_producer
/// }
/// }
///
/// impl Drop for BinarySemaphore {
/// fn drop(&mut self) {
/// if self.is_producer {
/// let ret = unsafe { nc::semctl(self.semid, nc::IPC_RMID, 0, 0) };
/// assert!(ret.is_ok());
/// }
/// }
/// }
///
/// const KEY_ID: i32 = 0x1234;
/// let ret = BinarySemaphore::new(KEY_ID, true);
/// if let Err(errno) = ret {
/// eprintln!("sem init failed: {}", nc::strerror(errno));
/// return;
/// }
/// let mut sem = ret.unwrap();
///
/// // child thread as consumer
/// let handle = thread::spawn(|| {
/// let mut sem = BinarySemaphore::new(KEY_ID, false).unwrap();
/// for _ in 0..5 {
/// if let Err(errno) = sem.reserve() {
/// eprintln!("[worker ]sem reserve failed: {}", nc::strerror(errno));
/// break;
/// }
/// println!("[worker] wait for 100 millis");
/// thread::sleep(Duration::from_millis(100));
/// if let Err(errno) = sem.release() {
/// eprintln!("[worker] sem release failed: {}", nc::strerror(errno));
/// }
/// }
/// });
///
/// // parent thread as producer
/// for _ in 0..5 {
/// if let Err(errno) = sem.reserve() {
/// eprintln!("[worker ]sem reserve failed: {}", nc::strerror(errno));
/// break;
/// }
/// println!("[main] wait for 200 millis");
/// thread::sleep(Duration::from_millis(200));
/// if let Err(errno) = sem.release() {
/// eprintln!("[main] sem release failed: {}", nc::strerror(errno));
/// }
/// }
///
/// let _ = handle.join();
/// ```
pub unsafe fn semctl(semid: i32, semnum: i32, cmd: i32, arg: usize) -> Result<i32, Errno> {
let semid = semid as usize;
let semnum = semnum as usize;
let cmd = cmd as usize;
syscall4(SYS_SEMCTL, semid, semnum, cmd, arg).map(|ret| ret as i32)
}