Я разрабатываю драйвер устройства Linux, работающий на встроенном процессоре. Этот драйвер устройства управляет некоторым внешним оборудованием. Внешнее оборудование имеет собственный контроллер DDR и внешний DDR. Аппаратная DDR видна на встроенном процессоре через окно с подвижной памятью (так что я получил постраничный доступ к внешней DDR из драйвера Linux). Я использую ядро Linux версии 2.6.33.
Мой драйвер использует sysfs, чтобы разрешить управление внешним оборудованием из пользовательского пространства. Например, внешнее оборудование генерирует счетчик пульса, который увеличивает определенный адрес во внешней DDR. Драйвер читает это, чтобы определить, работает ли внешнее оборудование.
Если внешняя память DDR работает неправильно, то доступ к внешней памяти DDR приводит к ошибке шины во встроенном процессоре. Для защиты от одновременного многопоточного доступа драйвер использует семафор.
Теперь к проблеме. Если поток захватывает семафор, а затем завершается с ошибкой шины, семафор все еще заблокирован. Все последующие вызовы захватывают семафорный блок неопределенно долго. Какие приемы можно использовать, чтобы избежать зависания драйвера навсегда?
Пример функции sysfs (упрощенно):
static ssize_t running_attr_show(struct device *dev, struct device_attribute *attr, char *buffer)
{
struct my_device * const my_dev = container_of(dev, struct my_device, dev);
int ret;
if(down_interruptible(&my_dev->sem))
{
ret = -ERESTARTSYS;
}
else
{
u32 heartbeat;
int running;
// Following line could cause bus error
heartbeat = mwindow_get_reg(&my_dev->mwindow, HEARTBEAT_COUNTER_ADDR);
running = (heartbeat != my_dev->last_heartbeat) ? 1 : 0;
my_dev->last_heartbeat = heartbeat;
ret = sprintf(buffer, "%d\n", result);
/* unlock */
up(&my_dev->sem);
}
return ret;
}