带有Libvirt c代码的JNA。我做错了什么?

问题描述 投票:0回答:1

我是JNA的新手,正在尝试通过libvirt c和JNA获取存储信息。

有两个libvirt c函数,virConnectListAllStoragePools()virStoragePoolGetInfo(),如下所示。

    /**
     * virConnectListAllStoragePools:
     * @conn: Pointer to the hypervisor connection.
     * @pools: Pointer to a variable to store the array containing storage pool
     *         objects or NULL if the list is not required (just returns number
     *         of pools).
     * @flags: bitwise-OR of virConnectListAllStoragePoolsFlags.
     *
     * Collect the list of storage pools, and allocate an array to store those
     * objects. This API solves the race inherent between
     * virConnectListStoragePools and virConnectListDefinedStoragePools.
     *
     * Normally, all storage pools are returned; however, @flags can be used to
     * filter the results for a smaller list of targeted pools.  The valid
     * flags are divided into groups, where each group contains bits that
     * describe mutually exclusive attributes of a pool, and where all bits
     * within a group describe all possible pools.
     *
     * The first group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE (online)
     * and VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE (offline) to filter the pools
     * by state.
     *
     * The second group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_PERSITENT
     * (defined) and VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT (running but not
     * defined), to filter the pools by whether they have persistent config or not.
     *
     * The third group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART
     * and VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART, to filter the pools by
     * whether they are marked as autostart or not.
     *
     * The last group of @flags is provided to filter the pools by the types,
     * the flags include:
     * VIR_CONNECT_LIST_STORAGE_POOLS_DIR
     * VIR_CONNECT_LIST_STORAGE_POOLS_FS
     * VIR_CONNECT_LIST_STORAGE_POOLS_NETFS
     * VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL
     * VIR_CONNECT_LIST_STORAGE_POOLS_DISK
     * VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI
     * VIR_CONNECT_LIST_STORAGE_POOLS_SCSI
     * VIR_CONNECT_LIST_STORAGE_POOLS_MPATH
     * VIR_CONNECT_LIST_STORAGE_POOLS_RBD
     * VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG
     * VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER
     * VIR_CONNECT_LIST_STORAGE_POOLS_ZFS
     * VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE
     * VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI_DIRECT
     *
     * Returns the number of storage pools found or -1 and sets @pools to
     * NULL in case of error.  On success, the array stored into @pools is
     * guaranteed to have an extra allocated element set to NULL but not included
     * in the return count, to make iteration easier.  The caller is responsible
     * for calling virStoragePoolFree() on each array element, then calling
     * free() on @pools.
     */
    int
    virConnectListAllStoragePools(virConnectPtr conn,
                                  virStoragePoolPtr **pools,
                                  unsigned int flags)        
    {
    //logic about set pool pointer to parameter '**pools' and return number of pools.
    }

    /**
     * virStoragePoolGetInfo:
     * @pool: pointer to storage pool
     * @info: pointer at which to store info
     *
     * Get volatile information about the storage pool
     * such as free space / usage summary
     *
     * Returns 0 on success, or -1 on failure.
     */
    int
    virStoragePoolGetInfo(virStoragePoolPtr pool,
                          virStoragePoolInfoPtr info)
    {
    // logic about set pool info to parameter 'info'.
    }

我使用JNA的Java代码是:。

1)StoragePoolPointer.java

    import com.sun.jna.PointerType;
    public class StoragePoolPointer extends PointerType {}

2)virStoragePoolInfo

    public class virStoragePoolInfo extends Struture {
       public int state;
       public long capacity;
       public long allocation;
       public long available;
       private static final List<String> filedls = Arrays.asList("state", "capacity", "allocation", "available");

       protected List<String> getFieldOrder() {
          return fields;
       }
    }

3)Libvirt.java接口

    public interface Libvirt extends Library {
       int virConnectListAllStoragePools(ConnectionPoinet VCP, StoragePoolPointer[] pPointers, int flag);

       int virStoragePoolGetInfo(StoragePoolPointer poolPointer, virStoragePoolInfo info);
    }

4)jna测试代码

    public void listAllStoragePools(ConnectionPointer VCP) {
       Libvirt libvirt = (Libvirt) Native.loadLibrary("virt", Libvirt.class);

       StoragePoolPointer[] pPointerArr = new StoragePoolPointer[10];
       int result = livirt.virConnectListAllStoragePools(VCP, pPointerArr, 64);
       // result is fine. i get storage pool count. and also i get StoragePoolPointer object inside array.

       virStoragePoolInfo poolInfo = new virStoragePoolInfo(); 
       libvirt.virStoragePoolGetInfo(pPointerArr[0], poolInfo);
       // when i call libvirt.virStoragePoolGetInfo(). i get a error msg like this. 'libvirt: Storage Driver error : invalid storage pool pointer in virStoragePoolGetInfo.
       //error msg : org.libvirt.LibvirtException: invalid storage pool pointer in virStoragePoolGetInfo.
    }

我认为我使用了错误的接口方法virConnectListAllStoragePools(),并且为'virStoragePoolPtr ** pools'传递了错误的参数。

java jna libvirt
1个回答
0
投票

本机数组布置在连续内存中。在这种情况下,virStoragePoolPtr **pools是指向数组beginning的单个指针; C使用指针大小的知识来使用偏移量来查找其余元素。

JNA不会将(大多数)Java数组转换为该本机布局。当这样做时,它将使用明确定义的大小,例如JNA可以计算其大小并使用其int[]方法进行分配的原始数组(例如Structure)或toArray数组。

您已经在此处定义了Java端数组:

StoragePoolPointer[] pPointerArr = new StoragePoolPointer[10];

但是您尚未分配任何Java对象来填充数组,因此它只是null的数组。此外,即使您确实通过迭代和设置pPointerArr[i] = new StoragePoolPointer()来填充数组,您也将在这些指针上附加了不连续的本机内存。

(至少有两种方法可以解决此问题。一种是使用JNA的Memory类直接分配本机内存,如下所示:

pPointerArr = new Memory(10 * Native.POINTER_SIZE);

[对virConnectListAllStoragePools()的方法调用之后,您将在该缓冲区中保存指针,并且可以进行迭代,例如,当您递增Pointer p = pPointerArr.share(i * Native.POINTER_SIZE)时,i将是每个指针。

或者,您可以定义一个包含指针的Structure,如下所示:

@FieldOrder({ "storagePool" })
public class StoragePoolPointer extends Structure {
    public Pointer storagePool;
}

然后,您可以通过以下两种方式获得Java数组的便利性

连续的本机内存:
StoragePoolPointer[] pPointerArr = 
    (StoragePoolPointer[]) new StoragePoolPointer().toArray(10);

[填充数组后,pPointerArr[i].storagePool将是第i个指针。

假设您正在使用的10只是一个测试占位符,这种情况下的标准JNA习惯用法是使用空指针调用一次virConnectListAllStoragePools()以获取要使用的元素数,然后按我的方式分配内存。上面已经描述过,并使用适当大小的缓冲区(或由缓冲区支持的结构数组)再次调用它。

© www.soinside.com 2019 - 2024. All rights reserved.