keos_project4/sync/semaphore.rs
1//! # Semaphore.
2//!
3//! A **semaphore** is a fundamental synchronization primitive used to regulate
4//! concurrent access to a finite set of resources. It maintains an internal
5//! count representing the number of available "permits." Each permit grants a
6//! thread the right to access a shared resource. Semaphores are particularly
7//! well-suited for controlling resource allocation and coordinating
8//! thread execution in systems with bounded capacity constraints.
9//!
10//! Conceptually, a semaphore can be implemented using a combination of a
11//! mutex for mutual exclusion and a condition variable to support blocking and
12//! waking threads. This approach ensures thread-safe and efficient control over
13//! the internal permit count.
14//!
15//! Semaphores are widely used in operating systems to solve classic concurrency
16//! problems. One common example is the **producer-consumer** pattern, in which
17//! multiple threads coordinate access to a bounded buffer. A semaphore ensures
18//! that producers do not overfill the buffer and consumers do not read from an
19//! empty buffer.
20//!
21//! Another critical use case is **event signaling**. A semaphore initialized
22//! with zero permits can serve as a one-time or repeating signal, allowing one
23//! thread to notify another when a particular event has occurred.
24//!
25//! ## `Semaphore` in KeOS
26//!
27//! In KeOS, the [`Semaphore`] abstraction provides a clean and safe interface
28//! for controlling access to shared resources. [`Semaphore`] is combined with a
29//! resource to protect. Threads can acquire a permit by calling
30//! [`Semaphore::wait`], and release it either explicitly via
31//! [`Semaphore::signal`] or implicitly using the [`SemaphorePermits`] RAII
32//! guard. This design encourages robust and leak-free resource management, even
33//! in the presence of early returns or panics.
34//!
35//! Key features of the `Semaphore` interface include:
36//!
37//! - [`Semaphore::wait()`]: Decrements the permit count if a permit is
38//! available. If no permits remain, the calling thread blocks until one
39//! becomes available.
40//!
41//! - [`Semaphore::signal()`]: Increments the permit count and wakes one blocked
42//! thread, if any. This allows threads to proceed once a resource has been
43//! released or an event has been signaled.
44//!
45//! - [`SemaphorePermits`]: An RAII-based wrapper that automatically calls
46//! `signal()` when dropped. This ensures that permits are always correctly
47//! released, even in the face of errors or control-flow disruptions.
48//!
49//! By integrating semaphores into the KeOS kernel, you will gain a flexible and
50//! expressive tool for coordinating access to shared resources and implementing
51//! complex thread synchronization patterns.
52//!
53//! #### Usage Example
54//!
55//! ```rust
56//! let sema = Semaphore::new(3, state); // Allows up to 3 concurrent threads to the state
57//!
58//! // Acquire a permit (blocks if unavailable)
59//! let permit = sema.wait();
60//!
61//! // Critical section (up to 3 threads can enter concurrently)
62//! permit.work(); // Call a method defined on the `state`.
63//!
64//! // Permit is automatically released when `permit` goes out of scope.
65//! // Otherwise, you can explicitly released it with `drop(permit)``
66//! ```
67//!
68//! ## Implementation Requirements
69//! You need to implement the followings:
70//! - [`Semaphore`]
71//! - [`Semaphore::new`]
72//! - [`Semaphore::wait`]
73//! - [`Semaphore::signal`]
74//!
75//! By implementing the all synchorinzation primitives, your KeOS kernel now
76//! ready to serve multi-threaded process in the next [`section`].
77//!
78//! [`wait`]: Semaphore::wait
79//! [`signal`]: Semaphore::signal
80//! [`SemaphorePermits`]: SemaphorePermits
81//! [`Mutex`]: crate::sync::Mutex
82//! [`ConditionVariable`]: crate::sync::ConditionVariable
83//! [`section`]: crate::process
84
85use core::ops::Deref;
86
87use super::{condition_variable::ConditionVariable, mutex::Mutex};
88
89/// Counting semaphore.
90///
91/// A semaphore maintains a set of permits and resource. Permits are used to
92/// synchronize access to a shared resource. A semaphore differs from a mutex in
93/// that it can allow more than one concurrent caller to access the shared
94/// resource at a time.
95pub struct Semaphore<T> {
96 resource: T,
97 // TODO: Add any member you need.
98}
99
100impl<T> Semaphore<T> {
101 /// Creates a new semaphore initialized with a specified number of permits.
102 ///
103 /// # Arguments
104 ///
105 /// * `permits` - The initial number of available permits. Must be a
106 /// non-negative number.
107 /// * `state` - A resource combined with this resource
108 pub fn new(permits: usize, resource: T) -> Self {
109 Self {
110 resource,
111 // TODO: Initialize the members you added.
112 }
113 }
114
115 /// Waits until a permit becomes available and then acquires it.
116 ///
117 /// If no permits are available, this function will block the current thread
118 /// until another thread calls `signal()` to release a permit.
119 ///
120 /// This method returns a [`SemaphorePermits`] RAII guard. When the guard is
121 /// dropped, it will automatically release the acquired permit.
122 pub fn wait(&self) -> SemaphorePermits<'_, T> {
123 todo!()
124 }
125
126 /// Releases a permit back to the semaphore.
127 ///
128 /// This method increases the number of available permits by one, and if any
129 /// threads are blocked in `wait()`, one will be woken up to acquire the
130 /// newly released permit.
131 ///
132 /// Normally, you don’t call this directly except for signaling an event
133 /// with a zero-initialized semaphore. Instead, it's automatically invoked
134 /// when a [`SemaphorePermits`] guard is dropped.
135 pub fn signal(&self) {
136 todo!()
137 }
138}
139
140/// An RAII implementation of a "scoped semaphore". When this structure
141/// is dropped (falls out of scope), the semaphore will be signaled.
142///
143/// The data protected by the semaphore can be accessed through this guard via
144/// its [`Deref`] implementations.
145///
146/// This structure is created by the [`wait`] method on [`Semaphore`].
147///
148/// [`wait`]: Semaphore::wait
149pub struct SemaphorePermits<'a, T> {
150 sema: &'a Semaphore<T>,
151}
152
153impl<T> Deref for SemaphorePermits<'_, T> {
154 type Target = T;
155 fn deref(&self) -> &Self::Target {
156 &self.sema.resource
157 }
158}
159
160impl<T> Drop for SemaphorePermits<'_, T> {
161 fn drop(&mut self) {
162 self.sema.signal()
163 }
164}