LINUX.ORG.RU

Помогите найти ошибку в следующем коде!!!


0

0

   do{                                                                                                                                          
        fd_set rfds;    FD_ZERO (&rfds);    FD_SET (port->fd, &rfds);                                                                            
        tv.tv_sec=0;    tv.tv_usec=ITER_WAIT_TIME;                                                                                               
        int intr=0;                                                                                                                              
                                                                                                                                                 
        switch(select(port->fd+1, &rfds, NULL, NULL, &tv))                                                                                       
        {                                                                                                                                        
          case  1: bytes_readed=(size>14)?read(port->fd,buff,14):read(port->fd,buff,size);
                                                       
                   if(errno==EINTR){time_req+=ITER_WAIT_TIME; intr++;};                                                                          
                   switch(bytes_readed)                                                                                                          
                   {                                                                                                                             
                        case -1: if(errno!=EINTR){syslog(LOG_ERR,"can't read port %s : %s",port->name,strerror(errno));return -1;}; break;       
                        case  0: break;                                                                                                          
                        default: buff+=bytes_readed;  size-=bytes_readed;  break;                                                                
                   };                                                                                                                            
                   break;                                                                                                                        
          case  0: break;                                                                                                                        
          case -1: if(errno!=EINTR){syslog(LOG_ERR,"ERROR read port %s : %s",port->name,strerror(errno));return -1;}                             
                   else {time_req+=ITER_WAIT_TIME; intr++;};                                                                                     
                   break;                                                                                                                        
          default: syslog(LOG_ERR,"unexpected ERROR while read port %s : %s",port->name,strerror(errno));return -1;  break;                      
        };                                                                                                                                       
                                                                                                                                                 
        gettimeofday(&time_cur,NULL);                                                                                                            
        time_out=(time_cur.tv_sec-time_start.tv_sec)*1000000+(time_cur.tv_usec-time_star
t.tv_usec);                                              
                                                                                                                                                 
    }while((time_out<time_req) && (size>0) && !((time_out>ITER_WAIT_TIME) && (intr==0)  && (size==answer_size)));                                
★★★★★

не знаю, какую ошибку искать, читать лениво.
но одну видно сразу: значение errno после успешного
системного вызова неопределено! поэтому проверка
if(errno==EINTR) перед switch(bytes_readed) неправильна.

idle ★★★★★
()
Ответ на: комментарий от idle

Здесь ты глубоко ошибаешся. Вызовы read и write в случае EINTR составляют исключение из етого правила.

А ошибка состояла в том что intr надо было обьявить вне цикла.

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

> Здесь ты глубоко ошибаешся. Вызовы read и write
> в случае EINTR составляют исключение из етого правила.

это вы о чем вообще? _любой_ системный вызов
не трогает errno при успешном завершении. см
include/asm/unistd.h _syscall3. поэтому если
read() не вернул -1, в errno, вообще говоря,
может быть что угодно.

idle ★★★★★
()
Ответ на: комментарий от grustnoe

> тут не системные вызовы, а libcшные обертки над ними.

да какая разница, в данном случае? даже если
предположить, что текущая реализация очищает
errno после успешного вызова, закладываться на
это нельзя.

и никто не гарантирует, что в следующей версии
libc вы не увидите в /usr/include/unistd.h
_syscall3(int,read,int,fd,char *,buf,off_t,count).

да блин, о чем говорить.

#include <unistd.h>
#include <stdio.h>
#include <errno.h>


int main(void)
{
        char c;

        errno = EINTR;
        read(0, &c, 1);
        perror("");

        return 0;
}

3:~/$ ./r < /dev/null
Interrupted system call

idle ★★★★★
()
Ответ на: комментарий от idle

В man 2 read достаточно вразумительно написано что ситуация errno==EINTR не сопровождается возвратом -1 как результатом выполнения. Доберусь до линукса запостю фрагмент мана

cvv ★★★★★
() автор топика
Ответ на: комментарий от idle

А вот и man 2 read:

POSIX allows a read that is interrupted after reading some data to return -1 (with errno set to EINTR) or to return the number of bytes already read.

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

> POSIX allows a read that is interrupted after reading some
> data to return -1 (with errno set to EINTR) or to return the
> number of bytes already read.

а теперь сами прочитайте это внимательно.

здесь же английским языком сказано, что в errno
будет EINTR, если read() вернет -1, _или_ вернется
число прочитанных байт, что я и пытаюсь вам втолковать.
также посмотрите на код, который я запостил.

поймите вы наконец, ядро просто не может одновременно
вернуть количество байт, которое было прочитано, и
и какую-то информацию о том, что был сигнал.

idle ★★★★★
()
Ответ на: комментарий от idle

Хорошо idle. Я встретился с такой ситуацией: я писал прогу которая слушала последовательный порт и принимала оттудова некоторые пакеты. размер пакета заранее неизвестен. если во время приёма возникала ситуация EINTR то прога срабатывала так как будто всё нормально но при дальнейшем анализе пакет оказывался оборваным.

И мне один человек посоветовал написать именно то что ты видел и всё заработало нормально.

если ето неправильно то что ты посоветуешь мне написать взамен???

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

> если ето неправильно

"ето" неправильно.

> что ты посоветуешь мне написать взамен???

не видя кода, только искать ошибку, кто выставляет
EINTR, это должно происходить еще до вызова read().

idle ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.