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}