Skip to content

Commit 7ea07a7

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 05b0342 commit 7ea07a7

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>
@@ -32,6 +33,9 @@ static struct {
3233
} timer_cache[4];
3334
static uint8_t timer_cache_index = 0;
3435

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

86-
NOSCHED_ENTER();
90+
spin_lock_irqsave(&timer_lock, &timer_flags);
8791
if (timer_initialized) {
88-
NOSCHED_LEAVE();
92+
spin_unlock_irqrestore(&timer_lock, timer_flags);
8993
return ERR_OK;
9094
}
9195

@@ -101,7 +105,7 @@ static int32_t timer_subsystem_init(void)
101105
list_destroy(kcb->timer_list);
102106
kcb->timer_list = NULL;
103107
}
104-
NOSCHED_LEAVE();
108+
spin_unlock_irqrestore(&timer_lock, timer_flags);
105109
return ERR_FAIL;
106110
}
107111

@@ -112,7 +116,7 @@ static int32_t timer_subsystem_init(void)
112116
}
113117

114118
timer_initialized = true;
115-
NOSCHED_LEAVE();
119+
spin_unlock_irqrestore(&timer_lock, timer_flags);
116120
return ERR_OK;
117121
}
118122

@@ -294,7 +298,7 @@ int32_t mo_timer_create(void *(*callback)(void *arg),
294298
if (unlikely(!t))
295299
return ERR_FAIL;
296300

297-
NOSCHED_ENTER();
301+
spin_lock_irqsave(&timer_lock, &timer_flags);
298302

299303
/* Initialize timer */
300304
t->id = next_id++;
@@ -307,15 +311,15 @@ int32_t mo_timer_create(void *(*callback)(void *arg),
307311

308312
/* Insert into sorted all_timers_list */
309313
if (unlikely(timer_insert_sorted_by_id(t) != ERR_OK)) {
310-
NOSCHED_LEAVE();
314+
spin_unlock_irqrestore(&timer_lock, timer_flags);
311315
free(t);
312316
return ERR_FAIL;
313317
}
314318

315319
/* Add to cache */
316320
cache_timer(t->id, t);
317321

318-
NOSCHED_LEAVE();
322+
spin_unlock_irqrestore(&timer_lock, timer_flags);
319323
return t->id;
320324
}
321325

@@ -324,11 +328,11 @@ int32_t mo_timer_destroy(uint16_t id)
324328
if (unlikely(!timer_initialized))
325329
return ERR_FAIL;
326330

327-
NOSCHED_ENTER();
331+
spin_lock_irqsave(&timer_lock, &timer_flags);
328332

329333
list_node_t *node = timer_find_node_by_id(id);
330334
if (unlikely(!node)) {
331-
NOSCHED_LEAVE();
335+
spin_unlock_irqrestore(&timer_lock, timer_flags);
332336
return ERR_FAIL;
333337
}
334338

@@ -351,7 +355,7 @@ int32_t mo_timer_destroy(uint16_t id)
351355
free(t);
352356
return_timer_node(node);
353357

354-
NOSCHED_LEAVE();
358+
spin_unlock_irqrestore(&timer_lock, timer_flags);
355359
return ERR_OK;
356360
}
357361

@@ -362,11 +366,11 @@ int32_t mo_timer_start(uint16_t id, uint8_t mode)
362366
if (unlikely(!timer_initialized))
363367
return ERR_FAIL;
364368

365-
NOSCHED_ENTER();
369+
spin_lock_irqsave(&timer_lock, &timer_flags);
366370

367371
timer_t *t = timer_find_by_id_fast(id);
368372
if (unlikely(!t)) {
369-
NOSCHED_LEAVE();
373+
spin_unlock_irqrestore(&timer_lock, timer_flags);
370374
return ERR_FAIL;
371375
}
372376

@@ -380,11 +384,11 @@ int32_t mo_timer_start(uint16_t id, uint8_t mode)
380384

381385
if (unlikely(timer_sorted_insert(t) != ERR_OK)) {
382386
t->mode = TIMER_DISABLED;
383-
NOSCHED_LEAVE();
387+
spin_unlock_irqrestore(&timer_lock, timer_flags);
384388
return ERR_FAIL;
385389
}
386390

387-
NOSCHED_LEAVE();
391+
spin_unlock_irqrestore(&timer_lock, timer_flags);
388392
return ERR_OK;
389393
}
390394

@@ -393,17 +397,17 @@ int32_t mo_timer_cancel(uint16_t id)
393397
if (unlikely(!timer_initialized))
394398
return ERR_FAIL;
395399

396-
NOSCHED_ENTER();
400+
spin_lock_irqsave(&timer_lock, &timer_flags);
397401

398402
timer_t *t = timer_find_by_id_fast(id);
399403
if (unlikely(!t || t->mode == TIMER_DISABLED)) {
400-
NOSCHED_LEAVE();
404+
spin_unlock_irqrestore(&timer_lock, timer_flags);
401405
return ERR_FAIL;
402406
}
403407

404408
timer_remove_item_by_data(kcb->timer_list, t);
405409
t->mode = TIMER_DISABLED;
406410

407-
NOSCHED_LEAVE();
411+
spin_unlock_irqrestore(&timer_lock, timer_flags);
408412
return ERR_OK;
409413
}

0 commit comments

Comments
 (0)