我在可加载模块中创建了2个Linux内核线程,并将它们绑定到在双核Android设备上运行的独立CPU内核。运行几次之后,我注意到设备重启时硬件看门狗定时器复位。我一直都是这个问题。什么可能导致僵局?
基本上,我需要做的是,确保两个线程在不同的内核上同时运行do_something(),而没有任何人窃取cpu周期(即中断被禁用)。我正在使用自旋锁和一个volatile变量。我也有一个父线程的信号量等待子线程。
#define CPU_COUNT 2
/* Globals */
spinlock_t lock;
struct semaphore sem;
volatile unsigned long count;
/* Thread util function for binding the thread to CPU*/
struct task_struct* thread_init(kthread_fn fn, void* data, int cpu)
{
struct task_struct *ts;
ts=kthread_create(fn, data, "per_cpu_thread");
kthread_bind(ts, cpu);
if (!IS_ERR(ts)) {
wake_up_process(ts);
}
else {
ERR("Failed to bind thread to CPU %d\n", cpu);
}
return ts;
}
/* Sync both threads */
void thread_sync()
{
spin_lock(&lock);
++count;
spin_unlock(&lock);
while (count != CPU_COUNT);
}
void do_something()
{
}
/* Child thread */
int per_cpu_thread_fn(void* data)
{
int i = 0;
unsigned long flags = 0;
int cpu = smp_processor_id();
DBG("per_cpu_thread entering (cpu:%d)...\n", cpu);
/* Disable local interrupts */
local_irq_save(flags);
/* sync threads */
thread_sync();
/* Do something */
do_something();
/* Enable interrupts */
local_irq_restore(flags);
/* Notify parent about exit */
up(&sem);
DBG("per_cpu_thread exiting (cpu:%d)...\n", cpu);
return value;
}
/* Main thread */
int main_thread()
{
int cpuB;
int cpu = smp_processor_id();
unsigned long flags = 0;
DBG("main thread running (cpu:%d)...\n", cpu);
/* Init globals*/
sema_init(&sem, 0);
spin_lock_init(&lock);
count = 0;
/* Launch child thread and bind to the other CPU core */
if (cpu == 0) cpuB = 1; else cpuB = 0;
thread_init(per_cpu_thread_fn, NULL, cpuB);
/* Disable local interrupts */
local_irq_save(flags);
/* thread sync */
thread_sync();
/* Do something here */
do_something();
/* Enable interrupts */
local_irq_restore(flags);
/* Wait for child to join */
DBG("main thread waiting for all child threads to finish ...\n");
down_interruptible(&sem);
}
答案 0 :(得分:0)
我不确定,这是一个真正的原因,但您的代码包含一些严重的错误。
while (count != CPU_COUNT);
中的 第一次。除非读取是原子的,否则不能在没有锁定的情况下读取共享变量。使用count
时,无法保证。
您必须使用锁定保护count
的读取。您可以使用以下内容替换while循环:
unsigned long local_count;
do {
spin_lock(&lock);
local_count = count;
spin_unlock(&lock);
} while (local_count != CPU_COUNT);
或者,您可以使用原子类型。注意没有锁定
atomic_t count = ATOMIC_INIT(0);
...
void thread_sync() {
atomic_inc(&count);
while (atomic_read(&count) != CPU_COUNT);
}
第二次中断问题。我想,你不明白你在做什么。
local_irq_save()
保存并禁用中断。然后,使用local_irq_disable()
再次禁用中断。完成一些工作后,使用local_irq_restore()
恢复以前的状态,并使用local_irq_enable()
启用中断。这种启用是完全错误的。无论以前的状态如何,都可以启用中断。
第三次问题。如果主线程未绑定到cpu,则不应使用smp_processor_id()
,除非您确定在获得cpu编号后内核不会立即重新调度。最好使用get_cpu()
,它会禁用内核抢占,然后返回cpu id。完成后,请致电put_cpu()
。
但是,当你调用get_cpu()
时,这是一个创建和运行其他线程的错误。这就是你应该设置主线程的亲和力的原因。
<强>四即可。获取变量的local_irq_save()
和local_irq_restore()
宏,而不是指向unsigned long
的指针。 (我有一个错误和一些警告传递指针。我想知道你是如何编译代码的)。删除引用
最终代码可在此处找到:http://pastebin.com/Ven6wqWf