Skip to content

Commit 3f9d1bb

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 c746d0b commit 3f9d1bb

File tree

1 file changed

+22
-17
lines changed

1 file changed

+22
-17
lines changed

kernel/pipe.c

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

57
#include "private/error.h"
68
#include "private/utils.h"
79

8-
static inline bool pipe_is_empty(const pipe_t *p)
10+
static spinlock_t pipe_lock = SPINLOCK_INITIALIZER;
11+
static uint32_t pipe_flags = 0;
12+
13+
static inline int pipe_is_empty(const pipe_t *p)
914
{
1015
return p->used == 0;
1116
}
@@ -64,9 +69,9 @@ int32_t mo_pipe_destroy(pipe_t *p)
6469

6570
void mo_pipe_flush(pipe_t *p)
6671
{
67-
CRITICAL_ENTER();
72+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
6873
p->head = p->tail = p->used = 0;
69-
CRITICAL_LEAVE();
74+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
7075
}
7176

7277
int32_t mo_pipe_size(pipe_t *p)
@@ -78,27 +83,27 @@ int32_t mo_pipe_size(pipe_t *p)
7883
static void pipe_wait_until_readable(pipe_t *p)
7984
{
8085
while (1) {
81-
CRITICAL_ENTER();
86+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
8287
if (!pipe_is_empty(p)) {
83-
CRITICAL_LEAVE();
88+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
8489
return;
8590
}
8691
/* nothing to read – drop critical section and yield CPU */
87-
CRITICAL_LEAVE();
92+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
8893
mo_task_wfi();
8994
}
9095
}
9196

9297
static void pipe_wait_until_writable(pipe_t *p)
9398
{
9499
while (1) {
95-
CRITICAL_ENTER();
100+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
96101
if (!pipe_is_full(p)) {
97-
CRITICAL_LEAVE();
102+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
98103
return;
99104
}
100105
/* buffer full – yield until space is available */
101-
CRITICAL_LEAVE();
106+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
102107
mo_task_wfi();
103108
}
104109
}
@@ -113,9 +118,9 @@ int32_t mo_pipe_read(pipe_t *p, char *dst, uint16_t len)
113118
while (i < len) {
114119
pipe_wait_until_readable(p);
115120

116-
CRITICAL_ENTER();
121+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
117122
dst[i++] = pipe_get_byte(p);
118-
CRITICAL_LEAVE();
123+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
119124
}
120125
return i;
121126
}
@@ -129,9 +134,9 @@ int32_t mo_pipe_write(pipe_t *p, const char *src, uint16_t len)
129134
while (i < len) {
130135
pipe_wait_until_writable(p);
131136

132-
CRITICAL_ENTER();
137+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
133138
pipe_put_byte(p, src[i++]);
134-
CRITICAL_LEAVE();
139+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
135140
}
136141
return i;
137142
}
@@ -143,10 +148,10 @@ int32_t mo_pipe_nbread(pipe_t *p, char *dst, uint16_t len)
143148
return ERR_FAIL;
144149

145150
uint16_t i = 0;
146-
CRITICAL_ENTER();
151+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
147152
while (i < len && !pipe_is_empty(p))
148153
dst[i++] = pipe_get_byte(p);
149-
CRITICAL_LEAVE();
154+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
150155

151156
return i;
152157
}
@@ -157,10 +162,10 @@ int32_t mo_pipe_nbwrite(pipe_t *p, const char *src, uint16_t len)
157162
return ERR_FAIL;
158163

159164
uint16_t i = 0;
160-
CRITICAL_ENTER();
165+
spin_lock_irqsave(&pipe_lock, &pipe_flags);
161166
while (i < len && !pipe_is_full(p))
162167
pipe_put_byte(p, src[i++]);
163-
CRITICAL_LEAVE();
168+
spin_unlock_irqrestore(&pipe_lock, pipe_flags);
164169

165170
return i;
166171
}

0 commit comments

Comments
 (0)