1212#include <sys/task.h>
1313
1414#include "private/error.h"
15+ #include "private/utils.h"
1516
1617/* Semaphore Control Block structure. */
1718struct sem_t {
@@ -26,36 +27,47 @@ struct sem_t {
2627
2728static inline bool sem_is_valid (const sem_t * s )
2829{
29- return (s && s -> magic == SEM_MAGIC && s -> wait_q );
30+ return s && s -> magic == SEM_MAGIC && s -> wait_q && s -> max_waiters > 0 &&
31+ s -> count >= 0 && s -> count <= SEM_MAX_COUNT ;
32+ }
33+
34+ static inline void sem_invalidate (sem_t * s )
35+ {
36+ if (s ) {
37+ s -> magic = 0xDEADBEEF ; /* Clear magic to prevent reuse */
38+ s -> count = -1 ;
39+ s -> max_waiters = 0 ;
40+ }
3041}
3142
3243sem_t * mo_sem_create (uint16_t max_waiters , int32_t initial_count )
3344{
3445 /* Enhanced input validation */
35- if (!max_waiters || initial_count < 0 || initial_count > SEM_MAX_COUNT )
46+ if (unlikely (!max_waiters || initial_count < 0 ||
47+ initial_count > SEM_MAX_COUNT ))
3648 return NULL ;
3749
3850 sem_t * sem = malloc (sizeof (sem_t ));
39- if (!sem )
51+ if (unlikely ( !sem ) )
4052 return NULL ;
4153
42- /* Initialize structure to known state */
54+ /* Initialize structure to known safe state */
4355 sem -> wait_q = NULL ;
4456 sem -> count = 0 ;
4557 sem -> max_waiters = 0 ;
4658 sem -> magic = 0 ;
4759
4860 /* Create wait queue */
4961 sem -> wait_q = queue_create (max_waiters );
50- if (!sem -> wait_q ) {
62+ if (unlikely ( !sem -> wait_q ) ) {
5163 free (sem );
5264 return NULL ;
5365 }
5466
5567 /* Initialize remaining fields atomically */
5668 sem -> count = initial_count ;
5769 sem -> max_waiters = max_waiters ;
58- sem -> magic = SEM_MAGIC ; /* Mark as valid last */
70+ sem -> magic = SEM_MAGIC ; /* Mark as valid last to prevent races */
5971
6072 return sem ;
6173}
@@ -65,19 +77,19 @@ int32_t mo_sem_destroy(sem_t *s)
6577 if (!s )
6678 return ERR_OK ; /* Destroying NULL is a no-op, not an error */
6779
68- if (!sem_is_valid (s ))
80+ if (unlikely ( !sem_is_valid (s ) ))
6981 return ERR_FAIL ;
7082
7183 NOSCHED_ENTER ();
7284
7385 /* Check if any tasks are waiting - unsafe to destroy if so */
74- if (queue_count (s -> wait_q ) > 0 ) {
86+ if (unlikely ( queue_count (s -> wait_q ) > 0 ) ) {
7587 NOSCHED_LEAVE ();
7688 return ERR_TASK_BUSY ;
7789 }
7890
79- /* Invalidate the semaphore to prevent further use */
80- s -> magic = 0 ;
91+ /* Atomically invalidate the semaphore to prevent further use */
92+ sem_invalidate ( s ) ;
8193 queue_t * wait_q = s -> wait_q ;
8294 s -> wait_q = NULL ;
8395
@@ -91,23 +103,23 @@ int32_t mo_sem_destroy(sem_t *s)
91103
92104void mo_sem_wait (sem_t * s )
93105{
94- if (!sem_is_valid (s )) {
106+ if (unlikely ( !sem_is_valid (s ) )) {
95107 /* Invalid semaphore - this is a programming error */
96108 panic (ERR_SEM_OPERATION );
97109 }
98110
99111 NOSCHED_ENTER ();
100112
101- /* Fast path: resource available and no waiters (preserves FIFO) */
102- if (s -> count > 0 && queue_count (s -> wait_q ) == 0 ) {
113+ /* Fast path: resource available and no waiters (preserves FIFO ordering ) */
114+ if (likely ( s -> count > 0 && queue_count (s -> wait_q ) == 0 ) ) {
103115 s -> count -- ;
104116 NOSCHED_LEAVE ();
105117 return ;
106118 }
107119
108120 /* Slow path: must wait for resource */
109- /* Verify wait queue has capacity (should never fail for valid semaphore) */
110- if (queue_count (s -> wait_q ) >= s -> max_waiters ) {
121+ /* Verify wait queue has capacity before attempting to block */
122+ if (unlikely ( queue_count (s -> wait_q ) >= s -> max_waiters ) ) {
111123 NOSCHED_LEAVE ();
112124 panic (ERR_SEM_OPERATION ); /* Queue overflow - system error */
113125 }
@@ -120,22 +132,22 @@ void mo_sem_wait(sem_t *s)
120132 */
121133 _sched_block (s -> wait_q );
122134
123- /* When we return here, we have been awakened and have acquired the
124- * semaphore. The task that signaled us did NOT increment the count - the
125- * "token" was passed directly to us , so no further action is needed.
135+ /* When we return here, we have been awakened and acquired the semaphore.
136+ * The signaling task passed the "token" directly to us without incrementing
137+ * the count , so no further action is needed.
126138 */
127139}
128140
129141int32_t mo_sem_trywait (sem_t * s )
130142{
131- if (!sem_is_valid (s ))
143+ if (unlikely ( !sem_is_valid (s ) ))
132144 return ERR_FAIL ;
133145
134146 int32_t result = ERR_FAIL ;
135147
136148 NOSCHED_ENTER ();
137149
138- /* Only succeed if resource is available AND no waiters (preserves FIFO) */
150+ /* Only succeed if resource available AND no waiters (preserves FIFO) */
139151 if (s -> count > 0 && queue_count (s -> wait_q ) == 0 ) {
140152 s -> count -- ;
141153 result = ERR_OK ;
@@ -147,7 +159,7 @@ int32_t mo_sem_trywait(sem_t *s)
147159
148160void mo_sem_signal (sem_t * s )
149161{
150- if (!sem_is_valid (s )) {
162+ if (unlikely ( !sem_is_valid (s ) )) {
151163 /* Invalid semaphore - this is a programming error */
152164 panic (ERR_SEM_OPERATION );
153165 }
@@ -157,13 +169,13 @@ void mo_sem_signal(sem_t *s)
157169
158170 NOSCHED_ENTER ();
159171
160- /* Check if any tasks are waiting */
172+ /* Check if any tasks are waiting for resources */
161173 if (queue_count (s -> wait_q ) > 0 ) {
162174 /* Wake up the oldest waiting task (FIFO order) */
163175 awakened_task = queue_dequeue (s -> wait_q );
164- if (awakened_task ) {
165- /* Validate the awakened task before changing its state */
166- if (awakened_task -> state == TASK_BLOCKED ) {
176+ if (likely ( awakened_task ) ) {
177+ /* Validate awakened task state consistency */
178+ if (likely ( awakened_task -> state == TASK_BLOCKED ) ) {
167179 awakened_task -> state = TASK_READY ;
168180 should_yield = true;
169181 } else {
@@ -172,39 +184,46 @@ void mo_sem_signal(sem_t *s)
172184 }
173185 }
174186 /* Note: count is NOT incremented - the "token" is passed directly to
175- * the awakened task to prevent race conditions.
187+ * the awakened task to prevent race conditions where the count could
188+ * be decremented by another task between our increment and the
189+ * awakened task's execution.
176190 */
177191 } else {
178- /* No waiting tasks - increment available count */
179- if (s -> count < SEM_MAX_COUNT )
192+ /* No waiting tasks - increment available resource count */
193+ if (likely ( s -> count < SEM_MAX_COUNT ) )
180194 s -> count ++ ;
181- /* Silently ignore overflow - semaphore remains at max count */
195+
196+ /* Silently ignore overflow - semaphore remains at max count.
197+ * This prevents wraparound while maintaining system stability.
198+ */
182199 }
183200
184201 NOSCHED_LEAVE ();
185202
186- /* Yield outside critical section to allow awakened task to run.
187- * This improves responsiveness if the awakened task has higher priority.
203+ /* Yield outside critical section if we awakened a task.
204+ * This improves system responsiveness by allowing the awakened task to run
205+ * immediately if it has higher priority.
188206 */
189207 if (should_yield )
190208 mo_task_yield ();
191209}
192210
193211int32_t mo_sem_getvalue (sem_t * s )
194212{
195- if (!sem_is_valid (s ))
213+ if (unlikely ( !sem_is_valid (s ) ))
196214 return -1 ;
197215
198- /* This is inherently racy - the value may change immediately after being
199- * read. The volatile keyword ensures we read the current value, but does
200- * not provide atomicity across multiple operations.
216+ /* This read is inherently racy - the value may change immediately after
217+ * being read. The volatile keyword ensures we read the current value from
218+ * memory, but does not provide atomicity across multiple operations.
219+ * Callers should not rely on this value for synchronization decisions.
201220 */
202221 return s -> count ;
203222}
204223
205224int32_t mo_sem_waiting_count (sem_t * s )
206225{
207- if (!sem_is_valid (s ))
226+ if (unlikely ( !sem_is_valid (s ) ))
208227 return -1 ;
209228
210229 int32_t count ;
0 commit comments