Ваш крошечный буфер делает этот супер неэффективным (ядро / пользовательский переход когда-либо 255 байтов).По крайней мере, 8киБ будет намного лучше, может быть, от 32 до 64 тысяч.(Соответствует размеру кэша L2 на типичном современном x86.)
Вам также может понадобиться обработать чтение или запись, возвращающие EINTR
(прерывается сигналом перед чтением любых данных), для корректности в случае, если пользователь нажимает на элементг в нужный момент.Я не уверен точно, как семантика системных вызовов работает здесь, или это только для сигналов с обработчиками.Но если предполагается, что это функция, а не целая программа, вы не можете предполагать, что вызывающая сторона не установила никаких обработчиков.
По крайней мере, вы используете возвращаемое значение read
в качестведлина для write
, поэтому короткие чтения (которые возвращаются рано, но с ненулевой длиной) обрабатываются правильно.
Я думаю, можно с уверенностью предположить / потребовать, чтобы входные FD и stdout не былиоткрывается с O_NONBLOCK
, потому что вы не обрабатываете EWOULDBLOCK / EAGAIN.Но это нормально, и это не ошибка в cat()
, а лишь часть его контракта.
Качество кода: как указывало @phuclv, вы тратите байты кода с xor rax,rax
вместо xor eax,eax
.И это все равно бессмысленно, потому что mov eax, SYS_READ
уже перезаписывает весь RAX.
push rdi
тоже странно.Используйте регистр, например r8
или что-то еще, чтобы спрятать функцию fd arg.syscall
только клобберы RCX, R11 и возвращаемое значение в RAX.Вам не нужно трогать память стека пользовательского пространства между системными вызовами;это может привести к дополнительным пропускам TLB или ошибкам страниц в зависимости от стратегии смягчения последствий Meltdown ядра.(push / pop - это наименьшая опция размера кода.)
Разве OS X не имеет системного вызова для копирования с fd-на-fd для этого?
Linux имеет sendfile(2)
, который копирует между FD в пространстве ядра, избегая копирования данных в пространство пользователя и обратно.(Первоначально он был разработан для веб-файловых серверов с нулевым копированием для отправки данных из файлов в сокеты, и в действительно старых ядрах (до 2.6.33) out_fd
должен был быть сокетом. Но это было много лет назад.) В любом случае,произвольно большие размеры копий без выделения / сбоя страницы любой пользовательской памяти и сохранения копии.
Для файлов, в частности, есть также copy_file_range(2)
, который предоставляет драйверы ядра / файловой системывозможность делать такие вещи, как NFS-копирование на стороне сервера, или создавать ссылки для копирования при записи с системами, которые поддерживают это.(Sendfile также может сделать это, но на странице руководства это не упоминается.)
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
ssize_t copy_file_range(int fd_in, loff_t *off_in,
int fd_out, loff_t *off_out,
size_t len, unsigned int flags);