Skip to content

Commit 779dc0b

Browse files
committed
Replace interrupt masking with spinlock in pipe for SMP support
The original pipe implementation used CRITICAL_ENTER() and CRITICAL_LEAVE() to protect critical sections by disabling interrupts, which was acceptable for single-core systems. To support SMP, these macros are replaced with a proper spinlock based on RV32A atomic instructions. This ensures safe concurrent access to the circular buffer used by the pipe, even when multiple harts are performing read or write operations simultaneously. This change is necessary to avoid race conditions and ensure correct pipe behavior under multi-hart task scheduling.
1 parent 9683192 commit 779dc0b

File tree

1 file changed

+24
-19
lines changed

1 file changed

+24
-19
lines changed

kernel/pipe.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <lib/libc.h>
2+
#include <hal.h>
3+
#include <spinlock.h>
24
#include <sys/pipe.h>
35
#include <sys/task.h>
46

@@ -17,8 +19,11 @@ static inline bool pipe_is_valid(const pipe_t *p)
1719
p->head <= p->mask && p->tail <= p->mask;
1820
}
1921

22+
static spinlock_t pipe_lock = SPINLOCK_INITIALIZER;
23+
static uint32_t pipe_flags = 0;
24+
2025
/* empty/full checks using the used counter */
21-
static inline bool pipe_is_empty(const pipe_t *p)
26+
static inline int pipe_is_empty(const pipe_t *p)
2227
{
2328
return p->used == 0;
2429
}
@@ -171,9 +176,9 @@ void mo_pipe_flush(pipe_t *p)
171176
if (unlikely(!pipe_is_valid(p)))
172177
return;
173178

174-
CRITICAL_ENTER();
179+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
175180
p->head = p->tail = p->used = 0;
176-
CRITICAL_LEAVE();
181+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
177182
}
178183

179184
int32_t mo_pipe_size(pipe_t *p)
@@ -198,9 +203,9 @@ int32_t mo_pipe_free_space(pipe_t *p)
198203
if (unlikely(!pipe_is_valid(p)))
199204
return -1;
200205

201-
CRITICAL_ENTER();
206+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
202207
int32_t free_space = (int32_t) pipe_free_space_internal(p);
203-
CRITICAL_LEAVE();
208+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
204209

205210
return free_space;
206211
}
@@ -209,27 +214,27 @@ int32_t mo_pipe_free_space(pipe_t *p)
209214
static void pipe_wait_until_readable(pipe_t *p)
210215
{
211216
while (1) {
212-
CRITICAL_ENTER();
217+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
213218
if (!pipe_is_empty(p)) {
214-
CRITICAL_LEAVE();
219+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
215220
return;
216221
}
217222
/* Nothing to read – drop critical section and yield CPU */
218-
CRITICAL_LEAVE();
223+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
219224
mo_task_wfi(); /* Yield CPU without blocking task state */
220225
}
221226
}
222227

223228
static void pipe_wait_until_writable(pipe_t *p)
224229
{
225230
while (1) {
226-
CRITICAL_ENTER();
231+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
227232
if (!pipe_is_full(p)) {
228-
CRITICAL_LEAVE();
233+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
229234
return;
230235
}
231236
/* Buffer full – yield until space is available */
232-
CRITICAL_LEAVE();
237+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
233238
mo_task_wfi(); /* Yield CPU without blocking task state */
234239
}
235240
}
@@ -247,9 +252,9 @@ int32_t mo_pipe_read(pipe_t *p, char *dst, uint16_t len)
247252
pipe_wait_until_readable(p);
248253

249254
/* Read as much as possible in one critical section */
250-
CRITICAL_ENTER();
255+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
251256
uint16_t chunk = pipe_bulk_read(p, dst + bytes_read, len - bytes_read);
252-
CRITICAL_LEAVE();
257+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
253258

254259
bytes_read += chunk;
255260

@@ -272,10 +277,10 @@ int32_t mo_pipe_write(pipe_t *p, const char *src, uint16_t len)
272277
pipe_wait_until_writable(p);
273278

274279
/* Write as much as possible in one critical section */
275-
CRITICAL_ENTER();
280+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
276281
uint16_t chunk =
277282
pipe_bulk_write(p, src + bytes_written, len - bytes_written);
278-
CRITICAL_LEAVE();
283+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
279284

280285
bytes_written += chunk;
281286

@@ -294,9 +299,9 @@ int32_t mo_pipe_nbread(pipe_t *p, char *dst, uint16_t len)
294299

295300
uint16_t bytes_read;
296301

297-
CRITICAL_ENTER();
302+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
298303
bytes_read = pipe_bulk_read(p, dst, len);
299-
CRITICAL_LEAVE();
304+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
300305

301306
return (int32_t) bytes_read;
302307
}
@@ -309,9 +314,9 @@ int32_t mo_pipe_nbwrite(pipe_t *p, const char *src, uint16_t len)
309314

310315
uint16_t bytes_written;
311316

312-
CRITICAL_ENTER();
317+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
313318
bytes_written = pipe_bulk_write(p, src, len);
314-
CRITICAL_LEAVE();
319+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
315320

316321
return (int32_t) bytes_written;
317322
}

0 commit comments

Comments
 (0)