Skip to content

Commit 7354a9f

Browse files
committed
kernel: mempool: fix race condition in rt_mp_alloc
When thread wake up from waiting for memory, there is a chance that there is no memory available in high pressure. So use a loop to check again. Otherwise, there will be a NULL reference. Commit b8bf6be from master.
1 parent d57e880 commit 7354a9f

File tree

1 file changed

+49
-48
lines changed

1 file changed

+49
-48
lines changed

src/mempool.c

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -323,78 +323,79 @@ void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
323323
rt_uint8_t *block_ptr;
324324
register rt_base_t level;
325325
struct rt_thread *thread;
326+
rt_uint32_t before_sleep = 0;
327+
328+
/* get current thread */
329+
thread = rt_thread_self();
326330

327331
/* disable interrupt */
328332
level = rt_hw_interrupt_disable();
329333

330-
if (mp->block_free_count)
331-
{
332-
/* memory block is available. decrease the free block counter */
333-
mp->block_free_count --;
334-
335-
/* get block from block list */
336-
block_ptr = mp->block_list;
337-
mp->block_list = *(rt_uint8_t **)block_ptr;
338-
339-
/* point to memory pool */
340-
*(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
341-
}
342-
else
334+
while (mp->block_free_count == 0)
343335
{
344336
/* memory block is unavailable. */
345337
if (time == 0)
346338
{
347339
/* enable interrupt */
348340
rt_hw_interrupt_enable(level);
349341

342+
rt_set_errno(-RT_ETIMEOUT);
343+
350344
return RT_NULL;
351345
}
352-
else
353-
{
354-
RT_DEBUG_NOT_IN_INTERRUPT;
355346

356-
/* get current thread */
357-
thread = rt_thread_self();
347+
RT_DEBUG_NOT_IN_INTERRUPT;
358348

359-
thread->error = RT_EOK;
349+
thread->error = RT_EOK;
360350

361-
/* need suspend thread */
362-
rt_thread_suspend(thread);
363-
rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
364-
mp->suspend_thread_count ++;
351+
/* need suspend thread */
352+
rt_thread_suspend(thread);
353+
rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
354+
mp->suspend_thread_count++;
365355

366-
if (time > 0)
367-
{
368-
/* init thread timer and start it */
369-
rt_timer_control(&(thread->thread_timer),
370-
RT_TIMER_CTRL_SET_TIME,
371-
&time);
372-
rt_timer_start(&(thread->thread_timer));
373-
}
356+
if (time > 0)
357+
{
358+
/* get the start tick of timer */
359+
before_sleep = rt_tick_get();
360+
361+
/* init thread timer and start it */
362+
rt_timer_control(&(thread->thread_timer),
363+
RT_TIMER_CTRL_SET_TIME,
364+
&time);
365+
rt_timer_start(&(thread->thread_timer));
366+
}
374367

375-
/* enable interrupt */
376-
rt_hw_interrupt_enable(level);
368+
/* enable interrupt */
369+
rt_hw_interrupt_enable(level);
370+
371+
/* do a schedule */
372+
rt_schedule();
377373

378-
/* do a schedule */
379-
rt_schedule();
374+
if (thread->error != RT_EOK)
375+
return RT_NULL;
380376

381-
if (thread->error != RT_EOK)
382-
return RT_NULL;
377+
if (time > 0)
378+
{
379+
time -= rt_tick_get() - before_sleep;
380+
if (time < 0)
381+
time = 0;
382+
}
383+
/* disable interrupt */
384+
level = rt_hw_interrupt_disable();
385+
}
383386

384-
/* disable interrupt */
385-
level = rt_hw_interrupt_disable();
387+
/* memory block is available. decrease the free block counter */
388+
mp->block_free_count--;
386389

387-
/* decrease free block */
388-
mp->block_free_count --;
390+
/* get block from block list */
391+
block_ptr = mp->block_list;
392+
RT_ASSERT(block_ptr != RT_NULL);
389393

390-
/* get block from block list */
391-
block_ptr = mp->block_list;
392-
mp->block_list = *(rt_uint8_t **)block_ptr;
394+
/* Setup the next free node. */
395+
mp->block_list = *(rt_uint8_t **)block_ptr;
393396

394-
/* point to memory pool */
395-
*(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
396-
}
397-
}
397+
/* point to memory pool */
398+
*(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
398399

399400
/* enable interrupt */
400401
rt_hw_interrupt_enable(level);

0 commit comments

Comments
 (0)