psx_sem/
sem.rs

1// Copyright 2023 Nathan Sizemore <nathanrsizemore@gmail.com>
2//
3// This Source Code Form is subject to the terms of the
4// Mozilla Public License, v. 2.0. If a copy of the MPL was not
5// distributed with this file, You can obtain one at
6// http://mozilla.org/MPL/2.0/.
7
8use std::{ffi::CString, io};
9
10use bitflags::bitflags;
11
12bitflags! {
13    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14    pub struct OpenOptions: libc::c_int {
15        /// Create if not exists.
16        const CREATE = libc::O_CREAT;
17        /// Open for read.
18        const READ = libc::O_RDONLY;
19        /// Open for write.
20        const WRITE = libc::O_WRONLY;
21    }
22
23    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24    pub struct OpenMode: libc::mode_t {
25        /// User read.
26        const R_USR = libc::S_IRUSR;
27        /// User write.
28        const W_USR = libc::S_IWUSR;
29        /// Group read.
30        const R_GRP = libc::S_IRGRP;
31        /// Group write.
32        const W_GRP = libc::S_IWGRP;
33        /// Other read.
34        const R_OTH = libc::S_IROTH;
35        /// Other write.
36        const W_OTH = libc::S_IWOTH;
37    }
38}
39
40#[derive(Debug)]
41pub struct Sem {
42    ptr: *mut libc::sem_t,
43}
44
45impl Sem {
46    /// Opens a semaphore at `name`.
47    pub fn open(
48        name: &str,
49        oflags: OpenOptions,
50        mode: OpenMode,
51        initial: usize,
52    ) -> io::Result<Self> {
53        let cstr = CString::new(name).unwrap();
54        let r = unsafe {
55            libc::sem_open(
56                cstr.as_ptr(),
57                oflags.bits(),
58                mode.bits() as libc::c_uint,
59                initial,
60            )
61        };
62        if r == libc::SEM_FAILED {
63            return Err(io::Error::last_os_error());
64        }
65
66        Ok(Self {
67            ptr: r as *mut libc::sem_t,
68        })
69    }
70
71    /// Increments the semaphore.
72    pub fn post(&self) -> io::Result<()> {
73        let r = unsafe { libc::sem_post(self.ptr) };
74        if r != 0 {
75            return Err(io::Error::last_os_error());
76        }
77
78        Ok(())
79    }
80
81    /// Decrements the semaphore.
82    pub fn wait(&self) -> io::Result<()> {
83        let r = unsafe { libc::sem_wait(self.ptr) };
84        if r != 0 {
85            return Err(io::Error::last_os_error());
86        }
87
88        Ok(())
89    }
90}
91
92impl Drop for Sem {
93    fn drop(&mut self) {
94        unsafe { libc::sem_close(self.ptr) };
95    }
96}
97
98unsafe impl Send for Sem {}
99unsafe impl Sync for Sem {}