2017-02-12 4 views
0

Я написал модуль Zsh. Там у меня встроенная функция, сопоставленная с командой Zsh. Эта функция дублирует его STDIN дескриптора файла:dup (fileno (stdin)), а затем порождает 32 потока -> ошибки ввода/вывода

/* Duplicate standard input */ 
oconf->stream = fdopen(dup(fileno(stdin)), "r"); 

Затем нить порождена, получающий oconf структуры. В этой теме, я делаю:

errno = 0; 

/* Read e.g. 5 characters, putting them after previous portion */ 
int count = fread(buf + index, 1, read_size, oconf->stream); 
/* Ensure that our whole data is a string - null terminated */ 
buf[ index + count ] = '\0'; 

if (errno) { 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno) > 
} 

Если я нерест 32 нити в Zsh:

for ((i=1; i<=32; i ++)); do 
    ls -R /Users/myuser/Documents | mybuiltin -A myhash_$i $i 
done 

Затем 2-3 нити имеют ошибку I/O сообщили из приведенного выше fprintf(), например:

ошибка чтения (дескриптор: 7): Ввод/вывод ошибки

ошибки чтения (дескриптор: 5): недопустимый IOCTL для устройства

ошибка чтения (Дескриптор: 14): неприемлемое IOCTL для устройства

Debugger говорит, что эти нити, после нескольких (5-20) Fread() повторов, блокируются в ядро-х __read_nocancel(). Так что что-то действительно плохое происходит с файловым дескриптором.

В противном случае это сработает. Труба правильно передает данные от ls -R, она считывается пользовательским встроенным. Так где же опасность? Как получилось, что dup() в главной теме приводит к чему-то нечитаемому до fread()? У меня были сомнения, если бы я сделал dup() во вторичной теме. Но я держу это только в надежном месте - основной нити, чтобы затем передать готовый поток FILE * к вторичной теме. Также попытался с POSIX open(), read() и close(), результат будет таким же.

ответ

0

Ты проверяешь errno. Вы должны проверить только errno, если функция, которая его устанавливает, сообщила об ошибке. Никакая функция в стандартной библиотеке C или POSIX никогда не устанавливает errno в ноль. И функции могут устанавливать errno на ненулевое значение без сообщения об ошибке.

Например, в Solaris это имело место (и, вероятно, все еще так), что после операций записи errno == ENOTTY, если поток файлов не был терминалом (например, перенаправлен на файл или канал). Не было никакой проблемы; устройство вывода не было терминалом, поэтому операция с терминалом не удалась, установив errno на ENOTTY.

Вы в настоящее время:

/* Read e.g. 5 characters, putting them after previous portion */ 
int count = fread(buf + index, 1, read_size, oconf->stream); 
/* Ensure that our whole data is a string - null terminated */ 
buf[ index + count ] = '\0'; 

if (errno) { 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno)); 
} 

Вы должны использовать что-то подобное:

int count = fread(buf + index, 1, read_size, oconf->stream); 
if (count == 0) 
{ 
    /* EOF or error — this might be a time to use feof() or ferror() */ 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno)); 
    …flow control?… 
} 
else 
    buf[index + count] = '\0'; 

Вы, вероятно, нужны другие потока из-под контроля деталей (возврат или сломаться или установить флаг) в EOF и путь ошибки; из вашего цитированного фрагмента неясно, что может быть уместным.

Смежные вопросы