Как я могу использовать петлевое устройство (или что-то подобное) с epoll? - PullRequest
0 голосов
/ 12 октября 2018

Я пишу небольшой библиотечный модуль, который обращается к UART и использует epoll для реагирования на входящие данные.Он работает нормально с устройством tty, однако я хочу написать тестовые случаи для этого модуля.Когда я открываю устройство цикла (/ dev / loop *) вместо tty, epoll_ctl завершается с EPERM.В Руководстве говорится:

EPERM: fd не поддерживает epoll.

Итак, вопрос: существует ли какое-либо устройство с обратной связью, которое можно использовать с epoll?


Вот суть моего примера кода: https://gist.github.com/0815fox/9ce9f19648ce2dc9b23b37dbbb9adab4

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <linux/loop.h>
#include <sys/ioctl.h>
#include <pthread.h>

static int getFreeLoopDevice(const char * backingfileName) {
    int loopctlfd, loopfd, backingfile;
    long devnr;
    char loopname[4096];

    loopctlfd = open("/dev/loop-control", O_RDWR);

    devnr = ioctl(loopctlfd, LOOP_CTL_GET_FREE);

    close(loopctlfd);
    return devnr;

    sprintf(loopname, "/dev/loop%ld", devnr);

    loopfd = open(loopname, O_RDWR);

    backingfile = open(backingfileName, O_RDWR);

    ioctl(loopfd, LOOP_SET_FD, backingfile);
    return loopfd;
}

static int set_interface_attribs (int fd, int speed, int parity) {
    struct termios tty;
    memset (&tty, 0, sizeof tty);
    if (tcgetattr (fd, &tty) != 0) {
        fprintf (stderr, "error %d from tcgetattr", errno);
        return -1;
    }

    cfsetospeed (&tty, speed);
    cfsetispeed (&tty, speed);

    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
    // disable IGNBRK for mismatched speed tests; otherwise receive break
    // as \000 chars
    tty.c_iflag &= ~IGNBRK;         // disable break processing
    tty.c_lflag = 0;                // no signaling chars, no echo,
                        // no canonical processing
    tty.c_oflag = 0;                // no remapping, no delays
    tty.c_cc[VMIN]  = 0;            // read doesn't block
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

    tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
                        // enable reading
    tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
    tty.c_cflag |= parity;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr (fd, TCSANOW, &tty) != 0) {
        fprintf (stderr, "error %d from tcsetattr", errno);
        return -1;
    }
    return 0;
}

void set_blocking (int fd, int should_block) {
    struct termios tty;
    memset (&tty, 0, sizeof tty);
    if (tcgetattr (fd, &tty) != 0)
    {
        fprintf (stderr, "error %d from tggetattr", errno);
        return;
    }

    tty.c_cc[VMIN]  = should_block ? 1 : 0;
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    if (tcsetattr (fd, TCSANOW, &tty) != 0)
        fprintf (stderr, "error %d setting term attributes", errno);
}

static void * uart_thread(void * handle) {
    const int uartHandle = *(int*)handle;
    char buffer[100];
    // the epoll stuff:
    const int ePollFileDescriptor = epoll_create(1);
    struct epoll_event ePollEvent;
    ePollEvent.events = EPOLLIN;
    ePollEvent.data.fd = uartHandle;
    const int epoll_ctl_result = epoll_ctl(ePollFileDescriptor, EPOLL_CTL_ADD, uartHandle, &ePollEvent);
    if (epoll_ctl_result) perror("epoll_ctl\n");
    for (;;) {
        static struct epoll_event events[1] __attribute__((aligned(8)));
        const int eventCount = epoll_wait(ePollFileDescriptor, events, 1, -1);
        if (eventCount < 0) {
            perror("epoll_wait\n");
        } else {
            const int bytesRead = read(uartHandle, buffer, 99);
            if (bytesRead >= 0) buffer[bytesRead] = 0;
            else buffer[0] = 0;
            fprintf(stderr, "Buffer: %s\nBytesread:%d\n", buffer, bytesRead);
        }
    }
}

int main (void) {
    // working:
    //    char *portname = "/dev/ttyUSB0";
    //    const int uartHandle = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
    // not working:
    const int uartHandle = getFreeLoopDevice("/tmp/my-loop-back");

    if (uartHandle < 0) {
        fprintf (stderr, "error %d opening: %s\n", errno, strerror (errno));
        return errno;
    }

    set_interface_attribs (uartHandle, B115200, 0);  // set speed to 115,200 bps, 8n1 (no parity)
    set_blocking (uartHandle, 0);                // set no blocking

    // the pthread stuff:
    pthread_t threadHandle;
    const int pthread_create_result = pthread_create( &threadHandle, NULL, uart_thread, (void *) &uartHandle);

    while (1) {
        fprintf(stderr, "writing to uart\n");
        write(uartHandle, "hello!\n", 7);
        sleep(10);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...