Linux中C mmap和Java MappedByteBuffer之间的区别

时间:2018-01-13 15:55:06

标签: java c++ linux mmap

我在使用Java的Linux UIO设备时遇到问题。这个设备背后的想法是你有一个带有一组内存映射寄存器的外设。为了访问这些寄存器以进行读写,内核模块公开了一个可以被映射的设备文件(例如/ dev / ui0)以及用于与寄存器交互的指针。 C ++中的以下代码演示了行为:

#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
#include <cstdio>

int main() {
    size_t filesize = 256;
    //Open file
    int fd = open("/dev/uio0", O_RDWR);
    assert(fd != -1);
    //Execute mmap
    void* mmappedData = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    assert(mmappedData != MAP_FAILED);
    //Write the mmapped data to stdout (= FD #1)
    volatile int* regs = (int*) mmappedData;
    for(int i =0; i < 7; i++) printf("REG[%d]=0x%08x\n", i, regs[i]);
    //Cleanup
    int rc = munmap(mmappedData, filesize);
    assert(rc == 0);
    close(fd);
    return 0;
}

上面代码的输出是:

REG[0]=0x00000001
REG[1]=0x00000001
REG[2]=0x00000004
REG[3]=0x00000024
REG[4]=0xa0109146
REG[5]=0x00000024
REG[6]=0x000000b9

哪个是对的。但是,我试图通过以下Java代码实现相同的目标:

public class RegisterFile {
    private final RandomAccessFile mRegisterSetFile;
    private final MappedByteBuffer mByteBuffer;

    public RegisterFile(String deviceName) throws IOException {
        LOGGER.log(Level.INFO, "Mapping device: {0}", deviceName);
        mRegisterSetFile = new RandomAccessFile(deviceName, "rws");
        LOGGER.log(Level.INFO, "File length is: {0}", mRegisterSetFile.length());
        mByteBuffer = mRegisterSetFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 256);
        dump();
    }


    public final void dump() throws IOException {
        StringBuilder builder = new StringBuilder("\n");
        for (Address address : Address.values()) {
            builder.append(String.format("REGFILE[%02d] = 0x%08x\n", address.get(), mByteBuffer.getInt(address.get())));
        }
        LOGGER.log(Level.INFO, "{0}", builder.toString());
    }
}

但结果是:

[junit] Jan 13, 2018 3:50:26 PM org.apache.hadoop.io.compress.gzipFpga.RegisterFile <init>
[junit] INFO: Mapping device: /dev/uio0
[junit] Jan 13, 2018 3:50:26 PM org.apache.hadoop.io.compress.gzipFpga.RegisterFile <init>
[junit] INFO: File length is: 0
[junit] Jan 13, 2018 3:50:26 PM org.apache.hadoop.io.compress.gzipFpga.GzipFpgaCompressor gzipCoreAvailable
[junit] SEVERE: Unable to read from GZIP core devices.
[junit] java.io.IOException: Invalid argument
[junit]     at sun.nio.ch.FileDispatcherImpl.truncate0(Native Method)
[junit]     at sun.nio.ch.FileDispatcherImpl.truncate(FileDispatcherImpl.java:80)
[junit]     at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:906)
[junit]     at org.apache.hadoop.io.compress.gzipFpga.RegisterFile.<init>(RegisterFile.java:85)

我认为原因是File.length()返回0,因为这不是真正的文件。有没有办法强制映射文件?

0 个答案:

没有答案