Выравнивание страницы ОС в Perl - PullRequest
0 голосов
/ 18 октября 2018

Драйвер предоставляет свой API через интерфейс ioctl.

Аргументом для вызова ioctl является буфер памяти, адрес которого должен соответствовать размеру страницы ОС.

Например, выделение в Cвызовет valloc (или posix_memalign)

Простое выделение Perl буфера следующим образом:

 $buffer = "\0" x  BUFFER_SIZE ;

недостаточно, так как, скорее всего, начальный адрес скаляра не будет выровнен по размеру страницы ОС.

Есть ли простой способ добиться этого?

Примечание: я конвертирую буфер в адрес C следующим образом:

 my $c_address = unpack('Q', pack('P', $buffer));

Спасибо!Эяль

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Вот пример, который решает проблему без использования mmap.

В основном код выполняет то, что делает posix_memalign ().

# Required for 'syscall' below
#
require 'syscall.ph';

use strict;
use warnings;

# Linux / unix specific
#
my $PAGE_SIZE = `getconf PAGE_SIZE`;

# Arg = size of requested buffer
#
# return = 1. allocated buffer
#          2. C address of allocated buffer
#          3. Offset for aligned buffer
#
# Code is not portable and tested on x86_64 only.
#
sub valloc
{
    my ($size, $ALIGN) = @_;

    $ALIGN = $PAGE_SIZE
        unless ($ALIGN);

    my $buffer = "\0" x ($size + $ALIGN - 1);

    my $address = unpack('Q', pack('p', $buffer));
    my $aligned_address = (($address + $ALIGN - 1) & (-$ALIGN));
    my $offset = $aligned_address - $address;

    return ($buffer, $address, $offset);
}
#-------------------------------------------------------------

# Example to a function that accepts C address
#
sub cat
{
    my ($path) = @_;

    open (my $fh, '<', $path) || die "$path: $!\n";

    my $size = -s $fh;
    my ($buffer, $address, $offset) = valloc($size);
    syscall(&SYS_read, fileno($fh), $address + $offset, $size);
    close $fh;

    return substr($buffer, $offset, $size);
}
#-------------------------------------------------------------

my $content = cat(__FILE__);
print $content;
0 голосов
/ 18 октября 2018

Существует несколько решений, но, следуя книге, вы можете использовать модуль IO::AIO, который имеет функцию IO::AIO::mmap.По сути, вы бы сделали что-то вроде этого (не проверено):

    use IO::AIO

    IO::AIO::mmap
          my $buffer, BUFFER_SIZE, IO::AIO::PROT_READ | IO::AIO::PROT_WRITE,
          IO::AIO::MAP_PRIVATE | IO::AIO::MAP_ANONYMOUS, undef
       or die "mmap failure: $!";

$buffer будет автоматически отображаться, когда вы undef выйдете или выйдете из области видимости, или вы можете использовать IO::AIO::munmap $buffer.

Вы также можете сделать это самостоятельно другими способами, выровняв несколько больший объем памяти, но вам, по крайней мере, потребуется запросить размер страницы, поэтому решение с использованием чистого perl не может быть выполнено переносимо без помощи модулей.и / или потеря памяти.

...