7169050: (se) Selector.select slow on Solaris due to insertion of POLLREMOVE and 0 events
Reviewed-by: chegar, coffeys
This commit is contained in:
parent
380c23f06b
commit
e1774fc7a1
@ -25,9 +25,7 @@
|
|||||||
|
|
||||||
package sun.nio.ch;
|
package sun.nio.ch;
|
||||||
|
|
||||||
import sun.misc.*;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +64,9 @@ class DevPollArrayWrapper {
|
|||||||
static final short EVENT_OFFSET = 4;
|
static final short EVENT_OFFSET = 4;
|
||||||
static final short REVENT_OFFSET = 6;
|
static final short REVENT_OFFSET = 6;
|
||||||
|
|
||||||
|
// Special value to indicate that an update should be ignored
|
||||||
|
static final byte CANCELLED = (byte)-1;
|
||||||
|
|
||||||
// Maximum number of open file descriptors
|
// Maximum number of open file descriptors
|
||||||
static final int OPEN_MAX = fdLimit();
|
static final int OPEN_MAX = fdLimit();
|
||||||
|
|
||||||
@ -74,13 +75,16 @@ class DevPollArrayWrapper {
|
|||||||
static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);
|
static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);
|
||||||
|
|
||||||
// Base address of the native pollArray
|
// Base address of the native pollArray
|
||||||
private long pollArrayAddress;
|
private final long pollArrayAddress;
|
||||||
|
|
||||||
// Array of pollfd structs used for driver updates
|
// Array of pollfd structs used for driver updates
|
||||||
private AllocatedNativeObject updatePollArray;
|
private final AllocatedNativeObject updatePollArray;
|
||||||
|
|
||||||
// Maximum number of POLL_FD structs to update at once
|
// Maximum number of POLL_FD structs to update at once
|
||||||
private int MAX_UPDATE_SIZE = Math.min(OPEN_MAX, 10000);
|
private final int MAX_UPDATE_SIZE = Math.min(OPEN_MAX, 512);
|
||||||
|
|
||||||
|
// Initial size of arrays for fd registration changes
|
||||||
|
private final int INITIAL_PENDING_UPDATE_SIZE = 64;
|
||||||
|
|
||||||
DevPollArrayWrapper() {
|
DevPollArrayWrapper() {
|
||||||
int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
|
int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
|
||||||
@ -91,19 +95,6 @@ class DevPollArrayWrapper {
|
|||||||
wfd = init();
|
wfd = init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Machinery for remembering fd registration changes
|
|
||||||
// A hashmap could be used but the number of changes pending
|
|
||||||
// is expected to be small
|
|
||||||
private static class Updator {
|
|
||||||
int fd;
|
|
||||||
int mask;
|
|
||||||
Updator(int fd, int mask) {
|
|
||||||
this.fd = fd;
|
|
||||||
this.mask = mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private LinkedList<Updator> updateList = new LinkedList<Updator>();
|
|
||||||
|
|
||||||
// The pollfd array for results from devpoll driver
|
// The pollfd array for results from devpoll driver
|
||||||
private AllocatedNativeObject pollArray;
|
private AllocatedNativeObject pollArray;
|
||||||
|
|
||||||
@ -122,6 +113,20 @@ class DevPollArrayWrapper {
|
|||||||
// Number of updated pollfd entries
|
// Number of updated pollfd entries
|
||||||
int updated;
|
int updated;
|
||||||
|
|
||||||
|
// object to synchronize fd registration changes
|
||||||
|
private final Object updateLock = new Object();
|
||||||
|
|
||||||
|
// number of file descriptors with registration changes pending
|
||||||
|
private int updateCount;
|
||||||
|
|
||||||
|
// file descriptors with registration changes pending
|
||||||
|
private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
|
||||||
|
|
||||||
|
// events for file descriptors with registration changes pending, indexed
|
||||||
|
// by file descriptor and stored as bytes for efficiency reasons.
|
||||||
|
private byte[] updateEvents = new byte[OPEN_MAX];
|
||||||
|
|
||||||
|
|
||||||
void initInterrupt(int fd0, int fd1) {
|
void initInterrupt(int fd0, int fd1) {
|
||||||
outgoingInterruptFD = fd1;
|
outgoingInterruptFD = fd1;
|
||||||
incomingInterruptFD = fd0;
|
incomingInterruptFD = fd0;
|
||||||
@ -149,14 +154,32 @@ class DevPollArrayWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setInterest(int fd, int mask) {
|
void setInterest(int fd, int mask) {
|
||||||
synchronized (updateList) {
|
synchronized (updateLock) {
|
||||||
updateList.add(new Updator(fd, mask));
|
// record the file descriptor and events, expanding the
|
||||||
|
// respective arrays first if necessary.
|
||||||
|
int oldCapacity = updateDescriptors.length;
|
||||||
|
if (updateCount >= oldCapacity) {
|
||||||
|
int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
|
||||||
|
int[] newDescriptors = new int[newCapacity];
|
||||||
|
System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
|
||||||
|
updateDescriptors = newDescriptors;
|
||||||
|
}
|
||||||
|
updateDescriptors[updateCount++] = fd;
|
||||||
|
|
||||||
|
// events are stored as bytes for efficiency reasons
|
||||||
|
byte b = (byte)mask;
|
||||||
|
assert (b == mask) && (b != CANCELLED);
|
||||||
|
updateEvents[fd] = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void release(int fd) {
|
void release(int fd) {
|
||||||
synchronized (updateList) {
|
synchronized (updateLock) {
|
||||||
updateList.add(new Updator(fd, POLLREMOVE));
|
// cancel any pending update for this file descriptor
|
||||||
|
updateEvents[fd] = CANCELLED;
|
||||||
|
|
||||||
|
// remove from /dev/poll
|
||||||
|
register(wfd, fd, POLLREMOVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,32 +204,37 @@ class DevPollArrayWrapper {
|
|||||||
|
|
||||||
void updateRegistrations() throws IOException {
|
void updateRegistrations() throws IOException {
|
||||||
// Populate pollfd array with updated masks
|
// Populate pollfd array with updated masks
|
||||||
synchronized (updateList) {
|
synchronized (updateLock) {
|
||||||
while (updateList.size() > 0) {
|
|
||||||
// We have to insert a dummy node in between each
|
|
||||||
// real update to use POLLREMOVE on the fd first because
|
|
||||||
// otherwise the changes are simply OR'd together
|
|
||||||
int index = 0;
|
|
||||||
Updator u = null;
|
|
||||||
while ((u = updateList.poll()) != null) {
|
|
||||||
// First add pollfd struct to clear out this fd
|
|
||||||
putPollFD(updatePollArray, index, u.fd, POLLREMOVE);
|
|
||||||
index++;
|
|
||||||
// Now add pollfd to update this fd, if necessary
|
|
||||||
if (u.mask != POLLREMOVE) {
|
|
||||||
putPollFD(updatePollArray, index, u.fd, (short)u.mask);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check against the max update size; these are
|
int j = 0;
|
||||||
// all we will process. Valid index ranges from 0 to
|
int index = 0;
|
||||||
// (MAX_UPDATE_SIZE - 1) and we can use up to 2 per loop
|
while (j < updateCount) {
|
||||||
if (index > MAX_UPDATE_SIZE - 2)
|
int fd = updateDescriptors[j];
|
||||||
break;
|
short events = updateEvents[fd];
|
||||||
|
|
||||||
|
// skip update if key has been cancelled
|
||||||
|
if (events != CANCELLED) {
|
||||||
|
// remove from /dev/poll when the interest ops changes to 0
|
||||||
|
if (events == 0)
|
||||||
|
events = POLLREMOVE;
|
||||||
|
|
||||||
|
// populate pollfd array with updated event
|
||||||
|
putPollFD(updatePollArray, index, fd, events);
|
||||||
|
index++;
|
||||||
|
if (index >= MAX_UPDATE_SIZE) {
|
||||||
|
registerMultiple(wfd, updatePollArray.address(), index);
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Register the changes with /dev/poll
|
j++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// write any remaining updates
|
||||||
|
if (index > 0)
|
||||||
registerMultiple(wfd, updatePollArray.address(), index);
|
registerMultiple(wfd, updatePollArray.address(), index);
|
||||||
}
|
|
||||||
|
updateCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,27 +118,20 @@ JNIEXPORT void JNICALL
|
|||||||
Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this,
|
Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this,
|
||||||
jint wfd, jint fd, jint mask)
|
jint wfd, jint fd, jint mask)
|
||||||
{
|
{
|
||||||
struct pollfd a[2];
|
struct pollfd a[1];
|
||||||
unsigned char *pollBytes = (unsigned char *)&a[0];
|
int n;
|
||||||
unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * 2;
|
|
||||||
|
|
||||||
/* We clear it first, otherwise any entries between poll invocations
|
|
||||||
get OR'd together */
|
|
||||||
a[0].fd = fd;
|
a[0].fd = fd;
|
||||||
a[0].events = POLLREMOVE;
|
a[0].events = mask;
|
||||||
a[0].revents = 0;
|
a[0].revents = 0;
|
||||||
|
|
||||||
a[1].fd = fd;
|
n = write(wfd, &a[0], sizeof(a));
|
||||||
a[1].events = mask;
|
if (n != sizeof(a)) {
|
||||||
a[1].revents = 0;
|
if (n < 0) {
|
||||||
|
|
||||||
while (pollBytes < pollEnd) {
|
|
||||||
int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes));
|
|
||||||
if (bytesWritten < 0) {
|
|
||||||
JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
|
JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
|
||||||
return;
|
} else {
|
||||||
|
JNU_ThrowIOException(env, "Unexpected number of bytes written");
|
||||||
}
|
}
|
||||||
pollBytes += bytesWritten;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user