JNA с кодом Libvirt c. Что я сделал не так? - PullRequest
0 голосов
/ 04 марта 2020

Я новичок в 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'.
    }

Мой java код с JNA:.

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 test code

    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 ** пулов'.

1 Ответ

0 голосов
/ 05 марта 2020

Собственные массивы расположены в непрерывной памяти. В этом случае virStoragePoolPtr **pools - это одиночный указатель на начало массива; и C использует свои знания о размере указателя, чтобы использовать смещения для поиска оставшихся элементов.

JNA не переводит (большинство) Java массивов в этот собственный макет. Когда это происходит, он использует четко определенные размеры, например, для примитивных массивов, таких как int[] или для массивов Structure, для которых JNA может рассчитать размер и выделить его с помощью метода toArray.

Вы определили здесь массив Java:

StoragePoolPointer[] pPointerArr = new StoragePoolPointer[10];

Но вы не выделили никаких объектов Java для заполнения массива, так что это просто массив null s. Кроме того, даже если вы заполнили массив путем итерации и установки pPointerArr[i] = new StoragePoolPointer(), к этим указателям была бы прикреплена несмежная собственная память.

Существует (как минимум) два подхода к решению этой проблемы. Одним из них является непосредственное выделение собственной памяти с использованием класса Memory JNA, например:

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() один раз с нулевым указателем, чтобы получить количество используемых элементов, а затем выделить память, как я описал выше и вызовите его второй раз с буфером правильного размера (или массивом структур, поддерживаемых буфером).

...