poll() не блокируется, немедленно возвращается
Я пытаюсь поймать прерывание на GPIO через sysfs
с помощью poll()
, У меня -1 в третьей позиции, поэтому он может блокировать, но, кажется, всегда возвращается. Я проверил несколько подобных сообщений на SO. Особенно это (1), это (2), и это (3).
В (1) это было решено путем размещения манекена read()
перед звонком poll()
, Если я сделаю это (см. Комментарий read()
в коде). Мой код проходит цикл один раз и навсегда блокируется poll()
во второй раз.
В (2) это может быть объяснением, но не дает решения моей проблемы.
В (3) у меня уже есть lseek()
до моего read()
Как я могу получить это poll()
блокировать и возвращать только в случае прерывания, когда GPIO value
изменилось?
Вот фрагмент кода:
int read_gpio(char *path, void (*callback)(int)){
int fd;
char buf[11];
int res = 0;
char c;
int off;
struct pollfd gpio_poll_fd = {
.fd = fd,
.events = POLLPRI,
.revents = 0
};
for(;;){
gpio_poll_fd.fd = open(path, O_RDONLY);
if(fd == -1){
perror("error opening file");
return -1;
}
// char c;
// read(fd,&c,1);
LOGD("for begins");
res = poll(&gpio_poll_fd,1,-1);
LOGD("polling ended");
if(res == -1){
perror("error polling");
break;
}
if((gpio_poll_fd.revents & POLLPRI) == POLLPRI){
LOGD("POLLPRI");
off = lseek(fd, 0, SEEK_SET);
if(off == -1) break;
memset(&buf[0], 0, 11);
size_t num = read(fd, &buf[0], 10*sizeof(char));
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
}
if((gpio_poll_fd.revents & POLLERR) == POLLERR) {
//seems always to be true ..
//LOGD("POLLERR");
}
close(fd);
LOGD("for ends");
}
LOGD("for exits");
return 0;
}
Примечание: поскольку я делаю это на Android JNI, я получаю информацию для отладки от LOGD()
Обновление: следуя совету в комментарии jxh, я организовал структуру так, хотя теперь она блокируется poll()
на неопределенный срок. Когда содержание значения изменяется от приложенного извне напряжения, POLLPRI не повышается, а poll() не возвращает:
int read_gpio(char *path, void (*callback)(int)){
int fd = open(path, O_RDONLY);
if(fd == -1){
perror("error opening file");
return -1;
}
char buf[11];
int res, off;
char c;
struct pollfd pfd = {
.fd = fd,
.events = POLLPRI,
.revents = 0
};
for(;;){
LOGD("for begins");
// dummy read causes poll never to run
// lseek() alone here cause poll never to run
// read(fd, &buf[],1);
// lseek(fd, 0, SEEK_SET);
res = poll(&pfd,1,-1);
LOGD("polling ended");
if(res == -1){
perror("error polling");
break;
}
if((pfd.revents & POLLPRI) == POLLPRI){
LOGD("POLLPRI");
off = lseek(fd, 0, SEEK_SET);
if(off == -1) break;
memset(&buf[0], 0, 11);
read(fd, &buf[0], 10*sizeof(char));
// These two lines will cause it to poll constantly
// close(fd);
// fd = open(path, O_RDONLY);
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
}
LOGD("for ends");
}
close(fd);
LOGD("for exits");
return 0;
}
1 ответ
В вашем коде fd
не инициализируется.
Когда вы открываете файл, вы назначаете gpio_poll_fd.fd
напрямую, без использования fd
, так fd
остается неинициализированным.
Пытаться:
gpio_poll_fd.fd = fd = open(path, O_RDONLY);
Как указано в комментариях, согласно руководству по GPIO (которое я не читал до более тщательного изучения этих комментариев), GPIO sysfs
интерфейс немного особенный:
Если вывод может быть сконфигурирован как прерывание, генерирующее прерывания, и если он был настроен для генерирования прерываний (см. Описание "фронта"), вы можете
poll(2)
в этом файле иpoll(2)
будет возвращаться всякий раз, когда прерывание было инициировано. Если вы используетеpoll(2)
установить событияPOLLPRI
а такжеPOLLERR
, Если вы используетеselect(2)
установите дескриптор файла вexceptfds
, Послеpoll(2)
возвращается, либоlseek(2)
к началуsysfs
файл и прочитайте новое значение или закройте файл и снова откройте его, чтобы прочитать значение.
Итак, хотя это не типичный poll()
идиома, ваша конструкция закрытия и повторного открытия верна. Однако я бы предпочел оставить дескриптор файла открытым. Итак, вот как я бы структурировал ваш код:
int read_gpio(char *path, void (*callback)(int)){
char buf[11];
int fd, res, off;
struct pollfd pfd;
if((pfd.fd = fd = open(path, O_RDONLY)) == -1){
perror("path");
return -1;
}
LOGD("First read");
res = read(fd, buf, 10);
assert(res == 10);
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
pfd.events = POLLPRI|POLLERR; // poll(2) says setting POLLERR is
// unnecessary, but GPIO may be
// special.
for(;;){
LOGD("for begins");
if((res = poll(&pfd,1,-1)) == -1){
perror("poll");
break;
}
LOGD("polling ended");
if((pfd.revents & POLLPRI) == POLLPRI){
LOGD("POLLPRI");
off = lseek(fd, 0, SEEK_SET);
if(off == -1) break;
memset(buf, 0, 11);
res = read(fd, buf, 10);
assert(res == 10);
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
} else {
// POLLERR, POLLHUP, or POLLNVAL
break;
}
LOGD("for ends");
}
close(fd);
LOGD("for exits");
return 0;
}