Skip to content

Commit c90db10

Browse files
committed
add a bunch of documentation
also close down some implementation classes that are not meant for extension at the moment. closes #35
1 parent 2af8b84 commit c90db10

File tree

10 files changed

+194
-26
lines changed

10 files changed

+194
-26
lines changed

core/src/main/java/tel/schich/javacan/IsotpCanChannelImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import tel.schich.javacan.platform.linux.LinuxNativeOperationException;
3131
import tel.schich.javacan.platform.linux.LinuxNetworkDevice;
3232

33-
class IsotpCanChannelImpl extends IsotpCanChannel {
33+
final class IsotpCanChannelImpl extends IsotpCanChannel {
3434

3535
private NetworkDevice device;
3636
private IsotpSocketAddress rx;

core/src/main/java/tel/schich/javacan/RawCanChannelImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
/**
3333
* Naming has been adopted from the JDK here (Interface + InterfaceImpl)
3434
*/
35-
public class RawCanChannelImpl extends RawCanChannel {
35+
final class RawCanChannelImpl extends RawCanChannel {
3636

3737
private volatile NetworkDevice device;
3838

epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/EPoll.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import tel.schich.javacan.platform.Platform;
2626
import tel.schich.javacan.platform.linux.LinuxNativeOperationException;
2727

28+
/**
29+
* This class specifies all supported native operations on the epoll subsystem.
30+
*/
2831
class EPoll {
2932

3033
private static final String LIB_NAME = "javacan-epoll";

epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/EPollException.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import tel.schich.javacan.platform.linux.LinuxNativeOperationException;
2626
import tel.schich.jniaccess.JNIAccess;
2727

28+
/**
29+
* Signals a low-level error specific to the epoll subsystem.
30+
*/
2831
public class EPollException extends LinuxNativeOperationException {
2932
@JNIAccess
3033
public EPollException(String message, int errorNumber, String errorString) {

epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/EPollRegistration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
import java.util.Set;
3232

3333
/**
34-
* This class implements the {@link java.nio.channels.SelectionKey} API necessary for
35-
* {@link java.nio.channels.Selector}s.
34+
* This class implements the {@link SelectorRegistration} API necessary for
35+
* {@link tel.schich.javacan.select.IOSelector}s.
3636
*/
37-
public class EPollRegistration<ChannelType extends Channel> implements SelectorRegistration<UnixFileDescriptor, ChannelType> {
37+
final public class EPollRegistration<ChannelType extends Channel> implements SelectorRegistration<UnixFileDescriptor, ChannelType> {
3838

3939
private final EPollSelector selector;
4040
private final ChannelType channel;

epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/EPollSelector.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,15 @@
4040
import static java.util.Collections.newSetFromMap;
4141

4242
/**
43-
* This is an implementation of the {@link java.nio.channels.Selector} API relying on Linux' epoll API to poll for
44-
* IO events from an arbitrary amount of file descriptors. The implementation is based
45-
* on {@link java.nio.channels.spi.AbstractSelector} and is inspired by Java's own epoll-based Selector implementation.
46-
* <p>
47-
* This reimplementation is sadly necessary, because the original implementation does not allow custom
48-
* {@link java.nio.channels.Channel} implementations as Java's selector is requires the channels to implement non-public
49-
* interface to expose the underlying file descriptor.
50-
* <p>
43+
* This is an implementation of the {@link IOSelector} API relying on Linux' epoll API to poll for
44+
* IO events from an arbitrary amount of file descriptors. The implementation is inspired by Java's
45+
* own epoll-based {@link java.nio.channels.Selector} implementation.
46+
*
5147
* This implementation does not expose any more public APIs.
5248
*
5349
* @see <a href="https://man7.org/linux/man-pages/man7/epoll.7.html">epoll man page</a>
5450
*/
55-
public class EPollSelector implements IOSelector<UnixFileDescriptor> {
51+
final public class EPollSelector implements IOSelector<UnixFileDescriptor> {
5652

5753
static {
5854
EPoll.initialize();
@@ -120,7 +116,8 @@ private void ensureOpen() {
120116
throw new ClosedSelectorException();
121117
}
122118

123-
public <ChannelType extends Channel> SelectorRegistration<UnixFileDescriptor, ChannelType> updateRegistration(SelectorRegistration<UnixFileDescriptor, ChannelType> key, Set<SelectorRegistration.Operation> newOps) throws IOException {
119+
public <ChannelType extends Channel> EPollRegistration<ChannelType> updateRegistration(SelectorRegistration<UnixFileDescriptor, ChannelType> key, Set<SelectorRegistration.Operation> newOps) throws IOException {
120+
ensureOpen();
124121
if (key.getSelector() != this) {
125122
throw new IllegalArgumentException("Key is not registered here!");
126123
}
@@ -147,7 +144,7 @@ public <ChannelType extends Channel> SelectorRegistration<UnixFileDescriptor, Ch
147144
}
148145
}
149146

150-
public <ChannelType extends Channel> SelectorRegistration<UnixFileDescriptor, ChannelType> register(ChannelType ch, Set<SelectorRegistration.Operation> ops) throws ClosedChannelException {
147+
public <ChannelType extends Channel> EPollRegistration<ChannelType> register(ChannelType ch, Set<SelectorRegistration.Operation> ops) throws IOException {
151148
ensureOpen();
152149
if (!ch.isOpen()) {
153150
throw new ClosedChannelException();
@@ -162,11 +159,7 @@ public <ChannelType extends Channel> SelectorRegistration<UnixFileDescriptor, Ch
162159
final UnixFileDescriptor handle = (UnixFileDescriptor) nativeHandle;
163160
int fd = handle.getValue();
164161

165-
try {
166-
EPoll.addFileDescriptor(epollfd, fd, translateInterestsToEPoll(ops));
167-
} catch (LinuxNativeOperationException ex) {
168-
throw new RuntimeException(ex);
169-
}
162+
EPoll.addFileDescriptor(epollfd, fd, translateInterestsToEPoll(ops));
170163

171164
EPollRegistration<ChannelType> key = new EPollRegistration<>(this, ch, handle, ops);
172165
synchronized (keyCollectionsLock) {
@@ -208,6 +201,7 @@ private static Set<SelectorRegistration.Operation> translateInterestsFromEPoll(i
208201
}
209202

210203
public <ChannelType extends Channel> boolean cancel(SelectorRegistration<UnixFileDescriptor, ChannelType> registration) throws IOException {
204+
ensureOpen();
211205
if (registration.getSelector() != this) {
212206
return false;
213207
}

epoll/src/main/java/tel/schich/javacan/select/IOEvent.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@
2525
import java.util.Objects;
2626
import java.util.Set;
2727

28-
public class IOEvent<HandleType> {
28+
/**
29+
* This class represents an IO event that happened on a selected channel, which is a tuple consisting
30+
* of the {@link SelectorRegistration} and a set of {@link tel.schich.javacan.select.SelectorRegistration.Operation}s
31+
* that can be performed now.
32+
*
33+
* @param <HandleType> The type of the resource handle
34+
*/
35+
final public class IOEvent<HandleType> {
2936
private final SelectorRegistration<HandleType, ?> registration;
3037
private final Set<SelectorRegistration.Operation> operations;
3138

@@ -34,10 +41,21 @@ public IOEvent(SelectorRegistration<HandleType, ?> registration, Set<SelectorReg
3441
this.operations = operations;
3542
}
3643

44+
/**
45+
* The registration this event belongs to.
46+
* The channel type is not statically known at this point.
47+
*
48+
* @return the registration
49+
*/
3750
public SelectorRegistration<HandleType, ?> getRegistration() {
3851
return registration;
3952
}
4053

54+
/**
55+
* The operations that can be performed now.
56+
*
57+
* @return a set of operations
58+
*/
4159
public Set<SelectorRegistration.Operation> getOperations() {
4260
return operations;
4361
}

epoll/src/main/java/tel/schich/javacan/select/IOSelector.java

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,116 @@
3131
import java.util.List;
3232
import java.util.Set;
3333

34+
/**
35+
* This interface is an improved version of {@link java.nio.channels.Selector} that is able to support SocketCAN sockets together with EPoll.
36+
* It also tries to model differences between platforms more closely by parameterizing the type of the resource handle.
37+
*
38+
* The JDK's {@link java.nio.channels.Selector} interface as a bunch of assumptions about the channel types it supports that make it impossible
39+
* to correctly use epoll. JavaCAN 2.x attempted to extend the existing JDK interfaces to cover the SocketCAN channel types, however certain
40+
* issues were not possible to fix as the JDK interfaces are too restrictive in their extension points, especially around registration and
41+
* cancellation.
42+
*
43+
* @param <HandleType> The type of the resource handle
44+
*
45+
* @see java.nio.channels.Selector
46+
*/
3447
public interface IOSelector<HandleType> extends AutoCloseable {
3548
boolean isOpen();
3649

37-
default <ChannelType extends Channel> SelectorRegistration<HandleType, ChannelType> register(ChannelType ch, SelectorRegistration.Operation... ops) throws ClosedChannelException {
50+
/**
51+
* Registers a channel to this selector and returns a registration.
52+
*
53+
* @param ch the channel to register
54+
* @param ops the operations to register for
55+
* @param <ChannelType> the type of the channel
56+
* @return the registration
57+
* @throws ClosedChannelException if the channel is already closed
58+
* @throws IOException if any low level IO operation failed
59+
*/
60+
default <ChannelType extends Channel> SelectorRegistration<HandleType, ChannelType> register(ChannelType ch, SelectorRegistration.Operation... ops) throws IOException {
3861
return register(ch, EnumSet.copyOf(Arrays.asList(ops)));
3962
}
4063

41-
<ChannelType extends Channel> SelectorRegistration<HandleType, ChannelType> register(ChannelType ch, Set<SelectorRegistration.Operation> ops) throws ClosedChannelException;
64+
/**
65+
* Registers a channel to this selector and returns a registration.
66+
*
67+
* @param ch the channel to register
68+
* @param ops the operations to register for
69+
* @param <ChannelType> the type of the channel
70+
* @return the registration
71+
* @throws ClosedChannelException if the channel is already closed
72+
* @throws IOException if any low level IO operation failed
73+
*/
74+
<ChannelType extends Channel> SelectorRegistration<HandleType, ChannelType> register(ChannelType ch, Set<SelectorRegistration.Operation> ops) throws IOException;
75+
76+
/**
77+
* Cancels a given registration.
78+
*
79+
* @param registration the registration to cancel
80+
* @param <ChannelType> the type of the channel
81+
* @return true if the cancellation was successful
82+
* @throws ClosedChannelException if the channel is already closed
83+
* @throws IOException if any low level IO operation failed
84+
*/
4285
<ChannelType extends Channel> boolean cancel(SelectorRegistration<HandleType, ChannelType> registration) throws IOException;
86+
87+
/**
88+
* Updates a registration's interested operations.
89+
*
90+
* The returned registration is a copy of the given registration with the interested ops updated, however the old
91+
* registration instance remains valid and can equally be used to perform selector operations.
92+
*
93+
* @param registration the registration to update
94+
* @param ops the new operations
95+
* @param <ChannelType> the type of the channel
96+
* @return the updated registration
97+
* @throws ClosedChannelException if the channel is already closed
98+
* @throws IOException if any low level IO operation failed
99+
*/
43100
<ChannelType extends Channel> SelectorRegistration<HandleType, ChannelType> updateRegistration(SelectorRegistration<HandleType, ChannelType> registration, Set<SelectorRegistration.Operation> ops) throws IOException;
44101

102+
/**
103+
* This operation selects IO events on this selector possibly blocking indefinitely until events happen.
104+
* Depending on the implementation this operation may still return without any events, especially when
105+
* {@link #wakeup()} is used.
106+
*
107+
* @return the events that occurred on channels registered to this selector since the last selection.
108+
* @throws IOException if any low level IO operation failed
109+
*/
45110
List<IOEvent<HandleType>> select() throws IOException;
111+
112+
/**
113+
* This operation selects IO events on this selector possibly blocking for the given {@link Duration} until events happen.
114+
* Depending on the implementation this operation may still return earlier without any events, especially when
115+
* {@link #wakeup()} is used.
116+
*
117+
* @param timeout the maximum time to wait for events
118+
* @return the events that occurred on channels registered to this selector since the last selection.
119+
* @throws IOException if any low level IO operation failed
120+
*/
46121
List<IOEvent<HandleType>> select(Duration timeout) throws IOException;
122+
123+
/**
124+
* This operation selects IO events on this selector without blocking when no events exist.
125+
*
126+
* @return the events that occurred on channels registered to this selector since the last selection.
127+
* @throws IOException if any low level IO operation failed
128+
*/
47129
List<IOEvent<HandleType>> selectNow() throws IOException;
130+
131+
/**
132+
* This operation wakes up any blocking {@link #select()} or {@link #select(Duration)} calls, without actually having
133+
* any IO events.
134+
*
135+
* @throws IOException if any low level IO operation failed
136+
*/
48137
void wakeup() throws IOException;
49138

139+
140+
/**
141+
* This operation closes the selector and frees all resources related to it.
142+
*
143+
* @throws IOException if any low level IO operation failed
144+
*/
50145
void close() throws IOException;
51146
}

epoll/src/main/java/tel/schich/javacan/select/SelectorRegistration.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,61 @@
2525
import java.nio.channels.Channel;
2626
import java.util.Set;
2727

28+
/**
29+
* This interfaces describes a registration of a certain {@link Channel} to a certain {@link IOSelector}.
30+
*
31+
* @param <HandleType> The type of the resource handle
32+
* @param <ChannelType> The type pf the channel
33+
*/
2834
public interface SelectorRegistration<HandleType, ChannelType extends Channel> extends AutoCloseable {
35+
/**
36+
* The handle of the resources being selected.
37+
*
38+
* @return the handle
39+
*/
2940
HandleType getHandle();
41+
42+
/**
43+
* The selector that issued this registration.
44+
*
45+
* @return the selector
46+
*/
3047
IOSelector<HandleType> getSelector();
48+
49+
/**
50+
* The channel that was registered,
51+
*
52+
* @return the channel
53+
*/
3154
ChannelType getChannel();
55+
56+
/**
57+
* The operations this registration is interested in.
58+
* This value might not reflect updates of the registration at a later point in time!
59+
*
60+
* @return the set of operations this registration is interested in
61+
*/
3262
Set<Operation> getOperations();
3363

64+
/**
65+
* A channel operation that can be selected on.
66+
*/
3467
enum Operation {
35-
READ, WRITE, ACCEPT, CONNECT
68+
/**
69+
* The channel can be read.
70+
*/
71+
READ,
72+
/**
73+
* The channel can be written.
74+
*/
75+
WRITE,
76+
/**
77+
* The channel can accept a connection.
78+
*/
79+
ACCEPT,
80+
/**
81+
* The channel can connect.
82+
*/
83+
CONNECT
3684
}
3785
}

epoll/src/main/java/tel/schich/javacan/util/EventLoop.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@
4040
import java.util.Set;
4141
import java.util.concurrent.ThreadFactory;
4242

43+
/**
44+
* This is a simple single-threaded event loop implementation.
45+
* It supports registering several channels of the same type.
46+
*
47+
* @param <HandleType> the type of handles that are supported by the underlying {@link IOSelector}
48+
* @param <ChannelType> the type of channels that can be registered
49+
*/
4350
public abstract class EventLoop<HandleType, ChannelType extends Channel> implements Closeable {
4451
private static final Logger LOGGER = LoggerFactory.getLogger(CanBroker.class);
4552

@@ -86,7 +93,7 @@ public Duration getTimeout() {
8693
* @param ops the interested ops
8794
* @throws ClosedChannelException if the channel is already closed
8895
*/
89-
protected final void register(ChannelType ch, Set<SelectorRegistration.Operation> ops) throws ClosedChannelException {
96+
protected final void register(ChannelType ch, Set<SelectorRegistration.Operation> ops) throws IOException {
9097
registrations.put(ch, selector.register(ch, ops));
9198
}
9299

0 commit comments

Comments
 (0)