Skip to content

Commit

Permalink
Skipping on Windows (unfortunately is an endless loop)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkarg committed Mar 9, 2024
1 parent 9309c82 commit dbba4f5
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 5 deletions.
50 changes: 50 additions & 0 deletions src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -1625,4 +1625,54 @@ public String toString() {
sb.append(']');
return sb.toString();
}

/**
* Skips over and discards {@code n} bytes of data from this source
* channel. The {@code skip} method may, for a variety of reasons, end
* up skipping over some smaller number of bytes, possibly {@code 0}.
* This may result from any of a number of conditions; reaching end of file
* before {@code n} bytes have been skipped is only one possibility.
* The actual number of bytes skipped is returned. If {@code n} is
* negative, the {@code skip} method for class {@code SocketChannelImpl} always
* returns 0, and no bytes are skipped. Subclasses may handle the negative
* value differently.
*
* @implSpec
* The {@code skip} method implementation of this class creates a
* byte array and then repeatedly reads into it until {@code n} bytes
* have been read or the end of the stream has been reached. Subclasses are
* encouraged to provide a more efficient implementation of this method.
* For instance, the implementation may depend on the ability to seek.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped which might be zero.
* @throws IOException if an I/O error occurs.
* @see java.io.InputStream#skipNBytes(long)
*/
public long skip(long n) throws IOException {
if (n < 1)
return 0;

readLock.lock();
try {
boolean blocking = isBlocking();
long ns = 0;
try {
beginRead(blocking);
configureSocketNonBlockingIfVirtualThread();
ns = IOUtil.drainN(fdVal, n);
if (blocking)
while (IOStatus.okayToRetry(ns) && isOpen()) {
park(Net.POLLIN);
ns = IOUtil.drainN(fdVal, n);
}
} finally {
endRead(blocking, ns > 0);
assert IOStatus.check(ns);
}
return IOStatus.normalize(ns);
} finally {
readLock.unlock();
}
}
}
19 changes: 14 additions & 5 deletions src/java.base/unix/native/libnio/ch/IOUtil.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,17 +158,26 @@ Java_sun_nio_ch_IOUtil_drainN(JNIEnv *env, jclass cl, jint fd, jlong n)
if (n < 1)
return 0;

const long bs = n < MAX_SKIP_BUFFER_SIZE ? n : MAX_SKIP_BUFFER_SIZE;
const long bs = n < MAX_SKIP_BUFFER_SIZE ? (long) n : MAX_SKIP_BUFFER_SIZE;
char buf[bs];
jlong tn = 0;

for (;;) {
const jlong remaining = n - tn;
const ssize_t count = remaining < bs ? remaining : bs;
const ssize_t count = remaining < bs ? (ssize_t) remaining : bs;
const ssize_t nr = read(fd, buf, count);
tn += nr;
if ((nr < 0) && (errno != EAGAIN && errno != EWOULDBLOCK))
JNU_ThrowIOExceptionWithLastError(env, "DrainN");
if (nr < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return tn;
} else if (errno == EINTR) {
return IOS_INTERRUPTED;
} else {
JNU_ThrowIOExceptionWithLastError(env, "read");
return IOS_THROWN;
}
}
if (nr > 0)
tn += nr;
if (nr == bs)
continue;
return tn;
Expand Down
34 changes: 34 additions & 0 deletions src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,38 @@ public long read(ByteBuffer[] dsts) throws IOException {
}
}

/**
* Skips over and discards {@code n} bytes of data from this source
* channel. The {@code skip} method may, for a variety of reasons, end
* up skipping over some smaller number of bytes, possibly {@code 0}.
* This may result from any of a number of conditions; reaching end of file
* before {@code n} bytes have been skipped is only one possibility.
* The actual number of bytes skipped is returned. If {@code n} is
* negative, the {@code skip} method for class {@code SourceChannelImpl} always
* returns 0, and no bytes are skipped. Subclasses may handle the negative
* value differently.
*
* @implSpec
* The {@code skip} method implementation of this class creates a
* byte array and then repeatedly reads into it until {@code n} bytes
* have been read or the end of the stream has been reached. Subclasses are
* encouraged to provide a more efficient implementation of this method.
* For instance, the implementation may depend on the ability to seek.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped which might be zero.
* @throws IOException if an I/O error occurs.
* @see java.io.InputStream#skipNBytes(long)
*/
public long skip(long n) throws IOException {
if (n < 1)
return 0;

try {
return ((SocketChannelImpl) sc).skip(n);
} catch (AsynchronousCloseException x) {
close();
throw x;
}
}
}
30 changes: 30 additions & 0 deletions src/java.base/windows/native/libnio/ch/IOUtil.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ static jfieldID handle_fdID;
/* field id for jint 'fd' in java.io.FileDescriptor used for socket fds */
static jfieldID fd_fdID;

// MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
// use when skipping.
static const int MAX_SKIP_BUFFER_SIZE = 4096;

JNIEXPORT jboolean JNICALL
Java_sun_security_provider_NativeSeedGenerator_nativeGenerateSeed
(JNIEnv *env, jclass clazz, jbyteArray randArray);
Expand Down Expand Up @@ -174,6 +178,32 @@ Java_sun_nio_ch_IOUtil_drain(JNIEnv *env, jclass cl, jint fd)
}
}

JNIEXPORT jlong JNICALL
Java_sun_nio_ch_IOUtil_drainN(JNIEnv *env, jclass cl, jint fd, jlong nt)
{
if (nt < 1)
return 0;

char buf[4096];
jlong readBytes = 0;
for (;;) {
const jlong remaining = nt - readBytes;
const int count = remaining < sizeof(buf) ? (int) remaining : sizeof(buf);
int n = recv((SOCKET) fd, buf, count, 0);
if (n == SOCKET_ERROR) {
if (WSAGetLastError() != WSAEWOULDBLOCK) {
JNU_ThrowIOExceptionWithLastError(env, "recv failed");
}
return readBytes;
}
if (n <= 0)
return readBytes;
readBytes += n;
if (n < (int)sizeof(buf))
return readBytes;
}
}

JNIEXPORT jint JNICALL
Java_sun_nio_ch_IOUtil_write1(JNIEnv *env, jclass cl, jint fd, jbyte b)
{
Expand Down

0 comments on commit dbba4f5

Please sign in to comment.