mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
|
||||
/**
|
||||
* Creates this platform's default AsynchronousChannelProvider
|
||||
*/
|
||||
|
||||
public class DefaultAsynchronousChannelProvider {
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultAsynchronousChannelProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default AsynchronousChannelProvider.
|
||||
*/
|
||||
public static AsynchronousChannelProvider create() {
|
||||
return new SolarisAsynchronousChannelProvider();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new DevPollSelectorProvider();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.util.BitSet;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
|
||||
/**
|
||||
* Manipulates a native array of pollfd structs on Solaris:
|
||||
*
|
||||
* typedef struct pollfd {
|
||||
* int fd;
|
||||
* short events;
|
||||
* short revents;
|
||||
* } pollfd_t;
|
||||
*
|
||||
* @author Mike McCloskey
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
class DevPollArrayWrapper {
|
||||
|
||||
// Event masks
|
||||
static final short POLLIN = 0x0001;
|
||||
static final short POLLPRI = 0x0002;
|
||||
static final short POLLOUT = 0x0004;
|
||||
static final short POLLRDNORM = 0x0040;
|
||||
static final short POLLWRNORM = POLLOUT;
|
||||
static final short POLLRDBAND = 0x0080;
|
||||
static final short POLLWRBAND = 0x0100;
|
||||
static final short POLLNORM = POLLRDNORM;
|
||||
static final short POLLERR = 0x0008;
|
||||
static final short POLLHUP = 0x0010;
|
||||
static final short POLLNVAL = 0x0020;
|
||||
static final short POLLREMOVE = 0x0800;
|
||||
static final short POLLCONN = POLLOUT;
|
||||
|
||||
// Miscellaneous constants
|
||||
static final short SIZE_POLLFD = 8;
|
||||
static final short FD_OFFSET = 0;
|
||||
static final short EVENT_OFFSET = 4;
|
||||
static final short REVENT_OFFSET = 6;
|
||||
|
||||
// Special value to indicate that an update should be ignored
|
||||
static final byte IGNORE = (byte)-1;
|
||||
|
||||
// Maximum number of open file descriptors
|
||||
static final int OPEN_MAX = IOUtil.fdLimit();
|
||||
|
||||
// Number of pollfd structures to create.
|
||||
// dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-1
|
||||
static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);
|
||||
|
||||
// Initial size of arrays for fd registration changes
|
||||
private static final int INITIAL_PENDING_UPDATE_SIZE = 64;
|
||||
|
||||
// maximum size of updatesLow
|
||||
private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
|
||||
new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
|
||||
|
||||
// The pollfd array for results from devpoll driver
|
||||
private final AllocatedNativeObject pollArray;
|
||||
|
||||
// Base address of the native pollArray
|
||||
private final long pollArrayAddress;
|
||||
|
||||
// The fd of the devpoll driver
|
||||
private int wfd;
|
||||
|
||||
// The fd of the interrupt line going out
|
||||
private int outgoingInterruptFD;
|
||||
|
||||
// The fd of the interrupt line coming in
|
||||
private int incomingInterruptFD;
|
||||
|
||||
// The index of the interrupt FD
|
||||
private int interruptedIndex;
|
||||
|
||||
// Number of updated pollfd entries
|
||||
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. For
|
||||
// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
|
||||
// least then the update is stored in a map.
|
||||
private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
|
||||
private Map<Integer,Byte> eventsHigh;
|
||||
|
||||
// Used by release and updateRegistrations to track whether a file
|
||||
// descriptor is registered with /dev/poll.
|
||||
private final BitSet registered = new BitSet();
|
||||
|
||||
DevPollArrayWrapper() {
|
||||
int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
|
||||
pollArray = new AllocatedNativeObject(allocationSize, true);
|
||||
pollArrayAddress = pollArray.address();
|
||||
wfd = init();
|
||||
if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
|
||||
eventsHigh = new HashMap<>();
|
||||
}
|
||||
|
||||
void initInterrupt(int fd0, int fd1) {
|
||||
outgoingInterruptFD = fd1;
|
||||
incomingInterruptFD = fd0;
|
||||
register(wfd, fd0, POLLIN);
|
||||
}
|
||||
|
||||
void putReventOps(int i, int revent) {
|
||||
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
|
||||
pollArray.putShort(offset, (short)revent);
|
||||
}
|
||||
|
||||
int getEventOps(int i) {
|
||||
int offset = SIZE_POLLFD * i + EVENT_OFFSET;
|
||||
return pollArray.getShort(offset);
|
||||
}
|
||||
|
||||
int getReventOps(int i) {
|
||||
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
|
||||
return pollArray.getShort(offset);
|
||||
}
|
||||
|
||||
int getDescriptor(int i) {
|
||||
int offset = SIZE_POLLFD * i + FD_OFFSET;
|
||||
return pollArray.getInt(offset);
|
||||
}
|
||||
|
||||
private void setUpdateEvents(int fd, byte events) {
|
||||
if (fd < MAX_UPDATE_ARRAY_SIZE) {
|
||||
eventsLow[fd] = events;
|
||||
} else {
|
||||
eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
|
||||
}
|
||||
}
|
||||
|
||||
private byte getUpdateEvents(int fd) {
|
||||
if (fd < MAX_UPDATE_ARRAY_SIZE) {
|
||||
return eventsLow[fd];
|
||||
} else {
|
||||
Byte result = eventsHigh.get(Integer.valueOf(fd));
|
||||
// result should never be null
|
||||
return result.byteValue();
|
||||
}
|
||||
}
|
||||
|
||||
void setInterest(int fd, int mask) {
|
||||
synchronized (updateLock) {
|
||||
// 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 != IGNORE);
|
||||
setUpdateEvents(fd, b);
|
||||
}
|
||||
}
|
||||
|
||||
void release(int fd) {
|
||||
synchronized (updateLock) {
|
||||
// ignore any pending update for this file descriptor
|
||||
setUpdateEvents(fd, IGNORE);
|
||||
|
||||
// remove from /dev/poll
|
||||
if (registered.get(fd)) {
|
||||
register(wfd, fd, POLLREMOVE);
|
||||
registered.clear(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void closeDevPollFD() throws IOException {
|
||||
FileDispatcherImpl.closeIntFD(wfd);
|
||||
pollArray.free();
|
||||
}
|
||||
|
||||
int poll(long timeout) throws IOException {
|
||||
updateRegistrations();
|
||||
updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
|
||||
for (int i=0; i<updated; i++) {
|
||||
if (getDescriptor(i) == incomingInterruptFD) {
|
||||
interruptedIndex = i;
|
||||
interrupted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
void updateRegistrations() throws IOException {
|
||||
synchronized (updateLock) {
|
||||
// Populate pollfd array with updated masks
|
||||
int j = 0;
|
||||
int index = 0;
|
||||
while (j < updateCount) {
|
||||
int fd = updateDescriptors[j];
|
||||
short events = getUpdateEvents(fd);
|
||||
boolean wasRegistered = registered.get(fd);
|
||||
|
||||
// events = 0 => POLLREMOVE or do-nothing
|
||||
if (events != IGNORE) {
|
||||
if (events == 0) {
|
||||
if (wasRegistered) {
|
||||
events = POLLREMOVE;
|
||||
registered.clear(fd);
|
||||
} else {
|
||||
events = IGNORE;
|
||||
}
|
||||
} else {
|
||||
if (!wasRegistered) {
|
||||
registered.set(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate pollfd array with updated event
|
||||
if (events != IGNORE) {
|
||||
// insert POLLREMOVE if changing events
|
||||
if (wasRegistered && events != POLLREMOVE) {
|
||||
putPollFD(pollArray, index, fd, POLLREMOVE);
|
||||
index++;
|
||||
}
|
||||
putPollFD(pollArray, index, fd, events);
|
||||
index++;
|
||||
if (index >= (NUM_POLLFDS-1)) {
|
||||
registerMultiple(wfd, pollArray.address(), index);
|
||||
index = 0;
|
||||
}
|
||||
|
||||
// events for this fd now up to date
|
||||
setUpdateEvents(fd, IGNORE);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
// write any remaining updates
|
||||
if (index > 0)
|
||||
registerMultiple(wfd, pollArray.address(), index);
|
||||
|
||||
updateCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void putPollFD(AllocatedNativeObject array, int index, int fd,
|
||||
short event)
|
||||
{
|
||||
int structIndex = SIZE_POLLFD * index;
|
||||
array.putInt(structIndex + FD_OFFSET, fd);
|
||||
array.putShort(structIndex + EVENT_OFFSET, event);
|
||||
array.putShort(structIndex + REVENT_OFFSET, (short)0);
|
||||
}
|
||||
|
||||
boolean interrupted = false;
|
||||
|
||||
public void interrupt() {
|
||||
interrupt(outgoingInterruptFD);
|
||||
}
|
||||
|
||||
public int interruptedIndex() {
|
||||
return interruptedIndex;
|
||||
}
|
||||
|
||||
boolean interrupted() {
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
void clearInterrupted() {
|
||||
interrupted = false;
|
||||
}
|
||||
|
||||
private native int init();
|
||||
private native void register(int wfd, int fd, int mask);
|
||||
private native void registerMultiple(int wfd, long address, int len)
|
||||
throws IOException;
|
||||
private native int poll0(long pollAddress, int numfds, long timeout,
|
||||
int wfd);
|
||||
private static native void interrupt(int fd);
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of Selector for Solaris.
|
||||
*/
|
||||
class DevPollSelectorImpl
|
||||
extends SelectorImpl
|
||||
{
|
||||
|
||||
// File descriptors used for interrupt
|
||||
protected int fd0;
|
||||
protected int fd1;
|
||||
|
||||
// The poll object
|
||||
DevPollArrayWrapper pollWrapper;
|
||||
|
||||
// Maps from file descriptors to keys
|
||||
private Map<Integer,SelectionKeyImpl> fdToKey;
|
||||
|
||||
// True if this Selector has been closed
|
||||
private boolean closed = false;
|
||||
|
||||
// Lock for close/cleanup
|
||||
private Object closeLock = new Object();
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
private Object interruptLock = new Object();
|
||||
private boolean interruptTriggered = false;
|
||||
|
||||
/**
|
||||
* Package private constructor called by factory method in
|
||||
* the abstract superclass Selector.
|
||||
*/
|
||||
DevPollSelectorImpl(SelectorProvider sp) {
|
||||
super(sp);
|
||||
long pipeFds = IOUtil.makePipe(false);
|
||||
fd0 = (int) (pipeFds >>> 32);
|
||||
fd1 = (int) pipeFds;
|
||||
try {
|
||||
pollWrapper = new DevPollArrayWrapper();
|
||||
pollWrapper.initInterrupt(fd0, fd1);
|
||||
fdToKey = new HashMap<>();
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
} catch (IOException ioe0) {
|
||||
t.addSuppressed(ioe0);
|
||||
}
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
} catch (IOException ioe1) {
|
||||
t.addSuppressed(ioe1);
|
||||
}
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
protected int doSelect(long timeout)
|
||||
throws IOException
|
||||
{
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
processDeregisterQueue();
|
||||
try {
|
||||
begin();
|
||||
pollWrapper.poll(timeout);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
processDeregisterQueue();
|
||||
int numKeysUpdated = updateSelectedKeys();
|
||||
if (pollWrapper.interrupted()) {
|
||||
// Clear the wakeup pipe
|
||||
pollWrapper.putReventOps(pollWrapper.interruptedIndex(), 0);
|
||||
synchronized (interruptLock) {
|
||||
pollWrapper.clearInterrupted();
|
||||
IOUtil.drain(fd0);
|
||||
interruptTriggered = false;
|
||||
}
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the keys whose fd's have been selected by the devpoll
|
||||
* driver. Add the ready keys to the ready queue.
|
||||
*/
|
||||
private int updateSelectedKeys() {
|
||||
int entries = pollWrapper.updated;
|
||||
int numKeysUpdated = 0;
|
||||
for (int i=0; i<entries; i++) {
|
||||
int nextFD = pollWrapper.getDescriptor(i);
|
||||
SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
|
||||
// ski is null in the case of an interrupt
|
||||
if (ski != null) {
|
||||
int rOps = pollWrapper.getReventOps(i);
|
||||
if (selectedKeys.contains(ski)) {
|
||||
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
|
||||
numKeysUpdated++;
|
||||
}
|
||||
} else {
|
||||
ski.channel.translateAndSetReadyOps(rOps, ski);
|
||||
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
|
||||
selectedKeys.add(ski);
|
||||
numKeysUpdated++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
|
||||
pollWrapper.release(fd0);
|
||||
pollWrapper.closeDevPollFD();
|
||||
selectedKeys = null;
|
||||
|
||||
// Deregister channels
|
||||
Iterator<SelectionKey> i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
fd0 = -1;
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||
fdToKey.put(Integer.valueOf(fd), ski);
|
||||
keys.add(ski);
|
||||
}
|
||||
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
int i = ski.getIndex();
|
||||
assert (i >= 0);
|
||||
int fd = ski.channel.getFDVal();
|
||||
fdToKey.remove(Integer.valueOf(fd));
|
||||
pollWrapper.release(fd);
|
||||
ski.setIndex(-1);
|
||||
keys.remove(ski);
|
||||
selectedKeys.remove(ski);
|
||||
deregister((AbstractSelectionKey)ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
|
||||
public void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
int fd = IOUtil.fdVal(sk.channel.getFD());
|
||||
pollWrapper.setInterest(fd, ops);
|
||||
}
|
||||
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
pollWrapper.interrupt();
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
public class DevPollSelectorProvider
|
||||
extends SelectorProviderImpl
|
||||
{
|
||||
public AbstractSelector openSelector() throws IOException {
|
||||
return new DevPollSelectorImpl(this);
|
||||
}
|
||||
|
||||
public Channel inheritedChannel() throws IOException {
|
||||
return InheritedChannel.getChannel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Selector implementation based on the Solaris event port mechanism.
|
||||
*/
|
||||
|
||||
class EventPortSelectorImpl
|
||||
extends SelectorImpl
|
||||
{
|
||||
private final EventPortWrapper pollWrapper;
|
||||
|
||||
// Maps from file descriptors to keys
|
||||
private Map<Integer,SelectionKeyImpl> fdToKey;
|
||||
|
||||
// True if this Selector has been closed
|
||||
private boolean closed = false;
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
private final Object interruptLock = new Object();
|
||||
private boolean interruptTriggered = false;
|
||||
|
||||
/**
|
||||
* Package private constructor called by factory method in
|
||||
* the abstract superclass Selector.
|
||||
*/
|
||||
EventPortSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
pollWrapper = new EventPortWrapper();
|
||||
fdToKey = new HashMap<>();
|
||||
}
|
||||
|
||||
protected int doSelect(long timeout) throws IOException {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
processDeregisterQueue();
|
||||
int entries;
|
||||
try {
|
||||
begin();
|
||||
entries = pollWrapper.poll(timeout);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
processDeregisterQueue();
|
||||
int numKeysUpdated = updateSelectedKeys(entries);
|
||||
if (pollWrapper.interrupted()) {
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = false;
|
||||
}
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
private int updateSelectedKeys(int entries) {
|
||||
int numKeysUpdated = 0;
|
||||
for (int i=0; i<entries; i++) {
|
||||
int nextFD = pollWrapper.getDescriptor(i);
|
||||
SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
|
||||
if (ski != null) {
|
||||
int rOps = pollWrapper.getEventOps(i);
|
||||
if (selectedKeys.contains(ski)) {
|
||||
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
|
||||
numKeysUpdated++;
|
||||
}
|
||||
} else {
|
||||
ski.channel.translateAndSetReadyOps(rOps, ski);
|
||||
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
|
||||
selectedKeys.add(ski);
|
||||
numKeysUpdated++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
pollWrapper.close();
|
||||
selectedKeys = null;
|
||||
|
||||
// Deregister channels
|
||||
Iterator<SelectionKey> i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||
fdToKey.put(Integer.valueOf(fd), ski);
|
||||
keys.add(ski);
|
||||
}
|
||||
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
int i = ski.getIndex();
|
||||
assert (i >= 0);
|
||||
int fd = ski.channel.getFDVal();
|
||||
fdToKey.remove(Integer.valueOf(fd));
|
||||
pollWrapper.release(fd);
|
||||
ski.setIndex(-1);
|
||||
keys.remove(ski);
|
||||
selectedKeys.remove(ski);
|
||||
deregister((AbstractSelectionKey)ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
|
||||
public void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
int fd = sk.channel.getFDVal();
|
||||
pollWrapper.setInterest(fd, ops);
|
||||
}
|
||||
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
pollWrapper.interrupt();
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
public class EventPortSelectorProvider
|
||||
extends SelectorProviderImpl
|
||||
{
|
||||
public AbstractSelector openSelector() throws IOException {
|
||||
return new EventPortSelectorImpl(this);
|
||||
}
|
||||
|
||||
public Channel inheritedChannel() throws IOException {
|
||||
return InheritedChannel.getChannel();
|
||||
}
|
||||
}
|
262
src/java.base/solaris/classes/sun/nio/ch/EventPortWrapper.java
Normal file
262
src/java.base/solaris/classes/sun/nio/ch/EventPortWrapper.java
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
import static sun.nio.ch.SolarisEventPort.*;
|
||||
|
||||
/**
|
||||
* Manages a Solaris event port and manipulates a native array of pollfd structs
|
||||
* on Solaris.
|
||||
*/
|
||||
|
||||
class EventPortWrapper {
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final int addressSize = unsafe.addressSize();
|
||||
|
||||
// Maximum number of open file descriptors
|
||||
static final int OPEN_MAX = IOUtil.fdLimit();
|
||||
|
||||
// Maximum number of events to retrive in one call to port_getn
|
||||
static final int POLL_MAX = Math.min(OPEN_MAX-1, 1024);
|
||||
|
||||
// initial size of the array to hold pending updates
|
||||
private final int INITIAL_PENDING_UPDATE_SIZE = 256;
|
||||
|
||||
// maximum size of updateArray
|
||||
private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
|
||||
new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
|
||||
|
||||
// special update status to indicate that it should be ignored
|
||||
private static final byte IGNORE = -1;
|
||||
|
||||
// port file descriptor
|
||||
private final int pfd;
|
||||
|
||||
// the poll array (populated by port_getn)
|
||||
private final long pollArrayAddress;
|
||||
private final AllocatedNativeObject pollArray;
|
||||
|
||||
// required when accessing the update* fields
|
||||
private final Object updateLock = new Object();
|
||||
|
||||
// the number of pending updates
|
||||
private int updateCount;
|
||||
|
||||
// queue of file descriptors with updates 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. For
|
||||
// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
|
||||
// least then the update is stored in a map.
|
||||
private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
|
||||
private Map<Integer,Byte> eventsHigh;
|
||||
// Used by release and updateRegistrations to track whether a file
|
||||
// descriptor is registered with /dev/poll.
|
||||
private final BitSet registered = new BitSet();
|
||||
|
||||
// bit set to indicate if a file descriptor has been visited when
|
||||
// processing updates (used to avoid duplicates calls to port_associate)
|
||||
private BitSet visited = new BitSet();
|
||||
|
||||
EventPortWrapper() throws IOException {
|
||||
int allocationSize = POLL_MAX * SIZEOF_PORT_EVENT;
|
||||
pollArray = new AllocatedNativeObject(allocationSize, true);
|
||||
pollArrayAddress = pollArray.address();
|
||||
this.pfd = port_create();
|
||||
if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
|
||||
eventsHigh = new HashMap<>();
|
||||
}
|
||||
|
||||
void close() throws IOException {
|
||||
port_close(pfd);
|
||||
pollArray.free();
|
||||
}
|
||||
|
||||
private short getSource(int i) {
|
||||
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE;
|
||||
return pollArray.getShort(offset);
|
||||
}
|
||||
|
||||
int getEventOps(int i) {
|
||||
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS;
|
||||
return pollArray.getInt(offset);
|
||||
}
|
||||
|
||||
int getDescriptor(int i) {
|
||||
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
|
||||
if (addressSize == 4) {
|
||||
return pollArray.getInt(offset);
|
||||
} else {
|
||||
return (int) pollArray.getLong(offset);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDescriptor(int i, int fd) {
|
||||
int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
|
||||
if (addressSize == 4) {
|
||||
pollArray.putInt(offset, fd);
|
||||
} else {
|
||||
pollArray.putLong(offset, fd);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpdate(int fd, byte events) {
|
||||
if (fd < MAX_UPDATE_ARRAY_SIZE) {
|
||||
eventsLow[fd] = events;
|
||||
} else {
|
||||
eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
|
||||
}
|
||||
}
|
||||
|
||||
private byte getUpdate(int fd) {
|
||||
if (fd < MAX_UPDATE_ARRAY_SIZE) {
|
||||
return eventsLow[fd];
|
||||
} else {
|
||||
Byte result = eventsHigh.get(Integer.valueOf(fd));
|
||||
// result should never be null
|
||||
return result.byteValue();
|
||||
}
|
||||
}
|
||||
|
||||
int poll(long timeout) throws IOException {
|
||||
// update registrations prior to poll
|
||||
synchronized (updateLock) {
|
||||
|
||||
// process newest updates first
|
||||
int i = updateCount - 1;
|
||||
while (i >= 0) {
|
||||
int fd = updateDescriptors[i];
|
||||
if (!visited.get(fd)) {
|
||||
short ev = getUpdate(fd);
|
||||
if (ev != IGNORE) {
|
||||
if (ev == 0) {
|
||||
if (registered.get(fd)) {
|
||||
port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
|
||||
registered.clear(fd);
|
||||
}
|
||||
} else {
|
||||
if (port_associate(pfd, PORT_SOURCE_FD, (long)fd, ev)) {
|
||||
registered.set(fd);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
visited.set(fd);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
updateCount = 0;
|
||||
}
|
||||
|
||||
// poll for events
|
||||
int updated = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
|
||||
|
||||
// after polling we need to queue all polled file descriptors as they
|
||||
// are candidates to register for the next poll.
|
||||
synchronized (updateLock) {
|
||||
for (int i=0; i<updated; i++) {
|
||||
if (getSource(i) == PORT_SOURCE_USER) {
|
||||
interrupted = true;
|
||||
setDescriptor(i, -1);
|
||||
} else {
|
||||
// the default is to re-associate for the next poll
|
||||
int fd = getDescriptor(i);
|
||||
registered.clear(fd);
|
||||
setInterest(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
private void setInterest(int fd) {
|
||||
assert Thread.holdsLock(updateLock);
|
||||
|
||||
// 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;
|
||||
visited.clear(fd);
|
||||
}
|
||||
|
||||
void setInterest(int fd, int mask) {
|
||||
synchronized (updateLock) {
|
||||
setInterest(fd);
|
||||
setUpdate(fd, (byte)mask);
|
||||
assert getUpdate(fd) == mask;
|
||||
}
|
||||
}
|
||||
|
||||
void release(int fd) {
|
||||
synchronized (updateLock) {
|
||||
if (registered.get(fd)) {
|
||||
try {
|
||||
port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
registered.clear(fd);
|
||||
}
|
||||
setUpdate(fd, IGNORE);
|
||||
}
|
||||
}
|
||||
|
||||
// -- wakeup support --
|
||||
|
||||
private boolean interrupted;
|
||||
|
||||
public void interrupt() {
|
||||
try {
|
||||
port_send(pfd, 0);
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
boolean interrupted() {
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
void clearInterrupted() {
|
||||
interrupted = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SolarisAsynchronousChannelProvider
|
||||
extends AsynchronousChannelProvider
|
||||
{
|
||||
private static volatile SolarisEventPort defaultEventPort;
|
||||
|
||||
private SolarisEventPort defaultEventPort() throws IOException {
|
||||
if (defaultEventPort == null) {
|
||||
synchronized (SolarisAsynchronousChannelProvider.class) {
|
||||
if (defaultEventPort == null) {
|
||||
defaultEventPort =
|
||||
new SolarisEventPort(this, ThreadPool.getDefault()).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultEventPort;
|
||||
}
|
||||
|
||||
public SolarisAsynchronousChannelProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
|
||||
throws IOException
|
||||
{
|
||||
return new SolarisEventPort(this, ThreadPool.create(nThreads, factory)).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
|
||||
throws IOException
|
||||
{
|
||||
return new SolarisEventPort(this, ThreadPool.wrap(executor, initialSize)).start();
|
||||
}
|
||||
|
||||
private SolarisEventPort toEventPort(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
if (group == null) {
|
||||
return defaultEventPort();
|
||||
} else {
|
||||
if (!(group instanceof SolarisEventPort))
|
||||
throw new IllegalChannelGroupException();
|
||||
return (SolarisEventPort)group;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousServerSocketChannelImpl(toEventPort(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousSocketChannelImpl(toEventPort(group));
|
||||
}
|
||||
}
|
265
src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java
Normal file
265
src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java
Normal file
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.io.IOException;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Provides an AsynchronousChannelGroup implementation based on the Solaris 10
|
||||
* event port framework and also provides direct access to that framework.
|
||||
*/
|
||||
|
||||
class SolarisEventPort
|
||||
extends Port
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final int addressSize = unsafe.addressSize();
|
||||
|
||||
private static int dependsArch(int value32, int value64) {
|
||||
return (addressSize == 4) ? value32 : value64;
|
||||
}
|
||||
|
||||
/*
|
||||
* typedef struct port_event {
|
||||
* int portev_events;
|
||||
* ushort_t portev_source;
|
||||
* ushort_t portev_pad;
|
||||
* uintptr_t portev_object;
|
||||
* void *portev_user;
|
||||
* } port_event_t;
|
||||
*/
|
||||
static final int SIZEOF_PORT_EVENT = dependsArch(16, 24);
|
||||
static final int OFFSETOF_EVENTS = 0;
|
||||
static final int OFFSETOF_SOURCE = 4;
|
||||
static final int OFFSETOF_OBJECT = 8;
|
||||
|
||||
// port sources
|
||||
static final short PORT_SOURCE_USER = 3;
|
||||
static final short PORT_SOURCE_FD = 4;
|
||||
|
||||
// file descriptor to event port.
|
||||
private final int port;
|
||||
|
||||
// true when port is closed
|
||||
private boolean closed;
|
||||
|
||||
SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool)
|
||||
throws IOException
|
||||
{
|
||||
super(provider, pool);
|
||||
|
||||
// create event port
|
||||
this.port = port_create();
|
||||
}
|
||||
|
||||
SolarisEventPort start() {
|
||||
startThreads(new EventHandlerTask());
|
||||
return this;
|
||||
}
|
||||
|
||||
// releass resources
|
||||
private void implClose() {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
port_close(port);
|
||||
}
|
||||
|
||||
private void wakeup() {
|
||||
try {
|
||||
port_send(port, 0);
|
||||
} catch (IOException x) {
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void executeOnHandlerTask(Runnable task) {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
throw new RejectedExecutionException();
|
||||
offerTask(task);
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void shutdownHandlerTasks() {
|
||||
/*
|
||||
* If no tasks are running then just release resources; otherwise
|
||||
* write to the one end of the socketpair to wakeup any polling threads..
|
||||
*/
|
||||
int nThreads = threadCount();
|
||||
if (nThreads == 0) {
|
||||
implClose();
|
||||
} else {
|
||||
// send user event to wakeup each thread
|
||||
while (nThreads-- > 0) {
|
||||
try {
|
||||
port_send(port, 0);
|
||||
} catch (IOException x) {
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void startPoll(int fd, int events) {
|
||||
// (re-)associate file descriptor
|
||||
// no need to translate events
|
||||
try {
|
||||
port_associate(port, PORT_SOURCE_FD, fd, events);
|
||||
} catch (IOException x) {
|
||||
throw new AssertionError(); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Task to read a single event from the port and dispatch it to the
|
||||
* channel's onEvent handler.
|
||||
*/
|
||||
private class EventHandlerTask implements Runnable {
|
||||
public void run() {
|
||||
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
|
||||
Invoker.getGroupAndInvokeCount();
|
||||
final boolean isPooledThread = (myGroupAndInvokeCount != null);
|
||||
boolean replaceMe = false;
|
||||
long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT);
|
||||
try {
|
||||
for (;;) {
|
||||
// reset invoke count
|
||||
if (isPooledThread)
|
||||
myGroupAndInvokeCount.resetInvokeCount();
|
||||
|
||||
// wait for I/O completion event
|
||||
// A error here is fatal (thread will not be replaced)
|
||||
replaceMe = false;
|
||||
try {
|
||||
port_get(port, address);
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
// event source
|
||||
short source = unsafe.getShort(address + OFFSETOF_SOURCE);
|
||||
if (source != PORT_SOURCE_FD) {
|
||||
// user event is trigger to invoke task or shutdown
|
||||
if (source == PORT_SOURCE_USER) {
|
||||
Runnable task = pollTask();
|
||||
if (task == null) {
|
||||
// shutdown request
|
||||
return;
|
||||
}
|
||||
// run task (may throw error/exception)
|
||||
replaceMe = true;
|
||||
task.run();
|
||||
}
|
||||
// ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
// pe->portev_object is file descriptor
|
||||
int fd = (int)unsafe.getAddress(address + OFFSETOF_OBJECT);
|
||||
// pe->portev_events
|
||||
int events = unsafe.getInt(address + OFFSETOF_EVENTS);
|
||||
|
||||
// lookup channel
|
||||
PollableChannel ch;
|
||||
fdToChannelLock.readLock().lock();
|
||||
try {
|
||||
ch = fdToChannel.get(fd);
|
||||
} finally {
|
||||
fdToChannelLock.readLock().unlock();
|
||||
}
|
||||
|
||||
// notify channel
|
||||
if (ch != null) {
|
||||
replaceMe = true;
|
||||
// no need to translate events
|
||||
ch.onEvent(events, isPooledThread);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// free per-thread resources
|
||||
unsafe.freeMemory(address);
|
||||
// last task to exit when shutdown release resources
|
||||
int remaining = threadExit(this, replaceMe);
|
||||
if (remaining == 0 && isShutdown())
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event port
|
||||
*/
|
||||
static native int port_create() throws IOException;
|
||||
|
||||
/**
|
||||
* Associates specific events of a given object with a port
|
||||
*/
|
||||
static native boolean port_associate(int port, int source, long object, int events)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Removes the association of an object with a port.
|
||||
*/
|
||||
static native boolean port_dissociate(int port, int source, long object)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieves a single event from a port
|
||||
*/
|
||||
static native void port_get(int port, long pe) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieves at most {@code max} events from a port.
|
||||
*/
|
||||
static native int port_getn(int port, long address, int max, long timeout)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Sends a user-defined eventto a specified port.
|
||||
*/
|
||||
static native void port_send(int port, int events) throws IOException;
|
||||
|
||||
/**
|
||||
* Closes a port.
|
||||
*/
|
||||
static native void port_close(int port);
|
||||
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
|
||||
/**
|
||||
* Creates this platform's default FileSystemProvider.
|
||||
*/
|
||||
|
||||
public class DefaultFileSystemProvider {
|
||||
private DefaultFileSystemProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default FileSystemProvider.
|
||||
*/
|
||||
public static FileSystemProvider create() {
|
||||
return new SolarisFileSystemProvider();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
import static sun.nio.fs.SolarisConstants.*;
|
||||
import static sun.nio.fs.SolarisNativeDispatcher.*;
|
||||
|
||||
|
||||
/**
|
||||
* Solaris implementation of AclFileAttributeView with native support for
|
||||
* NFSv4 ACLs on ZFS.
|
||||
*/
|
||||
|
||||
class SolarisAclFileAttributeView
|
||||
extends AbstractAclFileAttributeView
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
// Maximum number of entries allowed in an ACL
|
||||
private static final int MAX_ACL_ENTRIES = 1024;
|
||||
|
||||
/**
|
||||
* typedef struct ace {
|
||||
* uid_t a_who;
|
||||
* uint32_t a_access_mask;
|
||||
* uint16_t a_flags;
|
||||
* uint16_t a_type;
|
||||
* } ace_t;
|
||||
*/
|
||||
private static final short SIZEOF_ACE_T = 12;
|
||||
private static final short OFFSETOF_UID = 0;
|
||||
private static final short OFFSETOF_MASK = 4;
|
||||
private static final short OFFSETOF_FLAGS = 8;
|
||||
private static final short OFFSETOF_TYPE = 10;
|
||||
|
||||
private final UnixPath file;
|
||||
private final boolean followLinks;
|
||||
|
||||
SolarisAclFileAttributeView(UnixPath file, boolean followLinks) {
|
||||
this.file = file;
|
||||
this.followLinks = followLinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permission checks to access file
|
||||
*/
|
||||
private void checkAccess(UnixPath file,
|
||||
boolean checkRead,
|
||||
boolean checkWrite)
|
||||
{
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
if (checkRead)
|
||||
file.checkRead();
|
||||
if (checkWrite)
|
||||
file.checkWrite();
|
||||
sm.checkPermission(new RuntimePermission("accessUserInformation"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the ACL to the given buffer
|
||||
*/
|
||||
private static void encode(List<AclEntry> acl, long address) {
|
||||
long offset = address;
|
||||
for (AclEntry ace: acl) {
|
||||
int flags = 0;
|
||||
|
||||
// map UserPrincipal to uid and flags
|
||||
UserPrincipal who = ace.principal();
|
||||
if (!(who instanceof UnixUserPrincipals.User))
|
||||
throw new ProviderMismatchException();
|
||||
UnixUserPrincipals.User user = (UnixUserPrincipals.User)who;
|
||||
int uid;
|
||||
if (user.isSpecial()) {
|
||||
uid = -1;
|
||||
if (who == UnixUserPrincipals.SPECIAL_OWNER)
|
||||
flags |= ACE_OWNER;
|
||||
else if (who == UnixUserPrincipals.SPECIAL_GROUP)
|
||||
flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP);
|
||||
else if (who == UnixUserPrincipals.SPECIAL_EVERYONE)
|
||||
flags |= ACE_EVERYONE;
|
||||
else
|
||||
throw new AssertionError("Unable to map special identifier");
|
||||
} else {
|
||||
if (user instanceof UnixUserPrincipals.Group) {
|
||||
uid = user.gid();
|
||||
flags |= ACE_IDENTIFIER_GROUP;
|
||||
} else {
|
||||
uid = user.uid();
|
||||
}
|
||||
}
|
||||
|
||||
// map ACE type
|
||||
int type;
|
||||
switch (ace.type()) {
|
||||
case ALLOW:
|
||||
type = ACE_ACCESS_ALLOWED_ACE_TYPE;
|
||||
break;
|
||||
case DENY:
|
||||
type = ACE_ACCESS_DENIED_ACE_TYPE;
|
||||
break;
|
||||
case AUDIT:
|
||||
type = ACE_SYSTEM_AUDIT_ACE_TYPE;
|
||||
break;
|
||||
case ALARM:
|
||||
type = ACE_SYSTEM_ALARM_ACE_TYPE;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unable to map ACE type");
|
||||
}
|
||||
|
||||
// map permissions
|
||||
Set<AclEntryPermission> aceMask = ace.permissions();
|
||||
int mask = 0;
|
||||
if (aceMask.contains(AclEntryPermission.READ_DATA))
|
||||
mask |= ACE_READ_DATA;
|
||||
if (aceMask.contains(AclEntryPermission.WRITE_DATA))
|
||||
mask |= ACE_WRITE_DATA;
|
||||
if (aceMask.contains(AclEntryPermission.APPEND_DATA))
|
||||
mask |= ACE_APPEND_DATA;
|
||||
if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))
|
||||
mask |= ACE_READ_NAMED_ATTRS;
|
||||
if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))
|
||||
mask |= ACE_WRITE_NAMED_ATTRS;
|
||||
if (aceMask.contains(AclEntryPermission.EXECUTE))
|
||||
mask |= ACE_EXECUTE;
|
||||
if (aceMask.contains(AclEntryPermission.DELETE_CHILD))
|
||||
mask |= ACE_DELETE_CHILD;
|
||||
if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))
|
||||
mask |= ACE_READ_ATTRIBUTES;
|
||||
if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))
|
||||
mask |= ACE_WRITE_ATTRIBUTES;
|
||||
if (aceMask.contains(AclEntryPermission.DELETE))
|
||||
mask |= ACE_DELETE;
|
||||
if (aceMask.contains(AclEntryPermission.READ_ACL))
|
||||
mask |= ACE_READ_ACL;
|
||||
if (aceMask.contains(AclEntryPermission.WRITE_ACL))
|
||||
mask |= ACE_WRITE_ACL;
|
||||
if (aceMask.contains(AclEntryPermission.WRITE_OWNER))
|
||||
mask |= ACE_WRITE_OWNER;
|
||||
if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))
|
||||
mask |= ACE_SYNCHRONIZE;
|
||||
|
||||
// FIXME - it would be desirable to know here if the file is a
|
||||
// directory or not. Solaris returns EINVAL if an ACE has a directory
|
||||
// -only flag and the file is not a directory.
|
||||
Set<AclEntryFlag> aceFlags = ace.flags();
|
||||
if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))
|
||||
flags |= ACE_FILE_INHERIT_ACE;
|
||||
if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))
|
||||
flags |= ACE_DIRECTORY_INHERIT_ACE;
|
||||
if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))
|
||||
flags |= ACE_NO_PROPAGATE_INHERIT_ACE;
|
||||
if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))
|
||||
flags |= ACE_INHERIT_ONLY_ACE;
|
||||
|
||||
unsafe.putInt(offset + OFFSETOF_UID, uid);
|
||||
unsafe.putInt(offset + OFFSETOF_MASK, mask);
|
||||
unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags);
|
||||
unsafe.putShort(offset + OFFSETOF_TYPE, (short)type);
|
||||
|
||||
offset += SIZEOF_ACE_T;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the buffer, returning an ACL
|
||||
*/
|
||||
private static List<AclEntry> decode(long address, int n) {
|
||||
ArrayList<AclEntry> acl = new ArrayList<>(n);
|
||||
for (int i=0; i<n; i++) {
|
||||
long offset = address + i*SIZEOF_ACE_T;
|
||||
|
||||
int uid = unsafe.getInt(offset + OFFSETOF_UID);
|
||||
int mask = unsafe.getInt(offset + OFFSETOF_MASK);
|
||||
int flags = (int)unsafe.getShort(offset + OFFSETOF_FLAGS);
|
||||
int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE);
|
||||
|
||||
// map uid and flags to UserPrincipal
|
||||
UnixUserPrincipals.User who = null;
|
||||
if ((flags & ACE_OWNER) > 0) {
|
||||
who = UnixUserPrincipals.SPECIAL_OWNER;
|
||||
} else if ((flags & ACE_GROUP) > 0) {
|
||||
who = UnixUserPrincipals.SPECIAL_GROUP;
|
||||
} else if ((flags & ACE_EVERYONE) > 0) {
|
||||
who = UnixUserPrincipals.SPECIAL_EVERYONE;
|
||||
} else if ((flags & ACE_IDENTIFIER_GROUP) > 0) {
|
||||
who = UnixUserPrincipals.fromGid(uid);
|
||||
} else {
|
||||
who = UnixUserPrincipals.fromUid(uid);
|
||||
}
|
||||
|
||||
AclEntryType aceType = null;
|
||||
switch (type) {
|
||||
case ACE_ACCESS_ALLOWED_ACE_TYPE:
|
||||
aceType = AclEntryType.ALLOW;
|
||||
break;
|
||||
case ACE_ACCESS_DENIED_ACE_TYPE:
|
||||
aceType = AclEntryType.DENY;
|
||||
break;
|
||||
case ACE_SYSTEM_AUDIT_ACE_TYPE:
|
||||
aceType = AclEntryType.AUDIT;
|
||||
break;
|
||||
case ACE_SYSTEM_ALARM_ACE_TYPE:
|
||||
aceType = AclEntryType.ALARM;
|
||||
break;
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
|
||||
Set<AclEntryPermission> aceMask = EnumSet.noneOf(AclEntryPermission.class);
|
||||
if ((mask & ACE_READ_DATA) > 0)
|
||||
aceMask.add(AclEntryPermission.READ_DATA);
|
||||
if ((mask & ACE_WRITE_DATA) > 0)
|
||||
aceMask.add(AclEntryPermission.WRITE_DATA);
|
||||
if ((mask & ACE_APPEND_DATA ) > 0)
|
||||
aceMask.add(AclEntryPermission.APPEND_DATA);
|
||||
if ((mask & ACE_READ_NAMED_ATTRS) > 0)
|
||||
aceMask.add(AclEntryPermission.READ_NAMED_ATTRS);
|
||||
if ((mask & ACE_WRITE_NAMED_ATTRS) > 0)
|
||||
aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS);
|
||||
if ((mask & ACE_EXECUTE) > 0)
|
||||
aceMask.add(AclEntryPermission.EXECUTE);
|
||||
if ((mask & ACE_DELETE_CHILD ) > 0)
|
||||
aceMask.add(AclEntryPermission.DELETE_CHILD);
|
||||
if ((mask & ACE_READ_ATTRIBUTES) > 0)
|
||||
aceMask.add(AclEntryPermission.READ_ATTRIBUTES);
|
||||
if ((mask & ACE_WRITE_ATTRIBUTES) > 0)
|
||||
aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES);
|
||||
if ((mask & ACE_DELETE) > 0)
|
||||
aceMask.add(AclEntryPermission.DELETE);
|
||||
if ((mask & ACE_READ_ACL) > 0)
|
||||
aceMask.add(AclEntryPermission.READ_ACL);
|
||||
if ((mask & ACE_WRITE_ACL) > 0)
|
||||
aceMask.add(AclEntryPermission.WRITE_ACL);
|
||||
if ((mask & ACE_WRITE_OWNER) > 0)
|
||||
aceMask.add(AclEntryPermission.WRITE_OWNER);
|
||||
if ((mask & ACE_SYNCHRONIZE) > 0)
|
||||
aceMask.add(AclEntryPermission.SYNCHRONIZE);
|
||||
|
||||
Set<AclEntryFlag> aceFlags = EnumSet.noneOf(AclEntryFlag.class);
|
||||
if ((flags & ACE_FILE_INHERIT_ACE) > 0)
|
||||
aceFlags.add(AclEntryFlag.FILE_INHERIT);
|
||||
if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0)
|
||||
aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT);
|
||||
if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0)
|
||||
aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
|
||||
if ((flags & ACE_INHERIT_ONLY_ACE) > 0)
|
||||
aceFlags.add(AclEntryFlag.INHERIT_ONLY);
|
||||
|
||||
// build the ACL entry and add it to the list
|
||||
AclEntry ace = AclEntry.newBuilder()
|
||||
.setType(aceType)
|
||||
.setPrincipal(who)
|
||||
.setPermissions(aceMask).setFlags(aceFlags).build();
|
||||
acl.add(ace);
|
||||
}
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
// Returns true if NFSv4 ACLs not enabled on file system
|
||||
private static boolean isAclsEnabled(int fd) {
|
||||
try {
|
||||
long enabled = fpathconf(fd, _PC_ACL_ENABLED);
|
||||
if (enabled == _ACL_ACE_ENABLED)
|
||||
return true;
|
||||
} catch (UnixException x) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AclEntry> getAcl()
|
||||
throws IOException
|
||||
{
|
||||
// permission check
|
||||
checkAccess(file, true, false);
|
||||
|
||||
// open file (will fail if file is a link and not following links)
|
||||
int fd = -1;
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
try {
|
||||
long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES);
|
||||
try {
|
||||
// read ACL and decode it
|
||||
int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address);
|
||||
assert n >= 0;
|
||||
return decode(address, n);
|
||||
} catch (UnixException x) {
|
||||
if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
|
||||
}
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
} finally {
|
||||
unsafe.freeMemory(address);
|
||||
}
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcl(List<AclEntry> acl) throws IOException {
|
||||
// permission check
|
||||
checkAccess(file, false, true);
|
||||
|
||||
// open file (will fail if file is a link and not following links)
|
||||
int fd = -1;
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
try {
|
||||
// SECURITY: need to copy list as can change during processing
|
||||
acl = new ArrayList<AclEntry>(acl);
|
||||
int n = acl.size();
|
||||
|
||||
long address = unsafe.allocateMemory(SIZEOF_ACE_T * n);
|
||||
try {
|
||||
encode(acl, address);
|
||||
facl(fd, ACE_SETACL, n, address);
|
||||
} catch (UnixException x) {
|
||||
if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
|
||||
}
|
||||
if (x.errno() == EINVAL && (n < 3))
|
||||
throw new IOException("ACL must contain at least 3 entries");
|
||||
x.rethrowAsIOException(file);
|
||||
} finally {
|
||||
unsafe.freeMemory(address);
|
||||
}
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserPrincipal getOwner()
|
||||
throws IOException
|
||||
{
|
||||
checkAccess(file, true, false);
|
||||
|
||||
try {
|
||||
UnixFileAttributes attrs =
|
||||
UnixFileAttributes.get(file, followLinks);
|
||||
return UnixUserPrincipals.fromUid(attrs.uid());
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compile happy
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(UserPrincipal owner) throws IOException {
|
||||
checkAccess(file, true, false);
|
||||
|
||||
if (!(owner instanceof UnixUserPrincipals.User))
|
||||
throw new ProviderMismatchException();
|
||||
if (owner instanceof UnixUserPrincipals.Group)
|
||||
throw new IOException("'owner' parameter is a group");
|
||||
int uid = ((UnixUserPrincipals.User)owner).uid();
|
||||
|
||||
try {
|
||||
if (followLinks) {
|
||||
lchown(file, uid, -1);
|
||||
} else {
|
||||
chown(file, uid, -1);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
@@END_COPYRIGHT@@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/acl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* On Solaris, "sun" is defined as a macro. Undefine to make package
|
||||
declaration valid */
|
||||
#undef sun
|
||||
|
||||
/* To be able to name the Java constants the same as the C constants without
|
||||
having the preprocessor rewrite those identifiers, add PREFIX_ to all
|
||||
identifiers matching a C constant. The PREFIX_ is filtered out in the
|
||||
makefile. */
|
||||
|
||||
@@START_HERE@@
|
||||
|
||||
package sun.nio.fs;
|
||||
class SolarisConstants {
|
||||
|
||||
private SolarisConstants() { }
|
||||
|
||||
static final int PREFIX_O_XATTR = O_XATTR;
|
||||
static final int PREFIX__PC_XATTR_ENABLED = _PC_XATTR_ENABLED;
|
||||
static final int PREFIX__PC_ACL_ENABLED = _PC_ACL_ENABLED;
|
||||
static final int PREFIX__ACL_ACE_ENABLED = _ACL_ACE_ENABLED;
|
||||
static final int PREFIX_ACE_GETACL = ACE_GETACL;
|
||||
static final int PREFIX_ACE_SETACL = ACE_SETACL;
|
||||
static final int PREFIX_ACE_ACCESS_ALLOWED_ACE_TYPE = ACE_ACCESS_ALLOWED_ACE_TYPE;
|
||||
static final int PREFIX_ACE_ACCESS_DENIED_ACE_TYPE = ACE_ACCESS_DENIED_ACE_TYPE;
|
||||
static final int PREFIX_ACE_SYSTEM_AUDIT_ACE_TYPE = ACE_SYSTEM_AUDIT_ACE_TYPE;
|
||||
static final int PREFIX_ACE_SYSTEM_ALARM_ACE_TYPE = ACE_SYSTEM_ALARM_ACE_TYPE;
|
||||
static final int PREFIX_ACE_READ_DATA = ACE_READ_DATA;
|
||||
static final int PREFIX_ACE_LIST_DIRECTORY = ACE_LIST_DIRECTORY;
|
||||
static final int PREFIX_ACE_WRITE_DATA = ACE_WRITE_DATA;
|
||||
static final int PREFIX_ACE_ADD_FILE = ACE_ADD_FILE;
|
||||
static final int PREFIX_ACE_APPEND_DATA = ACE_APPEND_DATA;
|
||||
static final int PREFIX_ACE_ADD_SUBDIRECTORY = ACE_ADD_SUBDIRECTORY;
|
||||
static final int PREFIX_ACE_READ_NAMED_ATTRS = ACE_READ_NAMED_ATTRS;
|
||||
static final int PREFIX_ACE_WRITE_NAMED_ATTRS = ACE_WRITE_NAMED_ATTRS;
|
||||
static final int PREFIX_ACE_EXECUTE = ACE_EXECUTE;
|
||||
static final int PREFIX_ACE_DELETE_CHILD = ACE_DELETE_CHILD;
|
||||
static final int PREFIX_ACE_READ_ATTRIBUTES = ACE_READ_ATTRIBUTES;
|
||||
static final int PREFIX_ACE_WRITE_ATTRIBUTES = ACE_WRITE_ATTRIBUTES;
|
||||
static final int PREFIX_ACE_DELETE = ACE_DELETE;
|
||||
static final int PREFIX_ACE_READ_ACL = ACE_READ_ACL;
|
||||
static final int PREFIX_ACE_WRITE_ACL = ACE_WRITE_ACL;
|
||||
static final int PREFIX_ACE_WRITE_OWNER = ACE_WRITE_OWNER;
|
||||
static final int PREFIX_ACE_SYNCHRONIZE = ACE_SYNCHRONIZE;
|
||||
static final int PREFIX_ACE_FILE_INHERIT_ACE = ACE_FILE_INHERIT_ACE;
|
||||
static final int PREFIX_ACE_DIRECTORY_INHERIT_ACE = ACE_DIRECTORY_INHERIT_ACE;
|
||||
static final int PREFIX_ACE_NO_PROPAGATE_INHERIT_ACE = ACE_NO_PROPAGATE_INHERIT_ACE;
|
||||
static final int PREFIX_ACE_INHERIT_ONLY_ACE = ACE_INHERIT_ONLY_ACE;
|
||||
static final int PREFIX_ACE_SUCCESSFUL_ACCESS_ACE_FLAG = ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
|
||||
static final int PREFIX_ACE_FAILED_ACCESS_ACE_FLAG = ACE_FAILED_ACCESS_ACE_FLAG;
|
||||
static final int PREFIX_ACE_IDENTIFIER_GROUP = ACE_IDENTIFIER_GROUP;
|
||||
static final int PREFIX_ACE_OWNER = ACE_OWNER;
|
||||
static final int PREFIX_ACE_GROUP = ACE_GROUP;
|
||||
static final int PREFIX_ACE_EVERYONE = ACE_EVERYONE;
|
||||
}
|
111
src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java
Normal file
111
src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.attribute.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.SolarisConstants.*;
|
||||
|
||||
/**
|
||||
* Solaris implementation of FileStore
|
||||
*/
|
||||
|
||||
class SolarisFileStore
|
||||
extends UnixFileStore
|
||||
{
|
||||
private final boolean xattrEnabled;
|
||||
|
||||
SolarisFileStore(UnixPath file) throws IOException {
|
||||
super(file);
|
||||
this.xattrEnabled = xattrEnabled();
|
||||
}
|
||||
|
||||
SolarisFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
|
||||
super(fs, entry);
|
||||
this.xattrEnabled = xattrEnabled();
|
||||
}
|
||||
|
||||
// returns true if extended attributes enabled
|
||||
private boolean xattrEnabled() {
|
||||
long res = 0L;
|
||||
try {
|
||||
res = pathconf(file(), _PC_XATTR_ENABLED);
|
||||
} catch (UnixException x) {
|
||||
// ignore
|
||||
}
|
||||
return (res != 0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
UnixMountEntry findMountEntry() throws IOException {
|
||||
// On Solaris iterate over the entries in the mount table to find device
|
||||
for (UnixMountEntry entry: file().getFileSystem().getMountEntries()) {
|
||||
if (entry.dev() == dev()) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
throw new IOException("Device not found in mnttab");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||
if (type == AclFileAttributeView.class) {
|
||||
// lookup fstypes.properties
|
||||
FeatureStatus status = checkIfFeaturePresent("nfsv4acl");
|
||||
switch (status) {
|
||||
case PRESENT : return true;
|
||||
case NOT_PRESENT : return false;
|
||||
default :
|
||||
// AclFileAttributeView available on ZFS
|
||||
return (type().equals("zfs"));
|
||||
}
|
||||
}
|
||||
if (type == UserDefinedFileAttributeView.class) {
|
||||
// lookup fstypes.properties
|
||||
FeatureStatus status = checkIfFeaturePresent("xattr");
|
||||
switch (status) {
|
||||
case PRESENT : return true;
|
||||
case NOT_PRESENT : return false;
|
||||
default :
|
||||
// UserDefinedFileAttributeView available if extended
|
||||
// attributes supported
|
||||
return xattrEnabled;
|
||||
}
|
||||
}
|
||||
return super.supportsFileAttributeView(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(String name) {
|
||||
if (name.equals("acl"))
|
||||
return supportsFileAttributeView(AclFileAttributeView.class);
|
||||
if (name.equals("user"))
|
||||
return supportsFileAttributeView(UserDefinedFileAttributeView.class);
|
||||
return super.supportsFileAttributeView(name);
|
||||
}
|
||||
}
|
127
src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java
Normal file
127
src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import static sun.nio.fs.SolarisNativeDispatcher.*;
|
||||
|
||||
/**
|
||||
* Solaris implementation of FileSystem
|
||||
*/
|
||||
|
||||
class SolarisFileSystem extends UnixFileSystem {
|
||||
private final boolean hasSolaris11Features;
|
||||
|
||||
SolarisFileSystem(UnixFileSystemProvider provider, String dir) {
|
||||
super(provider, dir);
|
||||
|
||||
// check os.version
|
||||
String osversion = GetPropertyAction.privilegedGetProperty("os.version");
|
||||
String[] vers = Util.split(osversion, '.');
|
||||
assert vers.length >= 2;
|
||||
int majorVersion = Integer.parseInt(vers[0]);
|
||||
int minorVersion = Integer.parseInt(vers[1]);
|
||||
this.hasSolaris11Features =
|
||||
(majorVersion > 5 || (majorVersion == 5 && minorVersion >= 11));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isSolaris() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchService newWatchService()
|
||||
throws IOException
|
||||
{
|
||||
// FEN available since Solaris 11
|
||||
if (hasSolaris11Features) {
|
||||
return new SolarisWatchService(this);
|
||||
} else {
|
||||
return new PollingWatchService();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// lazy initialization of the list of supported attribute views
|
||||
private static class SupportedFileFileAttributeViewsHolder {
|
||||
static final Set<String> supportedFileAttributeViews =
|
||||
supportedFileAttributeViews();
|
||||
private static Set<String> supportedFileAttributeViews() {
|
||||
Set<String> result = new HashSet<>();
|
||||
result.addAll(standardFileAttributeViews());
|
||||
// additional Solaris-specific views
|
||||
result.add("acl");
|
||||
result.add("user");
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedFileAttributeViews() {
|
||||
return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
|
||||
}
|
||||
|
||||
@Override
|
||||
void copyNonPosixAttributes(int ofd, int nfd) {
|
||||
SolarisUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
|
||||
// TDB: copy ACL from source to target
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object to iterate over entries in /etc/mnttab
|
||||
*/
|
||||
@Override
|
||||
Iterable<UnixMountEntry> getMountEntries() {
|
||||
ArrayList<UnixMountEntry> entries = new ArrayList<>();
|
||||
try {
|
||||
UnixPath mnttab = new UnixPath(this, "/etc/mnttab");
|
||||
long fp = fopen(mnttab, "r");
|
||||
try {
|
||||
for (;;) {
|
||||
UnixMountEntry entry = new UnixMountEntry();
|
||||
int res = getextmntent(fp, entry);
|
||||
if (res < 0)
|
||||
break;
|
||||
entries.add(entry);
|
||||
}
|
||||
} finally {
|
||||
fclose(fp);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// nothing we can do
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
FileStore getFileStore(UnixMountEntry entry) throws IOException {
|
||||
return new SolarisFileStore(this, entry);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.file.spi.FileTypeDetector;
|
||||
import java.io.IOException;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* Solaris implementation of FileSystemProvider
|
||||
*/
|
||||
|
||||
public class SolarisFileSystemProvider extends UnixFileSystemProvider {
|
||||
public SolarisFileSystemProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
SolarisFileSystem newFileSystem(String dir) {
|
||||
return new SolarisFileSystem(this, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
SolarisFileStore getFileStore(UnixPath path) throws IOException {
|
||||
return new SolarisFileStore(path);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
|
||||
Class<V> type,
|
||||
LinkOption... options)
|
||||
{
|
||||
if (type == AclFileAttributeView.class) {
|
||||
return (V) new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj),
|
||||
Util.followLinks(options));
|
||||
}
|
||||
if (type == UserDefinedFileAttributeView.class) {
|
||||
return(V) new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj),
|
||||
Util.followLinks(options));
|
||||
}
|
||||
return super.getFileAttributeView(obj, type, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicFileAttributeView getFileAttributeView(Path obj,
|
||||
String name,
|
||||
LinkOption... options)
|
||||
{
|
||||
if (name.equals("acl"))
|
||||
return new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj),
|
||||
Util.followLinks(options));
|
||||
if (name.equals("user"))
|
||||
return new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj),
|
||||
Util.followLinks(options));
|
||||
return super.getFileAttributeView(obj, name, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
FileTypeDetector getFileTypeDetector() {
|
||||
Path userMimeTypes = Paths.get(
|
||||
GetPropertyAction.privilegedGetProperty("user.home"), ".mime.types");
|
||||
Path etcMimeTypes = Paths.get("/etc/mime.types");
|
||||
|
||||
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
|
||||
new MimeTypesFileTypeDetector(etcMimeTypes));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Solaris specific system calls.
|
||||
*/
|
||||
|
||||
class SolarisNativeDispatcher extends UnixNativeDispatcher {
|
||||
private SolarisNativeDispatcher() { }
|
||||
|
||||
/**
|
||||
* int getextmntent(FILE *fp, struct extmnttab *mp, int len);
|
||||
*/
|
||||
static native int getextmntent(long fp, UnixMountEntry entry)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* int facl(int filedes, int cmd, int nentries, void aclbufp)
|
||||
*/
|
||||
static native int facl(int fd, int cmd, int nentries, long aclbufp)
|
||||
throws UnixException;
|
||||
|
||||
|
||||
// initialize
|
||||
private static native void init();
|
||||
|
||||
static {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("nio");
|
||||
return null;
|
||||
}});
|
||||
init();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
import static sun.nio.fs.SolarisConstants.*;
|
||||
|
||||
/**
|
||||
* Solaris emulation of NamedAttributeView using extended attributes.
|
||||
*/
|
||||
|
||||
class SolarisUserDefinedFileAttributeView
|
||||
extends AbstractUserDefinedFileAttributeView
|
||||
{
|
||||
private static final byte[] HERE = { '.' };
|
||||
|
||||
private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
|
||||
byte[] bytes = Util.toBytes(name);
|
||||
// "", "." and ".." not allowed
|
||||
if (bytes.length == 0 || bytes[0] == '.') {
|
||||
if (bytes.length <= 1 ||
|
||||
(bytes.length == 2 && bytes[1] == '.'))
|
||||
{
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, "'" + name + "' is not a valid name");
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private final UnixPath file;
|
||||
private final boolean followLinks;
|
||||
|
||||
SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
|
||||
this.file = file;
|
||||
this.followLinks = followLinks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> list() throws IOException {
|
||||
if (System.getSecurityManager() != null)
|
||||
checkAccess(file.getPathForPermissionCheck(), true, false);
|
||||
|
||||
int fd = -1;
|
||||
try {
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
|
||||
// open extended attribute directory
|
||||
int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0);
|
||||
long dp;
|
||||
try {
|
||||
dp = fdopendir(dfd);
|
||||
} catch (UnixException x) {
|
||||
close(dfd);
|
||||
throw x;
|
||||
}
|
||||
|
||||
// read list of extended attributes
|
||||
List<String> list = new ArrayList<>();
|
||||
try {
|
||||
byte[] name;
|
||||
while ((name = readdir(dp)) != null) {
|
||||
String s = Util.toString(name);
|
||||
if (!s.equals(".") && !s.equals(".."))
|
||||
list.add(s);
|
||||
}
|
||||
} finally {
|
||||
closedir(dp);
|
||||
}
|
||||
return Collections.unmodifiableList(list);
|
||||
} catch (UnixException x) {
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, "Unable to get list of extended attributes: " +
|
||||
x.getMessage());
|
||||
}
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size(String name) throws IOException {
|
||||
if (System.getSecurityManager() != null)
|
||||
checkAccess(file.getPathForPermissionCheck(), true, false);
|
||||
|
||||
int fd = -1;
|
||||
try {
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
|
||||
// open attribute file
|
||||
int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
|
||||
try {
|
||||
// read attribute's attributes
|
||||
UnixFileAttributes attrs = UnixFileAttributes.get(afd);
|
||||
long size = attrs.size();
|
||||
if (size > Integer.MAX_VALUE)
|
||||
throw new ArithmeticException("Extended attribute value too large");
|
||||
return (int)size;
|
||||
} finally {
|
||||
close(afd);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, "Unable to get size of extended attribute '" + name +
|
||||
"': " + x.getMessage());
|
||||
}
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(String name, ByteBuffer dst) throws IOException {
|
||||
if (System.getSecurityManager() != null)
|
||||
checkAccess(file.getPathForPermissionCheck(), true, false);
|
||||
|
||||
int fd = -1;
|
||||
try {
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
|
||||
// open attribute file
|
||||
int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
|
||||
|
||||
// wrap with channel
|
||||
FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), true, false);
|
||||
|
||||
// read to EOF (nothing we can do if I/O error occurs)
|
||||
try {
|
||||
if (fc.size() > dst.remaining())
|
||||
throw new IOException("Extended attribute file too large");
|
||||
int total = 0;
|
||||
while (dst.hasRemaining()) {
|
||||
int n = fc.read(dst);
|
||||
if (n < 0)
|
||||
break;
|
||||
total += n;
|
||||
}
|
||||
return total;
|
||||
} finally {
|
||||
fc.close();
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, "Unable to read extended attribute '" + name +
|
||||
"': " + x.getMessage());
|
||||
}
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(String name, ByteBuffer src) throws IOException {
|
||||
if (System.getSecurityManager() != null)
|
||||
checkAccess(file.getPathForPermissionCheck(), false, true);
|
||||
|
||||
int fd = -1;
|
||||
try {
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
|
||||
// open/create attribute file
|
||||
int afd = openat(fd, nameAsBytes(file,name),
|
||||
(O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
|
||||
UnixFileModeAttribute.ALL_PERMISSIONS);
|
||||
|
||||
// wrap with channel
|
||||
FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), false, true);
|
||||
|
||||
// write value (nothing we can do if I/O error occurs)
|
||||
try {
|
||||
int rem = src.remaining();
|
||||
while (src.hasRemaining()) {
|
||||
fc.write(src);
|
||||
}
|
||||
return rem;
|
||||
} finally {
|
||||
fc.close();
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, "Unable to write extended attribute '" + name +
|
||||
"': " + x.getMessage());
|
||||
}
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String name) throws IOException {
|
||||
if (System.getSecurityManager() != null)
|
||||
checkAccess(file.getPathForPermissionCheck(), false, true);
|
||||
|
||||
int fd = -1;
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
|
||||
int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0);
|
||||
try {
|
||||
unlinkat(dfd, nameAsBytes(file,name), 0);
|
||||
} finally {
|
||||
close(dfd);
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
throw new FileSystemException(file.getPathForExceptionMessage(),
|
||||
null, "Unable to delete extended attribute '" + name +
|
||||
"': " + x.getMessage());
|
||||
} finally {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by copyTo/moveTo to copy extended attributes from source to target.
|
||||
*
|
||||
* @param ofd
|
||||
* file descriptor for source file
|
||||
* @param nfd
|
||||
* file descriptor for target file
|
||||
*/
|
||||
static void copyExtendedAttributes(int ofd, int nfd) {
|
||||
try {
|
||||
// open extended attribute directory
|
||||
int dfd = openat(ofd, HERE, (O_RDONLY|O_XATTR), 0);
|
||||
long dp = 0L;
|
||||
try {
|
||||
dp = fdopendir(dfd);
|
||||
} catch (UnixException x) {
|
||||
close(dfd);
|
||||
throw x;
|
||||
}
|
||||
|
||||
// copy each extended attribute
|
||||
try {
|
||||
byte[] name;
|
||||
while ((name = readdir(dp)) != null) {
|
||||
// ignore "." and ".."
|
||||
if (name[0] == '.') {
|
||||
if (name.length == 1)
|
||||
continue;
|
||||
if (name.length == 2 && name[1] == '.')
|
||||
continue;
|
||||
}
|
||||
copyExtendedAttribute(ofd, name, nfd);
|
||||
}
|
||||
} finally {
|
||||
closedir(dp);
|
||||
}
|
||||
} catch (UnixException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyExtendedAttribute(int ofd, byte[] name, int nfd)
|
||||
throws UnixException
|
||||
{
|
||||
// open source attribute file
|
||||
int src = openat(ofd, name, (O_RDONLY|O_XATTR), 0);
|
||||
try {
|
||||
// create target attribute file
|
||||
int dst = openat(nfd, name, (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
|
||||
UnixFileModeAttribute.ALL_PERMISSIONS);
|
||||
try {
|
||||
UnixCopyFile.transfer(dst, src, 0L);
|
||||
} finally {
|
||||
close(dst);
|
||||
}
|
||||
} finally {
|
||||
close(src);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,827 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Solaris implementation of WatchService based on file events notification
|
||||
* facility.
|
||||
*/
|
||||
|
||||
class SolarisWatchService
|
||||
extends AbstractWatchService
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static int addressSize = unsafe.addressSize();
|
||||
|
||||
private static int dependsArch(int value32, int value64) {
|
||||
return (addressSize == 4) ? value32 : value64;
|
||||
}
|
||||
|
||||
/*
|
||||
* typedef struct port_event {
|
||||
* int portev_events;
|
||||
* ushort_t portev_source;
|
||||
* ushort_t portev_pad;
|
||||
* uintptr_t portev_object;
|
||||
* void *portev_user;
|
||||
* } port_event_t;
|
||||
*/
|
||||
private static final int SIZEOF_PORT_EVENT = dependsArch(16, 24);
|
||||
private static final int OFFSETOF_EVENTS = 0;
|
||||
private static final int OFFSETOF_SOURCE = 4;
|
||||
private static final int OFFSETOF_OBJECT = 8;
|
||||
|
||||
/*
|
||||
* typedef struct file_obj {
|
||||
* timestruc_t fo_atime;
|
||||
* timestruc_t fo_mtime;
|
||||
* timestruc_t fo_ctime;
|
||||
* uintptr_t fo_pad[3];
|
||||
* char *fo_name;
|
||||
* } file_obj_t;
|
||||
*/
|
||||
private static final int SIZEOF_FILEOBJ = dependsArch(40, 80);
|
||||
private static final int OFFSET_FO_NAME = dependsArch(36, 72);
|
||||
|
||||
// port sources
|
||||
private static final short PORT_SOURCE_USER = 3;
|
||||
private static final short PORT_SOURCE_FILE = 7;
|
||||
|
||||
// user-watchable events
|
||||
private static final int FILE_MODIFIED = 0x00000002;
|
||||
private static final int FILE_ATTRIB = 0x00000004;
|
||||
private static final int FILE_NOFOLLOW = 0x10000000;
|
||||
|
||||
// exception events
|
||||
private static final int FILE_DELETE = 0x00000010;
|
||||
private static final int FILE_RENAME_TO = 0x00000020;
|
||||
private static final int FILE_RENAME_FROM = 0x00000040;
|
||||
private static final int UNMOUNTED = 0x20000000;
|
||||
private static final int MOUNTEDOVER = 0x40000000;
|
||||
|
||||
// background thread to read change events
|
||||
private final Poller poller;
|
||||
|
||||
SolarisWatchService(UnixFileSystem fs) throws IOException {
|
||||
int port = -1;
|
||||
try {
|
||||
port = portCreate();
|
||||
} catch (UnixException x) {
|
||||
throw new IOException(x.errorString());
|
||||
}
|
||||
|
||||
this.poller = new Poller(fs, this, port);
|
||||
this.poller.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
WatchKey register(Path dir,
|
||||
WatchEvent.Kind<?>[] events,
|
||||
WatchEvent.Modifier... modifiers)
|
||||
throws IOException
|
||||
{
|
||||
// delegate to poller
|
||||
return poller.register(dir, events, modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
void implClose() throws IOException {
|
||||
// delegate to poller
|
||||
poller.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* WatchKey implementation
|
||||
*/
|
||||
private class SolarisWatchKey extends AbstractWatchKey
|
||||
implements DirectoryNode
|
||||
{
|
||||
private final UnixFileKey fileKey;
|
||||
|
||||
// pointer to native file_obj object
|
||||
private final long object;
|
||||
|
||||
// events (may be changed). set to null when watch key is invalid
|
||||
private volatile Set<? extends WatchEvent.Kind<?>> events;
|
||||
|
||||
// map of entries in directory; created lazily; accessed only by
|
||||
// poller thread.
|
||||
private Map<Path,EntryNode> children = new HashMap<>();
|
||||
|
||||
SolarisWatchKey(SolarisWatchService watcher,
|
||||
UnixPath dir,
|
||||
UnixFileKey fileKey,
|
||||
long object,
|
||||
Set<? extends WatchEvent.Kind<?>> events)
|
||||
{
|
||||
super(dir, watcher);
|
||||
this.fileKey = fileKey;
|
||||
this.object = object;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
UnixPath getDirectory() {
|
||||
return (UnixPath)watchable();
|
||||
}
|
||||
|
||||
UnixFileKey getFileKey() {
|
||||
return fileKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long object() {
|
||||
return object;
|
||||
}
|
||||
|
||||
void invalidate() {
|
||||
events = null;
|
||||
}
|
||||
|
||||
Set<? extends WatchEvent.Kind<?>> events() {
|
||||
return events;
|
||||
}
|
||||
|
||||
void setEvents(Set<? extends WatchEvent.Kind<?>> events) {
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
Map<Path,EntryNode> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return events != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (isValid()) {
|
||||
// delegate to poller
|
||||
poller.cancel(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(Path name, EntryNode node) {
|
||||
children.put(name, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(Path name) {
|
||||
children.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryNode getChild(Path name) {
|
||||
return children.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Background thread to read from port
|
||||
*/
|
||||
private class Poller extends AbstractPoller {
|
||||
|
||||
// maximum number of events to read per call to port_getn
|
||||
private static final int MAX_EVENT_COUNT = 128;
|
||||
|
||||
// events that map to ENTRY_DELETE
|
||||
private static final int FILE_REMOVED =
|
||||
(FILE_DELETE|FILE_RENAME_TO|FILE_RENAME_FROM);
|
||||
|
||||
// events that tell us not to re-associate the object
|
||||
private static final int FILE_EXCEPTION =
|
||||
(FILE_REMOVED|UNMOUNTED|MOUNTEDOVER);
|
||||
|
||||
// address of event buffers (used to receive events with port_getn)
|
||||
private final long bufferAddress;
|
||||
|
||||
private final SolarisWatchService watcher;
|
||||
|
||||
// the I/O port
|
||||
private final int port;
|
||||
|
||||
// maps file key (dev/inode) to WatchKey
|
||||
private final Map<UnixFileKey,SolarisWatchKey> fileKey2WatchKey;
|
||||
|
||||
// maps file_obj object to Node
|
||||
private final Map<Long,Node> object2Node;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*/
|
||||
Poller(UnixFileSystem fs, SolarisWatchService watcher, int port) {
|
||||
this.watcher = watcher;
|
||||
this.port = port;
|
||||
this.bufferAddress =
|
||||
unsafe.allocateMemory(SIZEOF_PORT_EVENT * MAX_EVENT_COUNT);
|
||||
this.fileKey2WatchKey = new HashMap<UnixFileKey,SolarisWatchKey>();
|
||||
this.object2Node = new HashMap<Long,Node>();
|
||||
}
|
||||
|
||||
@Override
|
||||
void wakeup() throws IOException {
|
||||
// write to port to wakeup polling thread
|
||||
try {
|
||||
portSend(port, 0);
|
||||
} catch (UnixException x) {
|
||||
throw new IOException(x.errorString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object implRegister(Path obj,
|
||||
Set<? extends WatchEvent.Kind<?>> events,
|
||||
WatchEvent.Modifier... modifiers)
|
||||
{
|
||||
// no modifiers supported at this time
|
||||
if (modifiers.length > 0) {
|
||||
for (WatchEvent.Modifier modifier: modifiers) {
|
||||
if (modifier == null)
|
||||
return new NullPointerException();
|
||||
if (!ExtendedOptions.SENSITIVITY_HIGH.matches(modifier) &&
|
||||
!ExtendedOptions.SENSITIVITY_MEDIUM.matches(modifier) &&
|
||||
!ExtendedOptions.SENSITIVITY_LOW.matches(modifier)) {
|
||||
return new UnsupportedOperationException("Modifier not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnixPath dir = (UnixPath)obj;
|
||||
|
||||
// check file is directory
|
||||
UnixFileAttributes attrs = null;
|
||||
try {
|
||||
attrs = UnixFileAttributes.get(dir, true);
|
||||
} catch (UnixException x) {
|
||||
return x.asIOException(dir);
|
||||
}
|
||||
if (!attrs.isDirectory()) {
|
||||
return new NotDirectoryException(dir.getPathForExceptionMessage());
|
||||
}
|
||||
|
||||
// if already registered then update the events and return existing key
|
||||
UnixFileKey fileKey = attrs.fileKey();
|
||||
SolarisWatchKey watchKey = fileKey2WatchKey.get(fileKey);
|
||||
if (watchKey != null) {
|
||||
try {
|
||||
updateEvents(watchKey, events);
|
||||
} catch (UnixException x) {
|
||||
return x.asIOException(dir);
|
||||
}
|
||||
return watchKey;
|
||||
}
|
||||
|
||||
// register directory
|
||||
long object = 0L;
|
||||
try {
|
||||
object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB));
|
||||
} catch (UnixException x) {
|
||||
return x.asIOException(dir);
|
||||
}
|
||||
|
||||
// create watch key and insert it into maps
|
||||
watchKey = new SolarisWatchKey(watcher, dir, fileKey, object, events);
|
||||
object2Node.put(object, watchKey);
|
||||
fileKey2WatchKey.put(fileKey, watchKey);
|
||||
|
||||
// register all entries in directory
|
||||
registerChildren(dir, watchKey, false, false);
|
||||
|
||||
return watchKey;
|
||||
}
|
||||
|
||||
// release resources for single entry
|
||||
void releaseChild(EntryNode node) {
|
||||
long object = node.object();
|
||||
if (object != 0L) {
|
||||
object2Node.remove(object);
|
||||
releaseObject(object, true);
|
||||
node.setObject(0L);
|
||||
}
|
||||
}
|
||||
|
||||
// release resources for entries in directory
|
||||
void releaseChildren(SolarisWatchKey key) {
|
||||
for (EntryNode node: key.children().values()) {
|
||||
releaseChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
// cancel single key
|
||||
@Override
|
||||
void implCancelKey(WatchKey obj) {
|
||||
SolarisWatchKey key = (SolarisWatchKey)obj;
|
||||
if (key.isValid()) {
|
||||
fileKey2WatchKey.remove(key.getFileKey());
|
||||
|
||||
// release resources for entries
|
||||
releaseChildren(key);
|
||||
|
||||
// release resources for directory
|
||||
long object = key.object();
|
||||
object2Node.remove(object);
|
||||
releaseObject(object, true);
|
||||
|
||||
// and finally invalidate the key
|
||||
key.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// close watch service
|
||||
@Override
|
||||
void implCloseAll() {
|
||||
// release all native resources
|
||||
for (Long object: object2Node.keySet()) {
|
||||
releaseObject(object, true);
|
||||
}
|
||||
|
||||
// invalidate all keys
|
||||
for (Map.Entry<UnixFileKey,SolarisWatchKey> entry: fileKey2WatchKey.entrySet()) {
|
||||
entry.getValue().invalidate();
|
||||
}
|
||||
|
||||
// clean-up
|
||||
object2Node.clear();
|
||||
fileKey2WatchKey.clear();
|
||||
|
||||
// free global resources
|
||||
unsafe.freeMemory(bufferAddress);
|
||||
UnixNativeDispatcher.close(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Poller main loop. Blocks on port_getn waiting for events and then
|
||||
* processes them.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (;;) {
|
||||
int n = portGetn(port, bufferAddress, MAX_EVENT_COUNT);
|
||||
assert n > 0;
|
||||
|
||||
long address = bufferAddress;
|
||||
for (int i=0; i<n; i++) {
|
||||
boolean shutdown = processEvent(address);
|
||||
if (shutdown)
|
||||
return;
|
||||
address += SIZEOF_PORT_EVENT;
|
||||
}
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single port_event
|
||||
*
|
||||
* Returns true if poller thread is requested to shutdown.
|
||||
*/
|
||||
boolean processEvent(long address) {
|
||||
// pe->portev_source
|
||||
short source = unsafe.getShort(address + OFFSETOF_SOURCE);
|
||||
// pe->portev_object
|
||||
long object = unsafe.getAddress(address + OFFSETOF_OBJECT);
|
||||
// pe->portev_events
|
||||
int events = unsafe.getInt(address + OFFSETOF_EVENTS);
|
||||
|
||||
// user event is trigger to process pending requests
|
||||
if (source != PORT_SOURCE_FILE) {
|
||||
if (source == PORT_SOURCE_USER) {
|
||||
// process any pending requests
|
||||
boolean shutdown = processRequests();
|
||||
if (shutdown)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// lookup object to get Node
|
||||
Node node = object2Node.get(object);
|
||||
if (node == null) {
|
||||
// should not happen
|
||||
return false;
|
||||
}
|
||||
|
||||
// As a workaround for 6642290 and 6636438/6636412 we don't use
|
||||
// FILE_EXCEPTION events to tell use not to register the file.
|
||||
// boolean reregister = (events & FILE_EXCEPTION) == 0;
|
||||
boolean reregister = true;
|
||||
|
||||
// If node is EntryNode then event relates to entry in directory
|
||||
// If node is a SolarisWatchKey (DirectoryNode) then event relates
|
||||
// to a watched directory.
|
||||
boolean isDirectory = (node instanceof SolarisWatchKey);
|
||||
if (isDirectory) {
|
||||
processDirectoryEvents((SolarisWatchKey)node, events);
|
||||
} else {
|
||||
boolean ignore = processEntryEvents((EntryNode)node, events);
|
||||
if (ignore)
|
||||
reregister = false;
|
||||
}
|
||||
|
||||
// need to re-associate to get further events
|
||||
if (reregister) {
|
||||
try {
|
||||
events = FILE_MODIFIED | FILE_ATTRIB;
|
||||
if (!isDirectory) events |= FILE_NOFOLLOW;
|
||||
portAssociate(port,
|
||||
PORT_SOURCE_FILE,
|
||||
object,
|
||||
events);
|
||||
} catch (UnixException x) {
|
||||
// unable to re-register
|
||||
reregister = false;
|
||||
}
|
||||
}
|
||||
|
||||
// object is not re-registered so release resources. If
|
||||
// object is a watched directory then signal key
|
||||
if (!reregister) {
|
||||
// release resources
|
||||
object2Node.remove(object);
|
||||
releaseObject(object, false);
|
||||
|
||||
// if watch key then signal it
|
||||
if (isDirectory) {
|
||||
SolarisWatchKey key = (SolarisWatchKey)node;
|
||||
fileKey2WatchKey.remove( key.getFileKey() );
|
||||
key.invalidate();
|
||||
key.signal();
|
||||
} else {
|
||||
// if entry then remove it from parent
|
||||
EntryNode entry = (EntryNode)node;
|
||||
SolarisWatchKey key = (SolarisWatchKey)entry.parent();
|
||||
key.removeChild(entry.name());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process directory events. If directory is modified then re-scan
|
||||
* directory to register any new entries
|
||||
*/
|
||||
void processDirectoryEvents(SolarisWatchKey key, int mask) {
|
||||
if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) {
|
||||
registerChildren(key.getDirectory(), key,
|
||||
key.events().contains(StandardWatchEventKinds.ENTRY_CREATE),
|
||||
key.events().contains(StandardWatchEventKinds.ENTRY_DELETE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process events for entries in registered directories. Returns {@code
|
||||
* true} if events are ignored because the watch key has been cancelled.
|
||||
*/
|
||||
boolean processEntryEvents(EntryNode node, int mask) {
|
||||
SolarisWatchKey key = (SolarisWatchKey)node.parent();
|
||||
Set<? extends WatchEvent.Kind<?>> events = key.events();
|
||||
if (events == null) {
|
||||
// key has been cancelled so ignore event
|
||||
return true;
|
||||
}
|
||||
|
||||
// entry modified
|
||||
if (((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) &&
|
||||
events.contains(StandardWatchEventKinds.ENTRY_MODIFY))
|
||||
{
|
||||
key.signalEvent(StandardWatchEventKinds.ENTRY_MODIFY, node.name());
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all entries in the given directory
|
||||
*
|
||||
* The {@code sendCreateEvents} and {@code sendDeleteEvents} parameters
|
||||
* indicates if ENTRY_CREATE and ENTRY_DELETE events should be queued
|
||||
* when new entries are found. When initially registering a directory
|
||||
* they will always be false. When re-scanning a directory then it
|
||||
* depends on if the events are enabled or not.
|
||||
*/
|
||||
void registerChildren(UnixPath dir,
|
||||
SolarisWatchKey parent,
|
||||
boolean sendCreateEvents,
|
||||
boolean sendDeleteEvents)
|
||||
{
|
||||
boolean isModifyEnabled =
|
||||
parent.events().contains(StandardWatchEventKinds.ENTRY_MODIFY) ;
|
||||
|
||||
// reset visited flag on entries so that we can detect file deletes
|
||||
for (EntryNode node: parent.children().values()) {
|
||||
node.setVisited(false);
|
||||
}
|
||||
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
|
||||
for (Path entry: stream) {
|
||||
Path name = entry.getFileName();
|
||||
|
||||
// skip entry if already registered
|
||||
EntryNode node = parent.getChild(name);
|
||||
if (node != null) {
|
||||
node.setVisited(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// new entry found
|
||||
|
||||
long object = 0L;
|
||||
int errno = 0;
|
||||
boolean addNode = false;
|
||||
|
||||
// if ENTRY_MODIFY enabled then we register the entry for events
|
||||
if (isModifyEnabled) {
|
||||
try {
|
||||
UnixPath path = (UnixPath)entry;
|
||||
int events = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
|
||||
object = registerImpl(path, events);
|
||||
addNode = true;
|
||||
} catch (UnixException x) {
|
||||
errno = x.errno();
|
||||
}
|
||||
} else {
|
||||
addNode = true;
|
||||
}
|
||||
|
||||
if (addNode) {
|
||||
// create node
|
||||
node = new EntryNode(object, (UnixPath)entry.getFileName(), parent);
|
||||
node.setVisited(true);
|
||||
// tell the parent about it
|
||||
parent.addChild(entry.getFileName(), node);
|
||||
if (object != 0L)
|
||||
object2Node.put(object, node);
|
||||
}
|
||||
|
||||
// send ENTRY_CREATE event for the new file
|
||||
// send ENTRY_DELETE event for files that were deleted immediately
|
||||
boolean deleted = (errno == ENOENT);
|
||||
if (sendCreateEvents && (addNode || deleted))
|
||||
parent.signalEvent(StandardWatchEventKinds.ENTRY_CREATE, name);
|
||||
if (sendDeleteEvents && deleted)
|
||||
parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, name);
|
||||
|
||||
}
|
||||
} catch (DirectoryIteratorException | IOException x) {
|
||||
// queue OVERFLOW event so that user knows to re-scan directory
|
||||
parent.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// clean-up and send ENTRY_DELETE events for any entries that were
|
||||
// not found
|
||||
Iterator<Map.Entry<Path,EntryNode>> iterator =
|
||||
parent.children().entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Path,EntryNode> entry = iterator.next();
|
||||
EntryNode node = entry.getValue();
|
||||
if (!node.isVisited()) {
|
||||
long object = node.object();
|
||||
if (object != 0L) {
|
||||
object2Node.remove(object);
|
||||
releaseObject(object, true);
|
||||
}
|
||||
if (sendDeleteEvents)
|
||||
parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, node.name());
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update watch key's events. If ENTRY_MODIFY changes to be enabled
|
||||
* then register each file in the directory; If ENTRY_MODIFY changed to
|
||||
* be disabled then unregister each file.
|
||||
*/
|
||||
void updateEvents(SolarisWatchKey key, Set<? extends WatchEvent.Kind<?>> events)
|
||||
throws UnixException
|
||||
{
|
||||
|
||||
// update events, remembering if ENTRY_MODIFY was previously
|
||||
// enabled or disabled.
|
||||
boolean oldModifyEnabled = key.events()
|
||||
.contains(StandardWatchEventKinds.ENTRY_MODIFY);
|
||||
key.setEvents(events);
|
||||
|
||||
// check if ENTRY_MODIFY has changed
|
||||
boolean newModifyEnabled = events
|
||||
.contains(StandardWatchEventKinds.ENTRY_MODIFY);
|
||||
if (newModifyEnabled != oldModifyEnabled) {
|
||||
UnixException ex = null;
|
||||
for (EntryNode node: key.children().values()) {
|
||||
if (newModifyEnabled) {
|
||||
// register
|
||||
UnixPath path = key.getDirectory().resolve(node.name());
|
||||
int ev = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
|
||||
try {
|
||||
long object = registerImpl(path, ev);
|
||||
object2Node.put(object, node);
|
||||
node.setObject(object);
|
||||
} catch (UnixException x) {
|
||||
// if file has been deleted then it will be detected
|
||||
// as a FILE_MODIFIED event on the directory
|
||||
if (x.errno() != ENOENT) {
|
||||
ex = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// unregister
|
||||
releaseChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
// an error occurred
|
||||
if (ex != null) {
|
||||
releaseChildren(key);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls port_associate to register the given path.
|
||||
* Returns pointer to fileobj structure that is allocated for
|
||||
* the registration.
|
||||
*/
|
||||
long registerImpl(UnixPath dir, int events)
|
||||
throws UnixException
|
||||
{
|
||||
// allocate memory for the path (file_obj->fo_name field)
|
||||
byte[] path = dir.getByteArrayForSysCalls();
|
||||
int len = path.length;
|
||||
long name = unsafe.allocateMemory(len+1);
|
||||
unsafe.copyMemory(path, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,
|
||||
name, (long)len);
|
||||
unsafe.putByte(name + len, (byte)0);
|
||||
|
||||
// allocate memory for filedatanode structure - this is the object
|
||||
// to port_associate
|
||||
long object = unsafe.allocateMemory(SIZEOF_FILEOBJ);
|
||||
unsafe.setMemory(null, object, SIZEOF_FILEOBJ, (byte)0);
|
||||
unsafe.putAddress(object + OFFSET_FO_NAME, name);
|
||||
|
||||
// associate the object with the port
|
||||
try {
|
||||
portAssociate(port,
|
||||
PORT_SOURCE_FILE,
|
||||
object,
|
||||
events);
|
||||
} catch (UnixException x) {
|
||||
// debugging
|
||||
if (x.errno() == EAGAIN) {
|
||||
System.err.println("The maximum number of objects associated "+
|
||||
"with the port has been reached");
|
||||
}
|
||||
|
||||
unsafe.freeMemory(name);
|
||||
unsafe.freeMemory(object);
|
||||
throw x;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all resources for an file_obj object; optionally remove
|
||||
* association from port
|
||||
*/
|
||||
void releaseObject(long object, boolean dissociate) {
|
||||
// remove association
|
||||
if (dissociate) {
|
||||
try {
|
||||
portDissociate(port, PORT_SOURCE_FILE, object);
|
||||
} catch (UnixException x) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// free native memory
|
||||
long name = unsafe.getAddress(object + OFFSET_FO_NAME);
|
||||
unsafe.freeMemory(name);
|
||||
unsafe.freeMemory(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node with native (file_obj) resources
|
||||
*/
|
||||
private static interface Node {
|
||||
long object();
|
||||
}
|
||||
|
||||
/**
|
||||
* A directory node with a map of the entries in the directory
|
||||
*/
|
||||
private static interface DirectoryNode extends Node {
|
||||
void addChild(Path name, EntryNode node);
|
||||
void removeChild(Path name);
|
||||
EntryNode getChild(Path name);
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a node that is an entry in a directory.
|
||||
*/
|
||||
private static class EntryNode implements Node {
|
||||
private long object;
|
||||
private final UnixPath name;
|
||||
private final DirectoryNode parent;
|
||||
private boolean visited;
|
||||
|
||||
EntryNode(long object, UnixPath name, DirectoryNode parent) {
|
||||
this.object = object;
|
||||
this.name = name;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long object() {
|
||||
return object;
|
||||
}
|
||||
|
||||
void setObject(long ptr) {
|
||||
this.object = ptr;
|
||||
}
|
||||
|
||||
UnixPath name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
DirectoryNode parent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
boolean isVisited() {
|
||||
return visited;
|
||||
}
|
||||
|
||||
void setVisited(boolean v) {
|
||||
this.visited = v;
|
||||
}
|
||||
}
|
||||
|
||||
// -- native methods --
|
||||
|
||||
private static native void init();
|
||||
|
||||
private static native int portCreate() throws UnixException;
|
||||
|
||||
private static native void portAssociate(int port, int source, long object, int events)
|
||||
throws UnixException;
|
||||
|
||||
private static native void portDissociate(int port, int source, long object)
|
||||
throws UnixException;
|
||||
|
||||
private static native void portSend(int port, int events)
|
||||
throws UnixException;
|
||||
|
||||
private static native int portGetn(int port, long address, int max)
|
||||
throws UnixException;
|
||||
|
||||
static {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("nio");
|
||||
return null;
|
||||
}});
|
||||
init();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue