2015-08-21 4 views
2

Я работаю с пользовательским устройством char char, которое иногда возвращает большие отрицательные значения (около тысяч, скажем, -2000) для своего ioctl().Linux ioctl возвращаемое значение, интерпретируемое кем?

В пользовательском пространстве я не получаю эти значения, возвращенные из вызова ioctl. Вместо этого я получаю возвращаемое значение -1 обратно с errno, установленным на отрицательное значение из модуля ядра (+2000).

Насколько я могу читать и google, __syscall_return() - это макрос, который должен интерпретировать отрицательные значения возврата как ошибки. Но, похоже, он ищет только значения от -1 до -125. Поэтому я не ожидал перевода этих больших отрицательных значений.

Где эти возвращаемые значения переведены? Ожидается ли поведение?

Я нахожусь на Linux 2.6.35.10 с EGLIBC 2.11.3-4 + deb6u6.

+1

Может ли кто-то перенести этот вопрос на SO? –

ответ

2

Перевод и переход на errno происходят на уровне libc. Оба Gnu libc и мкКл libc лечения отрицательных чисел вниз, по меньшей мере, -4095 как условия ошибки, за http://www.makelinux.net/ldd3/chp-6-sect-1

См https://github.molgen.mpg.de/git-mirror/glibc/blob/85b290451e4d3ab460a57f1c5966c5827ca807ca/sysdeps/unix/sysv/linux/aarch64/ioctl.S для реализации Gnu libc из ioctl.

+0

Спасибо. Я ищу эквивалент для i386, но не могу его найти. Не могли бы вы помочь? –

+0

Я нашел https://github.molgen.mpg.de/git-mirror/glibc/blob/85b290451e4d3ab460a57f1c5966c5827ca807ca/sysdeps/unix/sysv/linux/i386/syscall.S, который, похоже, выполняет проверку ошибок на 386. –

0

Итак, с помощью BRPocock я расскажу о своих выводах здесь.

Ядро Linux будет делать проверку ошибок для всех системных вызовов по линиям (от unistd.h):

#define __syscall_return(type, res) \ 
do { \ 
     if ((unsigned long)(res) >= (unsigned long)(-125)) { \ 
       errno = -(res); \ 
       res = -1; \ 
     } \ 
     return (type) (res); \ 
} while (0) 

Libc также будет делать проверку ошибок для всех системных вызовов по линиям (от syscall.S):

.text 
ENTRY (syscall) 

    PUSHARGS_6  /* Save register contents. */ 
    _DOARGS_6(44)  /* Load arguments. */ 
    movl 20(%esp), %eax /* Load syscall number into %eax. */ 
    ENTER_KERNEL  /* Do the system call. */ 
    POPARGS_6  /* Restore register contents. */ 
    cmpl $-4095, %eax /* Check %eax for error. */ 
    jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ 
    ret   /* Return to caller. */ 

PSEUDO_END (syscall) 

Glibc дает основание для значения 4096 (от sysdep.h):

/* Linux uses a negative return value to indicate syscall errors, 
unlike most Unices, which use the condition codes' carry flag. 
Since version 2.1 the return value of a system call might be 
negative even if the call succeeded. E.g., the `lseek' system call 
might return a large offset. Therefore we must not anymore test 
for < 0, but test for a real error by making sure the value in %eax 
is a real error number. Linus said he will make sure the no syscall 
returns a value in -1 .. -4095 as a valid result so we can savely 
test with -4095. */ 

__syscall_return, кажется, отсутствует в более новых ядрах, я еще не исследовал это.