named_sem/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod error;
4#[cfg(unix)]
5mod unix;
6#[cfg(windows)]
7mod windows;
8
9use std::time::Duration;
10
11#[cfg(unix)]
12use unix::RawNamedSemaphore;
13#[cfg(windows)]
14use windows::RawNamedSemaphore;
15
16pub use error::Error;
17
18type Result<T> = std::result::Result<T, Error>;
19
20/// Named semaphore.
21///
22/// See lib level documentation for how to use this struct.
23pub struct NamedSemaphore {
24    raw_named_semaphore: RawNamedSemaphore,
25}
26
27impl NamedSemaphore {
28    /// Create a named semaphore with name and initial value, or open it if there
29    /// has already been a semaphore with the same name across system (in which case,
30    /// the `name` and `initial_value` are ignored).
31    ///
32    /// In Linux, `name` should starts with "/" and is no longer than 250, and does not
33    /// contain "/" after the prefix "/". `initial_value` should not greater than
34    /// `SEM_VALUE_MAX`. The underlined implementation is
35    /// [`sem_open`](https://www.man7.org/linux/man-pages/man3/sem_open.3.html).
36    ///
37    /// In Windows, `name` should be no longer than `MAX_PATH`. `initial_value` should
38    /// fit in `i32` and not less than 0, the maximum count of the semaphore is set to the initial value.
39    /// The underlying implementation is
40    /// [`CreateSemaphore`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsemaphorea)
41    ///
42    /// # Notes
43    ///
44    /// The named semaphore will be closed when the `NamedSemaphore` drops.
45    ///
46    /// In Windows, if all accesses to named semaphore have been closed, the semaphore
47    /// will be destroyed.
48    ///
49    /// In Linux, the named semaphore created will not be destroyed even if all processes accessing
50    /// it has been terminated. The named semaphore can be destroyed by removing corresponding
51    /// file in `/dev/shm`, or using [`sem_unlink`](https://www.man7.org/linux/man-pages/man3/sem_unlink.3.html),
52    /// or restarting the operating system.
53    pub fn create<T: AsRef<str>>(name: T, initial_value: u32) -> Result<Self> {
54        let raw_named_semaphore = RawNamedSemaphore::create(name, initial_value)?;
55
56        Ok(Self {
57            raw_named_semaphore,
58        })
59    }
60
61    /// Create a named semaphore with name and initial value, or open it if there
62    /// has already been a semaphore with the same name across system (in which case,
63    /// the `name` and `initial_value` are ignored).
64    /// Max value is used on windows, where the semaphore can have an internal limit. It does not affect linux.
65    ///
66    /// In Linux, `name` should starts with "/" and is no longer than 250, and does not
67    /// contain "/" after the prefix "/". `initial_value` should not greater than
68    /// `SEM_VALUE_MAX`. The underlined implementation is
69    /// [`sem_open`](https://www.man7.org/linux/man-pages/man3/sem_open.3.html).
70    /// Max value does not have an effect on linux.
71    ///
72    /// In Windows, `name` should be no longer than `MAX_PATH`. `initial_value` and `max_value` should
73    /// fit in `i32` and not less than 0. The underlying implementation is
74    /// [`CreateSemaphore`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsemaphorea)
75    ///
76    /// # Notes
77    ///
78    /// The named semaphore will be closed when the `NamedSemaphore` drops.
79    ///
80    /// In Windows, if all accesses to named semaphore have been closed, the semaphore
81    /// will be destroyed.
82    ///
83    /// In Linux, the named semaphore created will not be destroyed even if all processes accessing
84    /// it has been terminated. The named semaphore can be destroyed by removing corresponding
85    /// file in `/dev/shm`, or using [`sem_unlink`](https://www.man7.org/linux/man-pages/man3/sem_unlink.3.html),
86    /// or restarting the operating system.
87    pub fn create_with_max<T: AsRef<str>>(
88        name: T,
89        initial_value: u32,
90        max_value: u32,
91    ) -> Result<Self> {
92        let raw_named_semaphore =
93            RawNamedSemaphore::create_with_max(name, initial_value, max_value)?;
94
95        Ok(Self {
96            raw_named_semaphore,
97        })
98    }
99
100    /// Wait for the semaphore and decrease it, block if current semaphore's count is 0.
101    ///
102    /// In Linux, the underlined implementation is [`sem_wait`](https://www.man7.org/linux/man-pages/man3/sem_wait.3.html).
103    ///
104    /// In Windows, the underlined implementation is
105    /// [`WaitForSingleObject`](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject).
106    pub fn wait(&mut self) -> Result<()> {
107        self.raw_named_semaphore.wait()
108    }
109
110    /// Wait for the semaphore and decrease it, block for `dur` if current semaphore's count is 0.
111    ///
112    /// In Linux, the underlined implementation is [`sem_timedwait`](https://www.man7.org/linux/man-pages/man3/sem_timedwait.3.html).
113    ///
114    /// In Windows, the underlined implementation is
115    /// [`WaitForSingleObject`](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject).
116    ///
117    /// Note that macOS did not provide such functionality, see <https://stackoverflow.com/q/641126/10005095>.
118    pub fn timed_wait(&mut self, dur: Duration) -> Result<()> {
119        self.raw_named_semaphore.timedwait(dur)
120    }
121
122    /// Wait for the semaphore and decrease it, raise [`Error::WouldBlock`] if current
123    /// semaphore's count is 0.
124    ///
125    /// In Linux, the underlined implementation is [`sem_trywait`](https://www.man7.org/linux/man-pages/man3/sem_wait.3.html).
126    ///
127    /// In Windows, the underlined implementation is
128    /// [`WaitForSingleObject`](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject).
129    pub fn try_wait(&mut self) -> Result<()> {
130        self.raw_named_semaphore.try_wait()
131    }
132
133    /// Release the semaphore and increase it.
134    ///
135    /// In Linux, the underlined implementation is [`sem_post`](https://www.man7.org/linux/man-pages/man3/sem_post.3.html).
136    ///
137    /// In Windows, the underlined implementation is
138    /// [`ReleaseSemaphore`](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasesemaphore).
139    pub fn post(&mut self) -> Result<()> {
140        self.raw_named_semaphore.post()
141    }
142
143    /// A convenient method to wait-then-post the semaphore.
144    pub fn wait_then_post<T, F: FnOnce() -> T>(&mut self, action: F) -> Result<T> {
145        self.wait()?;
146        let result = action();
147        self.post()?;
148
149        Ok(result)
150    }
151}