Почему ioctl FIONREAD из /dev/null возвращает 0 в Mac OS X и случайное число в Linux?

Я столкнулся с тем, что кажется странным при добавлении тестов в проект, над которым я работаю - я использую /dev/null в качестве последовательного порта и не ожидаю, что какие-либо данные будут доступны для чтения.

Однако в LINUX данные всегда доступны, а в Mac OS X после вызова srand() эти данные доступны.

Может кто-нибудь помочь объяснить это поведение?

Вот минимальный жизнеспособный тест C++

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>

int open_serial(const char *device) {
    speed_t bd = B115200;
    int fd;
    int state;
    struct termios config;

    if ((fd = open(device, O_NDELAY | O_NOCTTY | O_NONBLOCK | O_RDWR)) == -1)
        return -1;

    fcntl(fd, F_SETFL, O_RDWR);
    tcgetattr(fd, &config);
    cfmakeraw(&config);
    cfsetispeed(&config, bd);
    cfsetospeed(&config, bd);

    config.c_cflag |= (CLOCAL | CREAD);
    config.c_cflag &= ~(CSTOPB | CSIZE | PARENB);
    config.c_cflag |= CS8;
    config.c_lflag &= ~(ECHO | ECHOE | ICANON | ISIG);
    config.c_oflag &= ~OPOST;
    config.c_cc[VMIN] = 0;
    config.c_cc[VTIME] = 50; // 5 seconds reception timeout

    tcsetattr(fd, TCSANOW, &config);
    ioctl(fd, TIOCMGET, &state);
    state |= (TIOCM_DTR | TIOCM_RTS);
    ioctl(fd, TIOCMSET, &state);

    usleep(10000);    // Sleep for 10 milliseconds
    return fd;
};

int serial_data_available(const int fd) {
    int result;
    ioctl(fd, FIONREAD, &result);
    return result;
};

int main() {
    int fd = open_serial("/dev/null");
    printf("Opened /dev/null - FD: %d\n", fd);
    printf("Serial data available : %d\n", serial_data_available(fd));
    printf("Serial data available : %d\n", serial_data_available(fd));
    printf("Calling srand()\n");
    srand(1234);
    printf("Serial data available : %d\n", serial_data_available(fd));
    printf("Serial data available : %d\n", serial_data_available(fd));
    return 0;
}

Под Mac OS X вывод выглядит следующим образом:

Opened /dev/null - FD: 3
Serial data available : 0
Serial data available : 0
Calling srand()
Serial data available : 148561936
Serial data available : 0

В Linux я получаю следующее:

Opened /dev/null - FD: 3
Serial data available : 32720
Serial data available : 32720
Calling srand()
Serial data available : 32720
Serial data available : 32720

Два вопроса -

  1. Разве /dev/null не должен всегда иметь 0 байтов для чтения?
  2. Почему вызов srand() в Mac OS X приводит к изменению байтов, доступных для чтения из /dev/null?

1 ответ

Проблема была очевидна (задним числом!) - результат int не инициализируется, поэтому, когда в ioctl выдается ошибка, функция возвращает ненулевое целое число, даже если данные могут быть недоступны.

int serial_data_available(const int fd) {
    int result;
    ioctl(fd, FIONREAD, &result);
    return result;
};

правильный код должен быть

int serial_data_available(const int fd) {
    int result = 0;
    ioctl(fd, FIONREAD, &result);
    return result;
};
Другие вопросы по тегам