Perl中OS页面对齐的分配

时间:2018-10-18 16:17:35

标签: perl mmap ioctl

驱动程序通过ioctl接口公开其API。

ioctl调用的参数是一个内存缓冲区,其地址 必须与操作系统页面大小保持一致。

例如,C语言中的分配将调用valloc(或posix_memalign)

像这样的简单Perl缓冲区分配:

Pan

还不够,因为很可能是标量的起始地址 不会与操作系统页面大小对齐。

有没有简单的方法可以实现这一目标?

注意:我将缓冲区转换为C地址,如下所示:

 $buffer = "\0" x  BUFFER_SIZE ;

谢谢! 没事

2 个答案:

答案 0 :(得分:4)

有多种解决方案,但是按照本书的顺序,您可以使用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

您还可以通过对齐一些较大的内存分配来以其他方式自己执行操作,但是至少需要查询页面大小,因此,如果没有模块和/或模块的帮助,pure-perl解决方案将无法移植浪费内存。

答案 1 :(得分:1)

这是一个无需使用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;