Dead lock in prvTimerTask() of smp when porting ca7*2

Hello!
There happens deal lock in prvTimerTask() during porting arm ca7( Reference ca9 ). I have just started with freertos smp so confused with the critical section.

The backtrace when dead lock occurs is as follows:

Thread 1 (Thread 1.1):
#0  0x80401588 in spin_lock (lock=0x80420240 <task_lock>) at ./drivers/spinlock.h:18
#1  0x80401934 in xPortSpinLockTask () at ../../Source/portable/GCC/ARM_CA7/port.c:344
#2  0x804045f4 in vTaskSuspendAll () at ../../Source/tasks.c:2929
#3  0x80408b78 in xQueueSemaphoreTake (xQueue=0x80421a50 <ucHeap+120>, xTicksToWait=4294967295) at ../../Source/queue.c:1585
#4  0x80401f58 in prvEventSemaphoreTask (pvParameters=0x0) at main.c:254
#5  0x00000000 in ?? ()

Thread 2 (Thread 1.2):
#0  0x80401588 in spin_lock (lock=0x80420240 <task_lock>) at ./drivers/spinlock.h:18
#1  0x80401934 in xPortSpinLockTask () at ../../Source/portable/GCC/ARM_CA7/port.c:344
#2  0x804066e8 in vTaskEnterCritical () at ../../Source/tasks.c:5349
#3  0x80409b14 in vQueueWaitForMessageRestricted (xQueue=0x80421984 <xStaticTimerQueue.0>, xTicksToWait=0, xWaitIndefinitely=1) at ../../Source/queue.c:2842
#4  0x8040b410 in prvProcessTimerOrBlockTask (xNextExpireTime=0, xListWasEmpty=1) at ../../Source/timers.c:663
#5  0x8040b34c in prvTimerTask (pvParameters=0x0) at ../../Source/timers.c:617
#6  0x00000000 in ?? ()

I check the calling flow and fine comments in vQueueWaitForMessageRestricted()

but even it should be called with the scheduler locked and not from a critical section.

prvLockQueue( pxQueue ) was called which will enter critical section and try get both lock, but task lock has been acquired. I’m wondering what I did wrong during porting.

My spinlcok implements as follow:

spinlock_t task_lock;
spinlock_t isr_lock;

typedef struct spinlock {
	volatile uint32_t lock;
} spinlock_t;

static inline void spin_lock(spinlock_t *lock)
{
	unsigned long tmp;

	__asm__ __volatile__(
"1:	ldrex	%0, [%1]\n"
"	cmp		%0, #0\n"
"	wfene\n"
"	strexeq	%0, %2, [%1]\n"
"	cmpeq	%0, #0\n"
"	bne		1b\n"
"	dmb"
	: "=&r" (tmp)
	: "r" (&lock->lock), "r" (0x1)
	: "cc");
}

static inline void spin_unlock(spinlock_t *lock)
{
	__asm__ __volatile__(
	"dmb	ish\n"
	"str	%1, [%0]\n"
	"dsb	ishst\n"
	"sev"
	:
	: "r" (&lock->lock), "r" (0x0)
	: "cc");
}

Looking forward to your reply.

Hi Sherry,

From your backtrace, both of the cores are trying to acquire the TASK spinlock and failed. If your system only has two cores, the TASK lock should be able to be locked by one of the core.

The spinlock for SMP is a recursive lock. It should be able to be locked by the same core multiple times. You can reference RP2040 implementation. Please give this method a try and reply further problem in this thread.

2 Likes

The spinlock is supposed to be a RECURSIVE lock, which means if the core that currently owns it tries to take it again, it needs to automatically succeed, not deadlock.

1 Like

@Fresh @richard-damon Thanks for you answer, I did not read the code comments carefully. Thanks again!