Skip to content

Commit fc36c35

Browse files
committed
Linux: improve resume handling
1 parent a3c18bc commit fc36c35

File tree

4 files changed

+40
-26
lines changed

4 files changed

+40
-26
lines changed

java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLOUT;
3333
import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLWAKEUP;
3434
import static net.codecrete.usb.linux.gen.errno.errno.EINTR;
35-
import static net.codecrete.usb.linux.gen.errno.errno.ENOENT;
35+
import static net.codecrete.usb.linux.gen.errno.errno.ENODEV;
3636
import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC;
3737
import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_BULK;
3838
import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.USBDEVFS_URB_TYPE_CONTROL;
@@ -174,8 +174,9 @@ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) {
174174
if (isMatch) {
175175
var transfer = e.getValue();
176176
transfer.urb = null;
177-
transfer.setResultCode(ENOENT());
177+
transfer.setResultCode(ENODEV());
178178
transfer.setResultSize(0);
179+
transfer.completion().completed(transfer);
179180
availableURBs.add(urb);
180181
}
181182
return isMatch;

java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
import java.util.List;
2020

2121
import static java.lang.System.Logger.Level.INFO;
22+
import static java.lang.foreign.MemorySegment.NULL;
2223
import static net.codecrete.usb.linux.EPoll.epoll_create1;
2324
import static net.codecrete.usb.linux.EPoll.epoll_wait;
2425
import static net.codecrete.usb.linux.Linux.allocateErrorState;
2526
import static net.codecrete.usb.linux.LinuxUsbException.throwException;
2627
import static net.codecrete.usb.linux.LinuxUsbException.throwLastError;
2728
import static net.codecrete.usb.linux.gen.epoll.epoll.EPOLLIN;
29+
import static net.codecrete.usb.linux.gen.errno.errno.EINTR;
2830
import static net.codecrete.usb.linux.gen.fcntl.fcntl.FD_CLOEXEC;
2931

3032
/**
@@ -44,6 +46,9 @@ public class LinuxUsbDeviceRegistry extends UsbDeviceRegistry {
4446
private static final MemorySegment ATTR_PRODUCT;
4547
private static final MemorySegment ATTR_SERIAL;
4648

49+
private MemorySegment monitor;
50+
private int monitorFd;
51+
4752
static {
4853
var global = Arena.global();
4954

@@ -58,13 +63,8 @@ public class LinuxUsbDeviceRegistry extends UsbDeviceRegistry {
5863
ATTR_SERIAL = global.allocateFrom("serial");
5964
}
6065

61-
@SuppressWarnings({"java:S1181", "java:S2189"})
62-
@Override
63-
protected void monitorDevices() {
64-
65-
int fd;
66-
MemorySegment monitor;
67-
66+
@SuppressWarnings("java:S1181")
67+
private boolean setupMonitor() {
6868
try {
6969
// setup udev monitor
7070
var udevInstance = udev.udev_new();
@@ -81,26 +81,34 @@ protected void monitorDevices() {
8181
if (udev.udev_monitor_enable_receiving(monitor) < 0)
8282
throwException("internal error (udev_monitor_enable_receiving)");
8383

84-
fd = udev.udev_monitor_get_fd(monitor);
85-
if (fd < 0)
84+
monitorFd = udev.udev_monitor_get_fd(monitor);
85+
if (monitorFd < 0)
8686
throwException("internal error (udev_monitor_get_fd)");
8787

8888
// create initial list of devices
8989
var deviceList = enumeratePresentDevices(udevInstance);
9090
setInitialDeviceList(deviceList);
91+
return true;
9192

9293
} catch (Throwable e) {
9394
enumerationFailed(e);
94-
return;
95+
return false;
9596
}
97+
}
98+
99+
@SuppressWarnings("java:S2189")
100+
@Override
101+
protected void monitorDevices() {
102+
if (!setupMonitor())
103+
return;
96104

97105
try (var arena = Arena.ofConfined()) {
98106
// create epoll
99107
var errorState = allocateErrorState(arena);
100108
var epfd = epoll_create1(FD_CLOEXEC(), errorState);
101109
if (epfd < 0)
102110
throwLastError(errorState, "internal error (epoll_create)");
103-
EPoll.addFileDescriptor(epfd, EPOLLIN(), fd);
111+
EPoll.addFileDescriptor(epfd, EPOLLIN(), monitorFd);
104112

105113
// allocate event (as output for epoll_wait)
106114
var event = arena.allocate(epoll_event.layout());
@@ -111,22 +119,27 @@ protected void monitorDevices() {
111119
try (var cleanup = new ScopeCleanup()) {
112120

113121
// wait for next change
114-
epoll_wait(epfd, event, 1, -1, errorState);
122+
int res = epoll_wait(epfd, event, 1, -1, errorState);
123+
if (res < 0) {
124+
var err = Linux.getErrno(errorState);
125+
if (err == EINTR())
126+
continue; // continue on interrupt
127+
throwException(err, "internal error (epoll_wait)");
128+
}
115129

116130
// retrieve change
117131
var udevDevice = udev.udev_monitor_receive_device(monitor);
118-
if (udevDevice == null)
119-
continue; // shouldn't happen
120-
121-
cleanup.add(() -> udev.udev_device_unref(udevDevice));
132+
if (udevDevice != NULL) {
133+
cleanup.add(() -> udev.udev_device_unref(udevDevice));
122134

123-
// get details
124-
var action = getDeviceAction(udevDevice);
135+
// get details
136+
var action = getDeviceAction(udevDevice);
125137

126-
if ("add".equals(action)) {
127-
onDeviceConnected(udevDevice);
128-
} else if ("remove".equals(action)) {
129-
onDeviceDisconnected(udevDevice);
138+
if ("add".equals(action)) {
139+
onDeviceConnected(udevDevice);
140+
} else if ("remove".equals(action)) {
141+
onDeviceDisconnected(udevDevice);
142+
}
130143
}
131144
}
132145
}

java-does-usb/src/test/java/net/codecrete/usb/special/Continuous.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static void main(String[] args) throws IOException {
2424
new Thread(() -> readData(device)).start();
2525
new Thread(() -> sendData(device)).start();
2626

27-
System.out.println("Press Enter to exit");
27+
System.out.println("Press RETURN to exit");
2828
System.in.read();
2929
device.close();
3030
}

test-devices/loopback-stm32/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ The device can be put into suspend mode by the host. It will go into a low-power
5252

5353
A MacBook with macOS usually puts the device into suspend mode about 1 minuate after is has gone to sleep if it is not connected to a power supply. The device will wake up when the MacBook is woken up.
5454

55-
On Windows, the device is put to sleep immediately when the Windows computer is put to sleep.
55+
On Windows and Linux, the device is put to sleep immediately when the computer is put to sleep or suspended.
5656

5757

5858
## Building the firmware

0 commit comments

Comments
 (0)