Implement getPollfds and freePollfds

This commit is contained in:
Klaus Reimer 2018-10-12 08:43:29 +02:00
parent 7d65b24fd7
commit bbd9390f47
6 changed files with 391 additions and 9 deletions

View File

@ -19,7 +19,7 @@
Add missing SPEED_SUPER_PLUS constant.
</action>
<action dev="kayahr" type="add" date="2018-10-08">
Wrap new libusb functions: setOption, devMemAlloc, devMemFree, interruptEventHandler.
Wrap new libusb functions: setOption, devMemAlloc, devMemFree, interruptEventHandler, getPollfds, freePollfds.
</action>
<action dev="kayahr" type="update" date="2018-10-07">
Updated to libusb 1.0.22.

View File

@ -775,8 +775,6 @@ public final class LibUsb
* Some options require one or more arguments to be provided. Consult each option's documentation for specific
* requirements.
*
* Since libusb version 1.0.22, LIBUSB_API_VERSION >= 0x01000106
*
* @param context
* The {@link Context} on which to operate.
* @param option
@ -796,8 +794,6 @@ public final class LibUsb
* Some options require one or more arguments to be provided. Consult each option's documentation for specific
* requirements.
*
* Since libusb version 1.0.22, LIBUSB_API_VERSION >= 0x01000106
*
* @param context
* The {@link Context} on which to operate.
* @param option
@ -1335,8 +1331,6 @@ public final class LibUsb
* allocated with this function must be freed with {@link #devMemFree()}. Specifically, this means that the flag
* {@link #TRANSFER_FREE_BUFFER} cannot be used to free memory allocated with this function.
*
* Since version 1.0.21, LIBUSB_API_VERSION >= 0x01000105
*
* @param handle
* A device handle.
* @param length
@ -2140,8 +2134,6 @@ public final class LibUsb
* This is mainly useful for interrupting a dedicated event handling thread when an application wishes to call
* {@link #exit()}.
*
* Since version 1.0.21, LIBUSB_API_VERSION >= 0x01000105
*
* @param ctx
* The context to operate on, or NULL for the default context.
*/
@ -2516,6 +2508,31 @@ public final class LibUsb
*/
static native void unsetPollfdNotifiersNative(final Context context);
/**
* Retrieve a list of file descriptors that should be polled by your main loop as libusb event sources.
*
* The returned list should be freed with {@link #freePollfds()} when done. The actual list contents must not be
* touched.
*
* As file descriptors are a Unix-specific concept, this function is not available on Windows and will always
* return NULL.
*
* @param context
* The context to operate on, or NULL for the default context.
* @return A list of libusb_pollfd structures, NULL on error, NULL on platforms where the functionality is not
* available.
*/
public static native Pollfds getPollfds(final Context context);
/**
* Free a list of {@link Pollfd} structures.
*
* This should be called for all pollfd lists allocated with {@link #getPollfds()}.
*
* It is legal to call this function with a NULL pollfd list. In this case, the function will simply return safely.
*/
public static native void freePollfds(final Pollfds pollfds);
/**
* Allocate a libusb transfer without support for isochronous transfers.
*

View File

@ -0,0 +1,111 @@
/*
* Copyright 2018 Klaus Reimer <k@ailis.de>
* See LICENSE.md for licensing information.
*
* Based on libusb <http://libusb.info/>:
*
* Copyright 2001 Johannes Erdfelt <johannes@erdfelt.com>
* Copyright 2007-2009 Daniel Drake <dsd@gentoo.org>
* Copyright 2010-2012 Peter Stuge <peter@stuge.se>
* Copyright 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net>
* Copyright 2009-2013 Pete Batard <pete@akeo.ie>
* Copyright 2009-2013 Ludovic Rousseau <ludovic.rousseau@gmail.com>
* Copyright 2010-2012 Michael Plante <michael.plante@gmail.com>
* Copyright 2011-2013 Hans de Goede <hdegoede@redhat.com>
* Copyright 2012-2013 Martin Pieuchot <mpi@openbsd.org>
* Copyright 2012-2013 Toby Gray <toby.gray@realvnc.com>
*/
package org.usb4java;
/**
* File descriptor for polling.
*
* @author Klaus Reimer (k@ailis.de)
*/
public final class Pollfd
{
/** There is data to read */
public static final int POLLIN = 1;
/** Writing now will not block. */
public static final int POLLOUT = 4;
/** The native pointer to the pollfd structure. */
private long pollfdPointer;
/**
* Package-private constructor to prevent manual instantiation. Structures are
* always created by JNI.
*/
Pollfd()
{
// Empty
}
/**
* Returns the native pointer to the pollfd structure.
*
* @return The native pointer to the pollfd structure.
*/
public long getPointer()
{
return this.pollfdPointer;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = (prime * result)
+ (int) (this.pollfdPointer ^ (this.pollfdPointer >>> 32));
return result;
}
@Override
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (this.getClass() != obj.getClass())
{
return false;
}
final Pollfd other = (Pollfd) obj;
if (this.pollfdPointer != other.pollfdPointer)
{
return false;
}
return true;
}
@Override
public String toString()
{
return String.format("libusb pollfd 0x%x", this.pollfdPointer);
}
/**
* Returns the numeric file descriptor.
*
* @return The numeric file descriptor.
*/
public native byte fd();
/**
* Returns the event flags to poll.
*
* {@link #POLLIN} indicates that you should monitor this file descriptor for becoming ready to read from, and
* {@link #POLLOUT} indicates that you should monitor this file descriptor for non-blocking write readiness.
*
* @return The event flags to poll.
*/
public native short events();
}

View File

@ -0,0 +1,102 @@
/*
* Copyright 2018 Klaus Reimer <k@ailis.de>
* See LICENSE.md for licensing information.
*/
package org.usb4java;
import java.util.Iterator;
/**
* List of poll file descriptors as returned by {@link LibUsb#getPollfds(Context)}.
*
* @author Klaus Reimer (k@ailis.de)
*/
public final class Pollfds implements Iterable<Pollfd>
{
/** The native pointer to the pollfd array. */
private long pollfdsPointer;
/** The number of file descriptors in the list. */
private int size;
/**
* Package-private constructor to prevent manual instantiation. Structures are
* always created by JNI.
*/
Pollfds()
{
// Empty
}
/**
* Returns the native pointer.
*
* @return The native pointer.
*/
public long getPointer()
{
return this.pollfdsPointer;
}
/**
* Returns the number of poll file descriptors in the list.
*
* @return The number of poll file descriptors in the list.
*/
public int getSize()
{
return this.size;
}
/**
* Returns the poll file descriptor with the specified index.
*
* @param index
* The index.
* @return The poll file descriptor or null when index is out of bounds.
*/
public native Pollfd get(final int index);
@Override
public Iterator<Pollfd> iterator()
{
return new PollfdsIterator(this);
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = (prime * result)
+ (int) (this.pollfdsPointer ^ (this.pollfdsPointer >>> 32));
return result;
}
@Override
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (this.getClass() != obj.getClass())
{
return false;
}
final Pollfds other = (Pollfds) obj;
return this.pollfdsPointer == other.pollfdsPointer;
}
@Override
public String toString()
{
return String.format("libusb pollfd list 0x%x with size %d",
this.pollfdsPointer, this.size);
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2018 Klaus Reimer <k@ailis.de>
* See LICENSE.md for licensing information.
*/
package org.usb4java;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Iterator for {@link Pollfds}.
*
* @author Klaus Reimer (k@ailis.de)
*/
final class PollfdsIterator implements Iterator<Pollfd>
{
/** The file descriptor list. */
private final Pollfds pollfds;
/** The current index. */
private int nextIndex;
/**
* Constructor.
*
* @param pollfds
* The file descriptor list list.
*/
PollfdsIterator(final Pollfds pollfds)
{
this.pollfds = pollfds;
}
@Override
public boolean hasNext()
{
return this.nextIndex < this.pollfds.getSize();
}
@Override
public Pollfd next()
{
if (!hasNext()) throw new NoSuchElementException();
return this.pollfds.get(this.nextIndex++);
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
}

View File

@ -9,8 +9,11 @@ import static org.usb4java.test.UsbAssume.assumeUsbTestsEnabled;
import static org.usb4java.test.UsbAssume.isUsbTestsEnabled;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNotNull;
import java.nio.ByteBuffer;
@ -1212,4 +1215,100 @@ public class LibUsbDeviceTest
LibUsb.exit(null);
}
}
/**
* Tests the {@link LibUsb#getPollfds()} and {@link LibUsb#freePollfds()} methods.
*/
@Test
public void testGetAndFreePollfds()
{
assumeUsbTestsEnabled();
final Pollfds pollfds = LibUsb.getPollfds(this.context);
try {
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
assertNull(pollfds);
} else {
assertNotNull(pollfds);
assertTrue("Size must be >= 0", pollfds.getSize() >= 0);
int i = 0;
for (Pollfd pollfd : pollfds) {
assertEquals(pollfds.get(i), pollfd);
assertTrue("File descriptor must be > 0", pollfd.fd() > 0);
assertTrue("Events must be > 0", pollfd.events() > 0);
i++;
}
}
} finally {
LibUsb.freePollfds(pollfds);
}
}
/**
* Tests the {@link LibUsb#getPollfds()} and {@link LibUsb#freePollfds()} methods with the default context.
*/
@Test
public void testGetAndFreePollfdsWithDefaultContext()
{
assumeUsbTestsEnabled();
assertEquals(0, LibUsb.init(null));
final Pollfds pollfds = LibUsb.getPollfds(null);
try {
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
assertNull(pollfds);
} else {
assertNotNull(pollfds);
assertTrue("Size must be >= 0", pollfds.getSize() >= 0);
int i = 0;
for (Pollfd pollfd : pollfds) {
assertEquals(pollfds.get(i), pollfd);
assertTrue("File descriptor must be > 0", pollfd.fd() > 0);
assertTrue("Events must be > 0", pollfd.events() > 0);
i++;
}
}
} finally {
LibUsb.freePollfds(pollfds);
}
}
/**
* Ensures that {@link LibUsb#freePollfds()} doesn't throw an error when called with null argument.
*/
@Test
public void testFreePollfdsWithNullArgument()
{
LibUsb.freePollfds(null);
}
/**
* Ensures that {@link LibUsb#freePollfds()} doesn't crash when called twice and throws an IllegalStateException
* instead.
*/
@Test(expected = IllegalStateException.class)
public void testDoubleFreePollfds()
{
assumeFalse(System.getProperty("os.name").toLowerCase().contains("windows"));
assumeUsbTestsEnabled();
final Pollfds pollfds = LibUsb.getPollfds(this.context);
LibUsb.freePollfds(pollfds);
LibUsb.freePollfds(pollfds);
}
/**
* Ensures that accessing Pollfds properties after calling {@link LibUsb#freePollfds()} doesn't crash and
* throws an IllegalStateException instead.
*/
@Test(expected = IllegalStateException.class)
public void testPollfdsAccessAfterFree()
{
assumeFalse(System.getProperty("os.name").toLowerCase().contains("windows"));
assumeUsbTestsEnabled();
assertEquals(0, LibUsb.init(null));
final Pollfds pollfds = LibUsb.getPollfds(null);
assertNotNull(pollfds);
LibUsb.freePollfds(pollfds);
assertNotNull(pollfds.get(0));
}
}