3

我在可加载模块中创建了 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);
}
4

1 回答 1

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

于 2013-08-03T01:07:01.550 回答