Skip to content

Commit b42d2f1

Browse files
committed
Replace interrupt masking with spinlock in timer for SMP support
The timer subsystem originally used NOSCHED_ENTER() and NOSCHED_LEAVE() to disable interrupts when accessing shared timer state, which sufficed on single-core systems. To support SMP, we now replace these macros with a spinlock based on RV32A atomic instructions. This ensures safe concurrent access to global timer state such as timer_initialized, the timer list, and ID management. This change prepares the timer subsystem for correct operation when multiple harts simultaneously create, start, or cancel timers.
1 parent 9e4bdb7 commit b42d2f1

File tree

1 file changed

+21
-17
lines changed

1 file changed

+21
-17
lines changed

kernel/timer.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include <hal.h>
11+
#include <spinlock.h>
1112
#include <lib/list.h>
1213
#include <lib/malloc.h>
1314
#include <sys/task.h>
@@ -31,6 +32,9 @@ static struct {
3132
} timer_cache[4];
3233
static uint8_t timer_cache_index = 0;
3334

35+
static spinlock_t timer_lock = SPINLOCK_INITIALIZER;
36+
static uint32_t timer_flags = 0;
37+
3438
/* Get a node from the pool, fall back to malloc if pool is empty */
3539
static list_node_t *get_timer_node(void)
3640
{
@@ -82,9 +86,9 @@ static int32_t timer_subsystem_init(void)
8286
if (timer_initialized)
8387
return ERR_OK;
8488

85-
NOSCHED_ENTER();
89+
spin_lock_irqsave(&timer_lock, &timer_flags);
8690
if (timer_initialized) {
87-
NOSCHED_LEAVE();
91+
spin_unlock_irqrestore(&timer_lock, timer_flags);
8892
return ERR_OK;
8993
}
9094

@@ -95,7 +99,7 @@ static int32_t timer_subsystem_init(void)
9599
free(all_timers_list);
96100
free(kcb->timer_list);
97101
kcb->timer_list = NULL;
98-
NOSCHED_LEAVE();
102+
spin_unlock_irqrestore(&timer_lock, timer_flags);
99103
return ERR_FAIL;
100104
}
101105

@@ -106,7 +110,7 @@ static int32_t timer_subsystem_init(void)
106110
}
107111

108112
timer_initialized = true;
109-
NOSCHED_LEAVE();
113+
spin_unlock_irqrestore(&timer_lock, timer_flags);
110114
return ERR_OK;
111115
}
112116

@@ -284,7 +288,7 @@ int32_t mo_timer_create(void *(*callback)(void *arg),
284288
if (!t)
285289
return ERR_FAIL;
286290

287-
NOSCHED_ENTER();
291+
spin_lock_irqsave(&timer_lock, &timer_flags);
288292

289293
/* Initialize timer */
290294
t->id = next_id++;
@@ -296,15 +300,15 @@ int32_t mo_timer_create(void *(*callback)(void *arg),
296300

297301
/* Insert into sorted all_timers_list */
298302
if (timer_insert_sorted_by_id(t) != ERR_OK) {
299-
NOSCHED_LEAVE();
303+
spin_unlock_irqrestore(&timer_lock, timer_flags);
300304
free(t);
301305
return ERR_FAIL;
302306
}
303307

304308
/* Add to cache */
305309
cache_timer(t->id, t);
306310

307-
NOSCHED_LEAVE();
311+
spin_unlock_irqrestore(&timer_lock, timer_flags);
308312
return t->id;
309313
}
310314

@@ -313,11 +317,11 @@ int32_t mo_timer_destroy(uint16_t id)
313317
if (!timer_initialized)
314318
return ERR_FAIL;
315319

316-
NOSCHED_ENTER();
320+
spin_lock_irqsave(&timer_lock, &timer_flags);
317321

318322
list_node_t *node = timer_find_node_by_id(id);
319323
if (!node) {
320-
NOSCHED_LEAVE();
324+
spin_unlock_irqrestore(&timer_lock, timer_flags);
321325
return ERR_FAIL;
322326
}
323327

@@ -340,7 +344,7 @@ int32_t mo_timer_destroy(uint16_t id)
340344
free(t);
341345
return_timer_node(node);
342346

343-
NOSCHED_LEAVE();
347+
spin_unlock_irqrestore(&timer_lock, timer_flags);
344348
return ERR_OK;
345349
}
346350

@@ -351,11 +355,11 @@ int32_t mo_timer_start(uint16_t id, uint8_t mode)
351355
if (!timer_initialized)
352356
return ERR_FAIL;
353357

354-
NOSCHED_ENTER();
358+
spin_lock_irqsave(&timer_lock, &timer_flags);
355359

356360
timer_t *t = timer_find_by_id_fast(id);
357361
if (!t) {
358-
NOSCHED_LEAVE();
362+
spin_unlock_irqrestore(&timer_lock, timer_flags);
359363
return ERR_FAIL;
360364
}
361365

@@ -369,11 +373,11 @@ int32_t mo_timer_start(uint16_t id, uint8_t mode)
369373

370374
if (timer_sorted_insert(t) != ERR_OK) {
371375
t->mode = TIMER_DISABLED;
372-
NOSCHED_LEAVE();
376+
spin_unlock_irqrestore(&timer_lock, timer_flags);
373377
return ERR_FAIL;
374378
}
375379

376-
NOSCHED_LEAVE();
380+
spin_unlock_irqrestore(&timer_lock, timer_flags);
377381
return ERR_OK;
378382
}
379383

@@ -382,17 +386,17 @@ int32_t mo_timer_cancel(uint16_t id)
382386
if (!timer_initialized)
383387
return ERR_FAIL;
384388

385-
NOSCHED_ENTER();
389+
spin_lock_irqsave(&timer_lock, &timer_flags);
386390

387391
timer_t *t = timer_find_by_id_fast(id);
388392
if (!t || t->mode == TIMER_DISABLED) {
389-
NOSCHED_LEAVE();
393+
spin_unlock_irqrestore(&timer_lock, timer_flags);
390394
return ERR_FAIL;
391395
}
392396

393397
timer_remove_item_by_data(kcb->timer_list, t);
394398
t->mode = TIMER_DISABLED;
395399

396-
NOSCHED_LEAVE();
400+
spin_unlock_irqrestore(&timer_lock, timer_flags);
397401
return ERR_OK;
398402
}

0 commit comments

Comments
 (0)