Это Linux, использующий glibc. В BSD есть sched_yield, но есть собственная библиотека libc.
Это не странно. Макрос syscall0 выдает инструкцию ассемблера int 0x80
, а номер системного вызова находится в регистре rax
[архитектура x86]. Это стандартный интерфейс системных вызовов для Linux. Под капотом все функции linux glibc, которые являются оболочками системных вызовов, будут делать это [или использовать более современные пары инструкций sysenter / sysexit x86]
glibc имеет тенденцию «узурпировать» системные вызовы в своих функциях-оболочках и добавлять что-то вокруг них. Например, когда вы вызываете fork
, он [в конечном итоге] вызывает __libc_fork
, который выполняет огромное количество дополнительных функций, связанных с потоками, закрытием файлов и т. Д.
Как правило, glibc делает правильный выбор. Но иногда опытным программистам Linux-приложений требуется необработанное поведение системных вызовов, особенно если они пишут системные утилиты или программы / библиотеки, которые должны тесно взаимодействовать с ядром, драйверами устройств или оборудованием устройства.
На самом деле __libc_fork
не вызывает fork
системный вызов, он вызывает clone
системный вызов, который [сложнее использовать] надмножество fork
. Но старый добрый системный вызов fork
все еще существует. Итак, если вы этого хотите, вам нужны макросы - и я уверен, что где-то есть определение sys_fork
.
С другой стороны, glibc может реализовать sched_yield
ala POSIX как nop, возвращающий -1 и устанавливающий для errno значение ENOSYS
. Я только что проверил последний исходный код glibc и не смог найти "настоящую" реализацию, кроме mach. Вероятно, он действительно работает, я просто не мог его найти.
Иногда в linux есть системный вызов, но glibc не хочет его поддерживать, или они считают его слишком опасным для прикладного программиста, поэтому не используют функцию-оболочку. Итак, макросы - это способ «закончить» glibc.
Вероятная причина того, что glibc реализует sched_yield
как nop, не говоря уже о posix, заключается в том, что они считают это "плохим" и, вероятно, советуют вам использовать вместо этого nanosleep
. Я использовал оба, и они не одинаковы, в зависимости от вашего варианта использования и желаемого эффекта.
Иногда вам нужно выполнить необработанный встроенный системный вызов. Например, загрузчик ELF [каждая система, поддерживающая двоичные файлы ELF, должна иметь такой, а Linux - ld-linux.so
] вызывается ядром для загрузки двоичного файла ELF. Он должен работать до того, как glibc.so станет доступным, потому что это то, что фактически связывает в glibc.so, загрузчик ELF должен иметь некоторые встроенные системные вызовы для open
и read
Кроме того, в большинстве систем есть syscall
библиотека функция, которая принимает переменное количество аргументов. Вы можете реализовать:
#define my_sched_yield() syscall(__NR_sched_yield)
#define my_read(_fd,_buf,_len) syscall(__NR_read,_fd,_buf,_len)
Эта функция обрабатывает возвращаемое системным вызовом значение / ошибку ядра и устанавливает errno. Это то, что должен был сделать макрос __syscall_return
.
Префикс __NR_*
- это то, что использует Linux, но в других системах есть AUE_*
или SYS_*
person
Craig Estey
schedule
02.11.2015