undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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 jdk.internal.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
class ClassLoaderHelper {
|
||||
|
||||
private ClassLoaderHelper() {}
|
||||
|
||||
/**
|
||||
* Shared objects may be loaded from .a archive object on AIX and .so may not exist.
|
||||
* This method returns false so that loading of shared library continues if
|
||||
* libname.so is not present.
|
||||
*/
|
||||
static boolean loadLibraryOnlyIfPresent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* AIX implementation of JVM_LoadLibrary handles the alternate path name mapping.
|
||||
* If loading of the given library name with ".so" suffix fails, it will attempt
|
||||
* to load the library of the same name with ".a" suffix as the alternate name.
|
||||
* This method simply returns null. It could implement the alternate name
|
||||
* converting ".so" with ".a" suffix but redundant.
|
||||
*/
|
||||
static File mapAlternativeName(File lib) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a PATH env variable.
|
||||
*
|
||||
* Empty elements will be replaced by dot.
|
||||
*/
|
||||
static String[] parsePath(String ldPath) {
|
||||
char ps = File.pathSeparatorChar;
|
||||
ArrayList<String> paths = new ArrayList<>();
|
||||
int pathStart = 0;
|
||||
int pathEnd;
|
||||
while ((pathEnd = ldPath.indexOf(ps, pathStart)) >= 0) {
|
||||
paths.add((pathStart < pathEnd) ?
|
||||
ldPath.substring(pathStart, pathEnd) : ".");
|
||||
pathStart = pathEnd + 1;
|
||||
}
|
||||
int ldLen = ldPath.length();
|
||||
paths.add((pathStart < ldLen) ?
|
||||
ldPath.substring(pathStart, ldLen) : ".");
|
||||
return paths.toArray(new String[paths.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 SAP SE. 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 AixAsynchronousChannelProvider
|
||||
extends AsynchronousChannelProvider
|
||||
{
|
||||
private static volatile AixPollPort defaultPort;
|
||||
|
||||
private AixPollPort defaultEventPort() throws IOException {
|
||||
if (defaultPort == null) {
|
||||
synchronized (AixAsynchronousChannelProvider.class) {
|
||||
if (defaultPort == null) {
|
||||
defaultPort = new AixPollPort(this, ThreadPool.getDefault()).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
public AixAsynchronousChannelProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
|
||||
throws IOException
|
||||
{
|
||||
return new AixPollPort(this, ThreadPool.create(nThreads, factory)).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
|
||||
throws IOException
|
||||
{
|
||||
return new AixPollPort(this, ThreadPool.wrap(executor, initialSize)).start();
|
||||
}
|
||||
|
||||
private Port toPort(AsynchronousChannelGroup group) throws IOException {
|
||||
if (group == null) {
|
||||
return defaultEventPort();
|
||||
} else {
|
||||
if (!(group instanceof AixPollPort))
|
||||
throw new IllegalChannelGroupException();
|
||||
return (Port)group;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousServerSocketChannelImpl(toPort(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousSocketChannelImpl(toPort(group));
|
||||
}
|
||||
}
|
||||
459
src/java.base/aix/classes/sun/nio/ch/AixPollPort.java
Normal file
459
src/java.base/aix/classes/sun/nio/ch/AixPollPort.java
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2024 SAP SE. 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.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import sun.nio.ch.IOUtil;
|
||||
import sun.nio.ch.Pollset;
|
||||
|
||||
/**
|
||||
* AsynchronousChannelGroup implementation based on the AIX pollset framework.
|
||||
*/
|
||||
final class AixPollPort
|
||||
extends Port
|
||||
{
|
||||
static {
|
||||
IOUtil.load();
|
||||
Pollset.init();
|
||||
}
|
||||
|
||||
// pollset ID
|
||||
private final int pollset;
|
||||
|
||||
// true if port is closed
|
||||
private boolean closed;
|
||||
|
||||
// socket pair used for wakeup
|
||||
private final int sp[];
|
||||
|
||||
// socket pair used to indicate pending pollsetCtl calls
|
||||
// Background info: pollsetCtl blocks when another thread is in a pollsetPoll call.
|
||||
private final int ctlSp[];
|
||||
|
||||
// number of wakeups pending
|
||||
private final AtomicInteger wakeupCount = new AtomicInteger();
|
||||
|
||||
// address of the poll array passed to pollset_poll
|
||||
private final long address;
|
||||
|
||||
// maximum number of events to poll at a time
|
||||
private static final int MAX_EVENTS_TO_POLL = 512;
|
||||
|
||||
// encapsulates an event for a channel
|
||||
static class Event {
|
||||
final PollableChannel channel;
|
||||
final int events;
|
||||
|
||||
Event(PollableChannel channel, int events) {
|
||||
this.channel = channel;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
PollableChannel channel() { return channel; }
|
||||
int events() { return events; }
|
||||
}
|
||||
|
||||
// queue of events for cases that a polling thread dequeues more than one
|
||||
// event
|
||||
private final ArrayBlockingQueue<Event> queue;
|
||||
private final Event NEED_TO_POLL = new Event(null, 0);
|
||||
private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
|
||||
private final Event CONTINUE_AFTER_CTL_EVENT = new Event(null, 0);
|
||||
|
||||
// encapsulates a pollset control event for a file descriptor
|
||||
static class ControlEvent {
|
||||
final int fd;
|
||||
final int events;
|
||||
final boolean removeOnly;
|
||||
int error = 0;
|
||||
|
||||
ControlEvent(int fd, int events, boolean removeOnly) {
|
||||
this.fd = fd;
|
||||
this.events = events;
|
||||
this.removeOnly = removeOnly;
|
||||
}
|
||||
|
||||
int fd() { return fd; }
|
||||
int events() { return events; }
|
||||
boolean removeOnly() { return removeOnly; }
|
||||
int error() { return error; }
|
||||
void setError(int error) { this.error = error; }
|
||||
}
|
||||
|
||||
// queue of control events that need to be processed
|
||||
// (this object is also used for synchronization)
|
||||
private final HashSet<ControlEvent> controlQueue = new HashSet<ControlEvent>();
|
||||
|
||||
// lock used to check whether a poll operation is ongoing
|
||||
private final ReentrantLock controlLock = new ReentrantLock();
|
||||
|
||||
AixPollPort(AsynchronousChannelProvider provider, ThreadPool pool)
|
||||
throws IOException
|
||||
{
|
||||
super(provider, pool);
|
||||
|
||||
// open pollset
|
||||
this.pollset = Pollset.pollsetCreate();
|
||||
|
||||
// create socket pair for wakeup mechanism
|
||||
int[] sv = new int[2];
|
||||
try {
|
||||
Pollset.socketpair(sv);
|
||||
// register one end with pollset
|
||||
Pollset.pollsetCtl(pollset, Pollset.PS_ADD, sv[0], Net.POLLIN);
|
||||
} catch (IOException x) {
|
||||
Pollset.pollsetDestroy(pollset);
|
||||
throw x;
|
||||
}
|
||||
this.sp = sv;
|
||||
|
||||
// create socket pair for pollset control mechanism
|
||||
sv = new int[2];
|
||||
try {
|
||||
Pollset.socketpair(sv);
|
||||
// make the reading part of the socket nonblocking, so the drain (drain_all) method works
|
||||
IOUtil.configureBlocking(IOUtil.newFD(sv[0]), false);
|
||||
// register one end with pollset
|
||||
Pollset.pollsetCtl(pollset, Pollset.PS_ADD, sv[0], Net.POLLIN);
|
||||
} catch (IOException x) {
|
||||
Pollset.pollsetDestroy(pollset);
|
||||
throw x;
|
||||
}
|
||||
this.ctlSp = sv;
|
||||
|
||||
// allocate the poll array
|
||||
this.address = Pollset.allocatePollArray(MAX_EVENTS_TO_POLL);
|
||||
|
||||
// create the queue and offer the special event to ensure that the first
|
||||
// threads polls
|
||||
this.queue = new ArrayBlockingQueue<Event>(MAX_EVENTS_TO_POLL);
|
||||
this.queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
|
||||
AixPollPort start() {
|
||||
startThreads(new EventHandlerTask());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources
|
||||
*/
|
||||
private void implClose() {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
Pollset.freePollArray(address);
|
||||
Pollset.close0(sp[0]);
|
||||
Pollset.close0(sp[1]);
|
||||
Pollset.close0(ctlSp[0]);
|
||||
Pollset.close0(ctlSp[1]);
|
||||
Pollset.pollsetDestroy(pollset);
|
||||
}
|
||||
|
||||
void wakeup() {
|
||||
if (wakeupCount.incrementAndGet() == 1) {
|
||||
// write byte to socketpair to force wakeup
|
||||
try {
|
||||
Pollset.interrupt(sp[1]);
|
||||
} 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 interrupt to each thread
|
||||
while (nThreads-- > 0) {
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invoke by clients to register a file descriptor
|
||||
@Override
|
||||
void startPoll(int fd, int events) {
|
||||
queueControlEvent(new ControlEvent(fd, events, false));
|
||||
}
|
||||
|
||||
// Callback method for implementations that need special handling when fd is removed
|
||||
@Override
|
||||
protected void preUnregister(int fd) {
|
||||
queueControlEvent(new ControlEvent(fd, 0, true));
|
||||
}
|
||||
|
||||
// Add control event into queue and wait for completion.
|
||||
// In case the control lock is free, this method also tries to apply the control change directly.
|
||||
private void queueControlEvent(ControlEvent ev) {
|
||||
// pollsetCtl blocks when a poll call is ongoing. This is very probable.
|
||||
// Therefore we let the polling thread do the pollsetCtl call.
|
||||
synchronized (controlQueue) {
|
||||
controlQueue.add(ev);
|
||||
// write byte to socketpair to force wakeup
|
||||
try {
|
||||
Pollset.interrupt(ctlSp[1]);
|
||||
} catch (IOException x) {
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
do {
|
||||
// Directly empty queue if no poll call is ongoing.
|
||||
if (controlLock.tryLock()) {
|
||||
try {
|
||||
processControlQueue();
|
||||
} finally {
|
||||
controlLock.unlock();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// Do not starve in case the polling thread returned before
|
||||
// we could write to ctlSp[1] but the polling thread did not
|
||||
// release the control lock until we checked. Therefore, use
|
||||
// a timed wait for the time being.
|
||||
controlQueue.wait(100);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore exception and try again
|
||||
}
|
||||
}
|
||||
} while (controlQueue.contains(ev));
|
||||
}
|
||||
if (ev.error() != 0) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
// Process all events currently stored in the control queue.
|
||||
private void processControlQueue() {
|
||||
// On Aix it is only possible to set the event
|
||||
// bits on the first call of pollsetCtl. Later
|
||||
// calls only add bits, but cannot remove them.
|
||||
// Therefore, we always remove the file
|
||||
// descriptor ignoring the error and then add it.
|
||||
Iterator<ControlEvent> iter = controlQueue.iterator();
|
||||
while (iter.hasNext()) {
|
||||
ControlEvent ev = iter.next();
|
||||
Pollset.pollsetCtl(pollset, Pollset.PS_DELETE, ev.fd(), 0);
|
||||
if (!ev.removeOnly()) {
|
||||
ev.setError(Pollset.pollsetCtl(pollset, Pollset.PS_MOD, ev.fd(), ev.events()));
|
||||
}
|
||||
iter.remove();
|
||||
}
|
||||
controlQueue.notifyAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* Task to process events from pollset and dispatch to the channel's
|
||||
* onEvent handler.
|
||||
*
|
||||
* Events are retrieved from pollset in batch and offered to a BlockingQueue
|
||||
* where they are consumed by handler threads. A special "NEED_TO_POLL"
|
||||
* event is used to signal one consumer to re-poll when all events have
|
||||
* been consumed.
|
||||
*/
|
||||
private class EventHandlerTask implements Runnable {
|
||||
private Event poll() throws IOException {
|
||||
try {
|
||||
for (;;) {
|
||||
int n;
|
||||
controlLock.lock();
|
||||
try {
|
||||
int m;
|
||||
m = n = Pollset.pollsetPoll(pollset, address,
|
||||
MAX_EVENTS_TO_POLL, Pollset.PS_NO_TIMEOUT);
|
||||
while (m-- > 0) {
|
||||
long eventAddress = Pollset.getEvent(address, m);
|
||||
int fd = Pollset.getDescriptor(eventAddress);
|
||||
|
||||
// To emulate one shot semantic we need to remove
|
||||
// the file descriptor here.
|
||||
if (fd != sp[0] && fd != ctlSp[0]) {
|
||||
synchronized (controlQueue) {
|
||||
Pollset.pollsetCtl(pollset, Pollset.PS_DELETE, fd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
controlLock.unlock();
|
||||
}
|
||||
/*
|
||||
* 'n' events have been read. Here we map them to their
|
||||
* corresponding channel in batch and queue n-1 so that
|
||||
* they can be handled by other handler threads. The last
|
||||
* event is handled by this thread (and so is not queued).
|
||||
*/
|
||||
fdToChannelLock.readLock().lock();
|
||||
try {
|
||||
while (n-- > 0) {
|
||||
long eventAddress = Pollset.getEvent(address, n);
|
||||
int fd = Pollset.getDescriptor(eventAddress);
|
||||
|
||||
// wakeup
|
||||
if (fd == sp[0]) {
|
||||
if (wakeupCount.decrementAndGet() == 0) {
|
||||
// no more wakeups so drain pipe
|
||||
Pollset.drain1(sp[0]);
|
||||
}
|
||||
|
||||
// queue special event if there are more events
|
||||
// to handle.
|
||||
if (n > 0) {
|
||||
queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
|
||||
continue;
|
||||
}
|
||||
return EXECUTE_TASK_OR_SHUTDOWN;
|
||||
}
|
||||
|
||||
// wakeup to process control event
|
||||
if (fd == ctlSp[0]) {
|
||||
synchronized (controlQueue) {
|
||||
IOUtil.drain(ctlSp[0]);
|
||||
processControlQueue();
|
||||
}
|
||||
if (n > 0) {
|
||||
continue;
|
||||
}
|
||||
return CONTINUE_AFTER_CTL_EVENT;
|
||||
}
|
||||
|
||||
PollableChannel channel = fdToChannel.get(fd);
|
||||
if (channel != null) {
|
||||
int events = Pollset.getRevents(eventAddress);
|
||||
Event ev = new Event(channel, events);
|
||||
|
||||
// n-1 events are queued; This thread handles
|
||||
// the last one except for the wakeup
|
||||
if (n > 0) {
|
||||
queue.offer(ev);
|
||||
} else {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fdToChannelLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// to ensure that some thread will poll when all events have
|
||||
// been consumed
|
||||
queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
|
||||
Invoker.getGroupAndInvokeCount();
|
||||
final boolean isPooledThread = (myGroupAndInvokeCount != null);
|
||||
boolean replaceMe = false;
|
||||
Event ev;
|
||||
try {
|
||||
for (;;) {
|
||||
// reset invoke count
|
||||
if (isPooledThread)
|
||||
myGroupAndInvokeCount.resetInvokeCount();
|
||||
|
||||
try {
|
||||
replaceMe = false;
|
||||
ev = queue.take();
|
||||
|
||||
// no events and this thread has been "selected" to
|
||||
// poll for more.
|
||||
if (ev == NEED_TO_POLL) {
|
||||
try {
|
||||
ev = poll();
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// continue after we processed a control event
|
||||
if (ev == CONTINUE_AFTER_CTL_EVENT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle wakeup to execute task or shutdown
|
||||
if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
|
||||
Runnable task = pollTask();
|
||||
if (task == null) {
|
||||
// shutdown request
|
||||
return;
|
||||
}
|
||||
// run task (may throw error/exception)
|
||||
replaceMe = true;
|
||||
task.run();
|
||||
continue;
|
||||
}
|
||||
|
||||
// process event
|
||||
try {
|
||||
ev.channel().onEvent(ev.events(), isPooledThread);
|
||||
} catch (Error | RuntimeException x) {
|
||||
replaceMe = true;
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// last handler to exit when shutdown releases resources
|
||||
int remaining = threadExit(this, replaceMe);
|
||||
if (remaining == 0 && isShutdown()) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 AixAsynchronousChannelProvider();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2025, 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;
|
||||
|
||||
/**
|
||||
* Default PollerProvider for AIX.
|
||||
*/
|
||||
class DefaultPollerProvider extends PollerProvider {
|
||||
DefaultPollerProvider(Poller.Mode mode) {
|
||||
if (mode != Poller.Mode.SYSTEM_THREADS) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
super(mode);
|
||||
}
|
||||
|
||||
DefaultPollerProvider() {
|
||||
this(Poller.Mode.SYSTEM_THREADS);
|
||||
}
|
||||
|
||||
@Override
|
||||
Poller readPoller(boolean subPoller) throws IOException {
|
||||
if (subPoller)
|
||||
throw new UnsupportedOperationException();
|
||||
return new PollsetPoller(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
Poller writePoller(boolean subPoller) throws IOException {
|
||||
if (subPoller)
|
||||
throw new UnsupportedOperationException();
|
||||
return new PollsetPoller(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2024, 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;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE = new PollSelectorProvider();
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
55
src/java.base/aix/classes/sun/nio/ch/FileDispatcherImpl.java
Normal file
55
src/java.base/aix/classes/sun/nio/ch/FileDispatcherImpl.java
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2022, 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.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FileDispatcherImpl extends UnixFileDispatcherImpl {
|
||||
FileDispatcherImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
int force(FileDescriptor fd, boolean metaData) throws IOException {
|
||||
return force0(fd, metaData);
|
||||
}
|
||||
|
||||
protected long transferTo(FileDescriptor src, long position,
|
||||
long count, FileDescriptor dst,
|
||||
boolean append)
|
||||
{
|
||||
return transferTo0(src, position, count, dst, append);
|
||||
}
|
||||
|
||||
// --- native methods ---
|
||||
|
||||
static native int force0(FileDescriptor fd, boolean metaData)
|
||||
throws IOException;
|
||||
|
||||
private static native long transferTo0(FileDescriptor src, long position,
|
||||
long count, FileDescriptor dst,
|
||||
boolean append);
|
||||
}
|
||||
124
src/java.base/aix/classes/sun/nio/ch/Pollset.java
Normal file
124
src/java.base/aix/classes/sun/nio/ch/Pollset.java
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, IBM Corp.
|
||||
* 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 jdk.internal.misc.Unsafe;
|
||||
|
||||
public class Pollset {
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
/**
|
||||
* struct pollfd {
|
||||
* int fd;
|
||||
* short events;
|
||||
* short revents;
|
||||
* }
|
||||
*/
|
||||
public static final int SIZEOF_POLLFD = eventSize();
|
||||
public static final int OFFSETOF_EVENTS = eventsOffset();
|
||||
public static final int OFFSETOF_REVENTS = reventsOffset();
|
||||
public static final int OFFSETOF_FD = fdOffset();
|
||||
|
||||
// opcodes
|
||||
public static final int PS_ADD = 0x0;
|
||||
public static final int PS_MOD = 0x1;
|
||||
public static final int PS_DELETE = 0x2;
|
||||
|
||||
// event
|
||||
public static final int PS_POLLPRI = 0x4;
|
||||
|
||||
// revent errcodes
|
||||
public static final char PS_POLLNVAL = 0x8000;
|
||||
public static final char PS_POLLERR = 0x4000;
|
||||
|
||||
public static final int PS_NO_TIMEOUT = -1;
|
||||
|
||||
/**
|
||||
* Allocates a poll array to handle up to {@code count} events.
|
||||
*/
|
||||
public static long allocatePollArray(int count) {
|
||||
return unsafe.allocateMemory(count * SIZEOF_POLLFD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a poll array
|
||||
*/
|
||||
public static void freePollArray(long address) {
|
||||
unsafe.freeMemory(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event[i];
|
||||
*/
|
||||
public static long getEvent(long address, int i) {
|
||||
return address + (SIZEOF_POLLFD * i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event->fd
|
||||
*/
|
||||
public static int getDescriptor(long eventAddress) {
|
||||
return unsafe.getInt(eventAddress + OFFSETOF_FD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event->events
|
||||
*/
|
||||
public static int getEvents(long eventAddress) {
|
||||
return unsafe.getChar(eventAddress + OFFSETOF_EVENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event->revents
|
||||
*/
|
||||
public static char getRevents(long eventAddress) {
|
||||
return unsafe.getChar(eventAddress + OFFSETOF_REVENTS);
|
||||
}
|
||||
|
||||
public static boolean isReventsError(long eventAddress) {
|
||||
char revents = getRevents(eventAddress);
|
||||
return (revents & PS_POLLNVAL) != 0 || (revents & PS_POLLERR) != 0;
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
public static native int pollsetCreate() throws IOException;
|
||||
public static native int pollsetCtl(int pollset, int opcode, int fd, int events);
|
||||
public static native int pollsetPoll(int pollset, long pollAddress, int numfds, int timeout)
|
||||
throws IOException;
|
||||
public static native void pollsetDestroy(int pollset);
|
||||
public static native void init();
|
||||
public static native int eventSize();
|
||||
public static native int eventsOffset();
|
||||
public static native int reventsOffset();
|
||||
public static native int fdOffset();
|
||||
public static native void socketpair(int[] sv) throws IOException;
|
||||
public static native void interrupt(int fd) throws IOException;
|
||||
public static native void drain1(int fd) throws IOException;
|
||||
public static native void close0(int fd);
|
||||
}
|
||||
114
src/java.base/aix/classes/sun/nio/ch/PollsetPoller.java
Normal file
114
src/java.base/aix/classes/sun/nio/ch/PollsetPoller.java
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, IBM Corp.
|
||||
* 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.time.Instant;
|
||||
import sun.nio.ch.Pollset;
|
||||
|
||||
/**
|
||||
* Poller implementation based on the AIX Pollset library.
|
||||
*/
|
||||
|
||||
class PollsetPoller extends Poller {
|
||||
|
||||
private static final int MAX_EVENTS_TO_POLL;
|
||||
|
||||
static {
|
||||
Pollset.init(); /* Dynamically loads pollset C functions */
|
||||
MAX_EVENTS_TO_POLL = 512;
|
||||
}
|
||||
|
||||
private final int event;
|
||||
private final int setid;
|
||||
private final long pollBuffer;
|
||||
|
||||
PollsetPoller(boolean read) throws IOException {
|
||||
this.event = (read) ? Net.POLLIN : Net.POLLOUT;
|
||||
this.setid = Pollset.pollsetCreate();
|
||||
this.pollBuffer = Pollset.allocatePollArray(MAX_EVENTS_TO_POLL);
|
||||
}
|
||||
|
||||
@Override
|
||||
void close() {
|
||||
Pollset.pollsetDestroy(setid);
|
||||
Pollset.freePollArray(pollBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
int fdVal() {
|
||||
return setid;
|
||||
}
|
||||
|
||||
@Override
|
||||
void implStartPoll(int fd) throws IOException {
|
||||
int ret = Pollset.pollsetCtl(setid, Pollset.PS_MOD, fd, Pollset.PS_POLLPRI | event);
|
||||
if (ret != 0) {
|
||||
throw new IOException("Unable to register fd " + fd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void implStopPoll(int fd, boolean polled) {
|
||||
int ret = Pollset.pollsetCtl(setid, Pollset.PS_DELETE, fd, 0);
|
||||
assert ret == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main poll method. The AIX Pollset library does not appear to pick up changes to the pollset
|
||||
* (the set of fds being polled) while blocked on a call to this method. These changes happen
|
||||
* regularly in the poll-loop thread and update thread from Poller.java.
|
||||
* To address this difficulty, we break poll calls into 100ms sub-calls and emulate the timout.
|
||||
*/
|
||||
@Override
|
||||
int poll(int timeout) throws IOException {
|
||||
int n;
|
||||
switch (timeout) {
|
||||
case 0:
|
||||
n = pollInner(0);
|
||||
break;
|
||||
case Pollset.PS_NO_TIMEOUT:
|
||||
do { n = pollInner(100); } while (n == 0);
|
||||
break;
|
||||
default:
|
||||
Instant end = Instant.now().plusMillis(timeout);
|
||||
do { n = pollInner(100); } while (n == 0 && Instant.now().isBefore(end));
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int pollInner(int subInterval) throws IOException {
|
||||
int n = Pollset.pollsetPoll(setid, pollBuffer, MAX_EVENTS_TO_POLL, subInterval);
|
||||
for (int i=0; i<n; i++) {
|
||||
long eventAddress = Pollset.getEvent(pollBuffer, i);
|
||||
int fd = Pollset.getDescriptor(eventAddress);
|
||||
polled(fd);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
119
src/java.base/aix/classes/sun/nio/fs/AixFileStore.java
Normal file
119
src/java.base/aix/classes/sun/nio/fs/AixFileStore.java
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 SAP SE. 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.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* AIX implementation of FileStore
|
||||
*/
|
||||
|
||||
class AixFileStore
|
||||
extends UnixFileStore
|
||||
{
|
||||
|
||||
AixFileStore(UnixPath file) throws IOException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
AixFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
|
||||
super(fs, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds, and returns, the mount entry for the file system where the file
|
||||
* resides.
|
||||
*/
|
||||
@Override
|
||||
UnixMountEntry findMountEntry() throws IOException {
|
||||
AixFileSystem fs = (AixFileSystem)file().getFileSystem();
|
||||
|
||||
// step 1: get realpath
|
||||
UnixPath path = null;
|
||||
try {
|
||||
byte[] rp = UnixNativeDispatcher.realpath(file());
|
||||
path = new UnixPath(fs, rp);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file());
|
||||
}
|
||||
|
||||
// step 2: find mount point
|
||||
UnixPath parent = path.getParent();
|
||||
while (parent != null) {
|
||||
UnixFileAttributes attrs = null;
|
||||
try {
|
||||
attrs = UnixFileAttributes.get(parent, true);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(parent);
|
||||
}
|
||||
if (attrs.dev() != dev())
|
||||
break;
|
||||
path = parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
// step 3: lookup mounted file systems
|
||||
byte[] dir = path.asByteArray();
|
||||
for (UnixMountEntry entry: fs.getMountEntries()) {
|
||||
if (Arrays.equals(dir, entry.dir()))
|
||||
return entry;
|
||||
}
|
||||
|
||||
throw new IOException("Mount point not found");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||
// support UserDefinedAttributeView if extended attributes enabled
|
||||
if (type == UserDefinedFileAttributeView.class) {
|
||||
// lookup fstypes.properties
|
||||
FeatureStatus status = checkIfFeaturePresent("user_xattr");
|
||||
if (status == FeatureStatus.PRESENT)
|
||||
return true;
|
||||
if (status == FeatureStatus.NOT_PRESENT)
|
||||
return false;
|
||||
|
||||
// typical AIX file system types that support xattr (JFS2 with EA enabled)
|
||||
String fstype = entry().fstype();
|
||||
if ("jfs2".equals(fstype)) {
|
||||
UnixPath dir = new UnixPath(file().getFileSystem(), entry().dir());
|
||||
return isExtendedAttributesEnabled(dir);
|
||||
}
|
||||
}
|
||||
return super.supportsFileAttributeView(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(String name) {
|
||||
if (name.equals("user"))
|
||||
return supportsFileAttributeView(UserDefinedFileAttributeView.class);
|
||||
return super.supportsFileAttributeView(name);
|
||||
}
|
||||
|
||||
}
|
||||
95
src/java.base/aix/classes/sun/nio/fs/AixFileSystem.java
Normal file
95
src/java.base/aix/classes/sun/nio/fs/AixFileSystem.java
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 SAP SE. 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.io.IOException;
|
||||
import java.util.*;
|
||||
import static sun.nio.fs.AixNativeDispatcher.*;
|
||||
|
||||
/**
|
||||
* AIX implementation of FileSystem
|
||||
*/
|
||||
|
||||
class AixFileSystem extends UnixFileSystem {
|
||||
|
||||
AixFileSystem(UnixFileSystemProvider provider, String dir) {
|
||||
super(provider, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchService newWatchService()
|
||||
throws IOException
|
||||
{
|
||||
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<String>();
|
||||
result.addAll(UnixFileSystem.standardFileAttributeViews());
|
||||
result.add("user");
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedFileAttributeViews() {
|
||||
return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
|
||||
}
|
||||
|
||||
@Override
|
||||
void copyNonPosixAttributes(int ofd, int nfd) {
|
||||
// TODO: Implement if needed.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object to iterate over the mount entries returned by mntctl
|
||||
*/
|
||||
@Override
|
||||
Iterable<UnixMountEntry> getMountEntries() {
|
||||
UnixMountEntry[] entries = null;
|
||||
try {
|
||||
entries = getmntctl();
|
||||
} catch (UnixException x) {
|
||||
// nothing we can do
|
||||
}
|
||||
if (entries == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.asList(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
FileStore getFileStore(UnixMountEntry entry) throws IOException {
|
||||
return new AixFileStore(this, entry);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2025 SAP SE. 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.io.IOException;
|
||||
|
||||
/**
|
||||
* AIX implementation of FileSystemProvider
|
||||
*/
|
||||
|
||||
class AixFileSystemProvider extends UnixFileSystemProvider {
|
||||
public AixFileSystemProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
AixFileSystem newFileSystem(String dir) {
|
||||
return new AixFileSystem(this, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see sun.nio.fs.UnixFileSystemProvider#getFileStore(sun.nio.fs.UnixPath)
|
||||
*/
|
||||
@Override
|
||||
AixFileStore getFileStore(UnixPath path) throws IOException {
|
||||
return new AixFileStore(path);
|
||||
}
|
||||
|
||||
private static boolean supportsUserDefinedFileAttributeView(UnixPath file) {
|
||||
try {
|
||||
FileStore store = new AixFileStore(file);
|
||||
return store.supportsFileAttributeView(UserDefinedFileAttributeView.class);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
|
||||
Class<V> type,
|
||||
LinkOption... options)
|
||||
{
|
||||
if (type == UserDefinedFileAttributeView.class) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
return supportsUserDefinedFileAttributeView(file) ?
|
||||
(V) new AixUserDefinedFileAttributeView(file, Util.followLinks(options))
|
||||
: null;
|
||||
}
|
||||
return super.getFileAttributeView(obj, type, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicFileAttributeView getFileAttributeView(Path obj,
|
||||
String name,
|
||||
LinkOption... options)
|
||||
{
|
||||
if (name.equals("user")) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
return supportsUserDefinedFileAttributeView(file) ?
|
||||
new AixUserDefinedFileAttributeView(file, Util.followLinks(options))
|
||||
: null;
|
||||
}
|
||||
return super.getFileAttributeView(obj, name, options);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 SAP SE. 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;
|
||||
|
||||
/**
|
||||
* AIX specific system calls.
|
||||
*/
|
||||
|
||||
class AixNativeDispatcher extends UnixNativeDispatcher {
|
||||
private AixNativeDispatcher() { }
|
||||
|
||||
/**
|
||||
* Special implementation of 'getextmntent' (see SolarisNativeDispatcher)
|
||||
* that returns all entries at once.
|
||||
*/
|
||||
static native UnixMountEntry[] getmntctl() throws UnixException;
|
||||
|
||||
// initialize
|
||||
private static native void init();
|
||||
|
||||
static {
|
||||
jdk.internal.loader.BootLoader.loadLibrary("nio");
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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;
|
||||
|
||||
class AixUserDefinedFileAttributeView
|
||||
extends UnixUserDefinedFileAttributeView
|
||||
{
|
||||
|
||||
AixUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
|
||||
super(file, followLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int maxNameLength() {
|
||||
return 255;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2018, 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.FileSystem;
|
||||
|
||||
/**
|
||||
* Creates this platform's default FileSystemProvider.
|
||||
*/
|
||||
|
||||
public class DefaultFileSystemProvider {
|
||||
private static final AixFileSystemProvider INSTANCE
|
||||
= new AixFileSystemProvider();
|
||||
|
||||
private DefaultFileSystemProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the platform's default file system provider.
|
||||
*/
|
||||
public static AixFileSystemProvider instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform's default file system.
|
||||
*/
|
||||
public static FileSystem theFileSystem() {
|
||||
return INSTANCE.theFileSystem();
|
||||
}
|
||||
}
|
||||
585
src/java.base/aix/conf/tzmappings
Normal file
585
src/java.base/aix/conf/tzmappings
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
#
|
||||
#
|
||||
# Copyright (c) 1994, 2014, 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Portions Copyright (c) 2014 IBM Corporation
|
||||
#
|
||||
|
||||
# This table describes mappings between AIX time zone IDs and Java time zone
|
||||
# IDs. Fields are separated by a single TAB ('\t'). Lines must be in the ascending
|
||||
# order in ASCII. (non-ASCII characters can't be used.)
|
||||
# NOTE
|
||||
# This table format is not a public interface of any Java
|
||||
# platforms. No applications should depend on this file in any form.
|
||||
# This file has been generated using programs. Do not edit this file manually.
|
||||
#
|
||||
# Solaris Java
|
||||
|
||||
ACST-9:30ACDT Australia/Adelaide
|
||||
AST4 America/Curacao
|
||||
AST4ADT America/Halifax
|
||||
AST9 Pacific/Gambier
|
||||
AST9ADT America/Anchorage
|
||||
AZOREST1 Atlantic/Cape_Verde
|
||||
AZOREST1AZOREDT Atlantic/Azores
|
||||
Africa/Abidjan Africa/Abidjan
|
||||
Africa/Accra Africa/Accra
|
||||
Africa/Addis_Ababa Africa/Addis_Ababa
|
||||
Africa/Algiers Africa/Algiers
|
||||
Africa/Asmera Africa/Asmera
|
||||
Africa/Bamako GMT
|
||||
Africa/Bangui Africa/Bangui
|
||||
Africa/Banjul Africa/Banjul
|
||||
Africa/Bissau Africa/Bissau
|
||||
Africa/Blantyre Africa/Blantyre
|
||||
Africa/Brazzaville Africa/Luanda
|
||||
Africa/Bujumbura Africa/Bujumbura
|
||||
Africa/Cairo Africa/Cairo
|
||||
Africa/Casablanca Africa/Casablanca
|
||||
Africa/Ceuta Europe/Paris
|
||||
Africa/Conakry Africa/Conakry
|
||||
Africa/Dakar Africa/Dakar
|
||||
Africa/Dar_es_Salaam Africa/Dar_es_Salaam
|
||||
Africa/Djibouti Africa/Djibouti
|
||||
Africa/Douala Africa/Douala
|
||||
Africa/El_Aaiun Africa/Casablanca
|
||||
Africa/Freetown Africa/Freetown
|
||||
Africa/Gaborone Africa/Gaborone
|
||||
Africa/Harare Africa/Harare
|
||||
Africa/Johannesburg Africa/Johannesburg
|
||||
Africa/Kampala Africa/Kampala
|
||||
Africa/Khartoum Africa/Khartoum
|
||||
Africa/Kigali Africa/Kigali
|
||||
Africa/Kinshasa Africa/Kinshasa
|
||||
Africa/Lagos Africa/Lagos
|
||||
Africa/Libreville Africa/Libreville
|
||||
Africa/Lome Africa/Lome
|
||||
Africa/Luanda Africa/Luanda
|
||||
Africa/Lubumbashi Africa/Lubumbashi
|
||||
Africa/Lusaka Africa/Lusaka
|
||||
Africa/Malabo Africa/Malabo
|
||||
Africa/Maputo Africa/Maputo
|
||||
Africa/Maseru Africa/Maseru
|
||||
Africa/Mbabane Africa/Mbabane
|
||||
Africa/Mogadishu Africa/Mogadishu
|
||||
Africa/Monrovia Africa/Monrovia
|
||||
Africa/Nairobi Africa/Nairobi
|
||||
Africa/Ndjamena Africa/Ndjamena
|
||||
Africa/Niamey Africa/Niamey
|
||||
Africa/Nouakchott Africa/Nouakchott
|
||||
Africa/Ouagadougou Africa/Ouagadougou
|
||||
Africa/Porto-Novo Africa/Porto-Novo
|
||||
Africa/Sao_Tome Africa/Sao_Tome
|
||||
Africa/Timbuktu Africa/Timbuktu
|
||||
Africa/Tripoli Africa/Tripoli
|
||||
Africa/Tunis Africa/Tunis
|
||||
Africa/Windhoek Africa/Windhoek
|
||||
America/Adak America/Adak
|
||||
America/Anchorage America/Anchorage
|
||||
America/Anguilla America/Anguilla
|
||||
America/Antigua America/Antigua
|
||||
America/Araguaina America/Sao_Paulo
|
||||
America/Argentina/Buenos_Aires America/Argentina/Buenos_Aires
|
||||
America/Argentina/Catamarca America/Argentina/Catamarca
|
||||
America/Argentina/ComodRivadavia America/Argentina/Catamarca
|
||||
America/Argentina/Cordoba America/Argentina/Cordoba
|
||||
America/Argentina/Jujuy America/Argentina/Jujuy
|
||||
America/Argentina/La_Rioja America/Argentina/La_Rioja
|
||||
America/Argentina/Mendoza America/Argentina/Mendoza
|
||||
America/Argentina/Rio_Gallegos America/Argentina/Rio_Gallegos
|
||||
America/Argentina/Salta America/Argentina/Salta
|
||||
America/Argentina/San_Juan America/Argentina/San_Juan
|
||||
America/Argentina/San_Luis America/Argentina/San_Luis
|
||||
America/Argentina/Tucuman America/Argentina/Tucuman
|
||||
America/Argentina/Ushuaia America/Argentina/Ushuaia
|
||||
America/Aruba America/Aruba
|
||||
America/Asuncion America/Asuncion
|
||||
America/Atka America/Adak
|
||||
America/Barbados America/Barbados
|
||||
America/Belize America/Belize
|
||||
America/Bogota America/Bogota
|
||||
America/Boise America/Denver
|
||||
America/Buenos_Aires America/Argentina/Buenos_Aires
|
||||
America/Cancun America/Chicago
|
||||
America/Caracas America/Caracas
|
||||
America/Catamarca America/Argentina/Catamarca
|
||||
America/Cayenne America/Cayenne
|
||||
America/Cayman America/Cayman
|
||||
America/Chicago America/Chicago
|
||||
America/Chihuahua America/Denver
|
||||
America/Coral_Harbour America/Atikokan
|
||||
America/Cordoba America/Argentina/Cordoba
|
||||
America/Costa_Rica America/Costa_Rica
|
||||
America/Cuiaba America/Cuiaba
|
||||
America/Curacao America/Curacao
|
||||
America/Dawson America/Los_Angeles
|
||||
America/Dawson_Creek America/Dawson_Creek
|
||||
America/Denver America/Denver
|
||||
America/Detroit America/New_York
|
||||
America/Dominica America/Dominica
|
||||
America/Edmonton America/Edmonton
|
||||
America/El_Salvador America/El_Salvador
|
||||
America/Ensenada America/Los_Angeles
|
||||
America/Fort_Wayne America/Indiana/Indianapolis
|
||||
America/Fortaleza America/Fortaleza
|
||||
America/Glace_Bay America/Halifax
|
||||
America/Godthab America/Godthab
|
||||
America/Goose_Bay America/Thule
|
||||
America/Grand_Turk America/Grand_Turk
|
||||
America/Grenada America/Grenada
|
||||
America/Guadeloupe America/Guadeloupe
|
||||
America/Guatemala America/Guatemala
|
||||
America/Guayaquil America/Guayaquil
|
||||
America/Guyana America/Guyana
|
||||
America/Halifax America/Halifax
|
||||
America/Havana America/Havana
|
||||
America/Indiana/Indianapolis America/Indianapolis
|
||||
America/Indianapolis America/Indiana/Indianapolis
|
||||
America/Inuvik America/Denver
|
||||
America/Iqaluit America/New_York
|
||||
America/Jamaica America/Jamaica
|
||||
America/Jujuy America/Argentina/Jujuy
|
||||
America/Juneau America/Anchorage
|
||||
America/Knox_IN America/Indiana/Knox
|
||||
America/La_Paz America/La_Paz
|
||||
America/Lima America/Lima
|
||||
America/Los_Angeles America/Los_Angeles
|
||||
America/Louisville America/Kentucky/Louisville
|
||||
America/Managua America/Managua
|
||||
America/Manaus America/Manaus
|
||||
America/Marigot America/Guadeloupe
|
||||
America/Martinique America/Martinique
|
||||
America/Mazatlan America/Mazatlan
|
||||
America/Mendoza America/Argentina/Mendoza
|
||||
America/Menominee America/Winnipeg
|
||||
America/Mexico_City America/Mexico_City
|
||||
America/Miquelon America/Miquelon
|
||||
America/Moncton America/Moncton
|
||||
America/Montevideo America/Montevideo
|
||||
America/Montreal America/Montreal
|
||||
America/Montserrat America/Montserrat
|
||||
America/Nassau America/Nassau
|
||||
America/New_York America/New_York
|
||||
America/Nipigon America/New_York
|
||||
America/Nome America/Anchorage
|
||||
America/Noronha America/Noronha
|
||||
America/Panama America/Panama
|
||||
America/Pangnirtung America/Thule
|
||||
America/Paramaribo America/Paramaribo
|
||||
America/Phoenix America/Phoenix
|
||||
America/Port-au-Prince America/Port-au-Prince
|
||||
America/Port_of_Spain America/Port_of_Spain
|
||||
America/Porto_Acre America/Rio_Branco
|
||||
America/Puerto_Rico America/Puerto_Rico
|
||||
America/Rainy_River America/Chicago
|
||||
America/Rankin_Inlet America/Chicago
|
||||
America/Regina America/Regina
|
||||
America/Rio_Branco America/Rio_Branco
|
||||
America/Rosario America/Argentina/Cordoba
|
||||
America/Santiago America/Santiago
|
||||
America/Santo_Domingo America/Santo_Domingo
|
||||
America/Sao_Paulo America/Sao_Paulo
|
||||
America/Scoresbysund America/Scoresbysund
|
||||
America/Shiprock America/Denver
|
||||
America/St_Barthelemy America/Guadeloupe
|
||||
America/St_Johns America/St_Johns
|
||||
America/St_Kitts America/St_Kitts
|
||||
America/St_Lucia America/St_Lucia
|
||||
America/St_Thomas America/St_Thomas
|
||||
America/St_Vincent America/St_Vincent
|
||||
America/Tegucigalpa America/Tegucigalpa
|
||||
America/Thule America/Thule
|
||||
America/Thunder_Bay America/New_York
|
||||
America/Tijuana America/Tijuana
|
||||
America/Toronto America/Toronto
|
||||
America/Tortola America/Tortola
|
||||
America/Vancouver America/Vancouver
|
||||
America/Virgin America/St_Thomas
|
||||
America/Whitehorse America/Los_Angeles
|
||||
America/Winnipeg America/Winnipeg
|
||||
America/Yakutat America/Anchorage
|
||||
America/Yellowknife America/Denver
|
||||
Antarctica/Casey Antarctica/Casey
|
||||
Antarctica/DumontDUrville Antarctica/DumontDUrville
|
||||
Antarctica/Mawson Antarctica/Mawson
|
||||
Antarctica/McMurdo Antarctica/McMurdo
|
||||
Antarctica/Palmer Antarctica/Palmer
|
||||
Antarctica/South_Pole Antarctica/McMurdo
|
||||
Arctic/Longyearbyen Europe/Oslo
|
||||
Asia/Aden Asia/Aden
|
||||
Asia/Almaty Asia/Almaty
|
||||
Asia/Amman Asia/Amman
|
||||
Asia/Anadyr Asia/Anadyr
|
||||
Asia/Aqtau Asia/Aqtau
|
||||
Asia/Aqtobe Asia/Aqtobe
|
||||
Asia/Ashkhabad Asia/Ashkhabad
|
||||
Asia/Baghdad Asia/Baghdad
|
||||
Asia/Bahrain Asia/Bahrain
|
||||
Asia/Baku Asia/Baku
|
||||
Asia/Bangkok Asia/Bangkok
|
||||
Asia/Beirut Asia/Beirut
|
||||
Asia/Bishkek Asia/Bishkek
|
||||
Asia/Brunei Asia/Brunei
|
||||
Asia/Calcutta Asia/Calcutta
|
||||
Asia/Chungking Asia/Shanghai
|
||||
Asia/Colombo Asia/Colombo
|
||||
Asia/Dacca Asia/Dacca
|
||||
Asia/Damascus Asia/Damascus
|
||||
Asia/Dhaka Asia/Dhaka
|
||||
Asia/Dubai Asia/Dubai
|
||||
Asia/Dushanbe Asia/Dushanbe
|
||||
Asia/Gaza Asia/Amman
|
||||
Asia/Harbin Asia/Shanghai
|
||||
Asia/Hong_Kong Asia/Hong_Kong
|
||||
Asia/Irkutsk Asia/Irkutsk
|
||||
Asia/Istanbul Europe/Istanbul
|
||||
Asia/Jakarta Asia/Jakarta
|
||||
Asia/Jayapura Asia/Jayapura
|
||||
Asia/Jerusalem Asia/Jerusalem
|
||||
Asia/Kabul Asia/Kabul
|
||||
Asia/Kamchatka Asia/Kamchatka
|
||||
Asia/Karachi Asia/Karachi
|
||||
Asia/Kashgar Asia/Shanghai
|
||||
Asia/Katmandu Asia/Katmandu
|
||||
Asia/Kolkata Asia/Kolkata
|
||||
Asia/Krasnoyarsk Asia/Krasnoyarsk
|
||||
Asia/Kuala_Lumpur Asia/Kuala_Lumpur
|
||||
Asia/Kuwait Asia/Kuwait
|
||||
Asia/Macao Asia/Macao
|
||||
Asia/Magadan Asia/Magadan
|
||||
Asia/Manila Asia/Manila
|
||||
Asia/Muscat Asia/Muscat
|
||||
Asia/Nicosia Asia/Nicosia
|
||||
Asia/Novosibirsk Asia/Novosibirsk
|
||||
Asia/Omsk Asia/Novosibirsk
|
||||
Asia/Phnom_Penh Asia/Phnom_Penh
|
||||
Asia/Pyongyang Asia/Pyongyang
|
||||
Asia/Qatar Asia/Qatar
|
||||
Asia/Rangoon Asia/Rangoon
|
||||
Asia/Riyadh Asia/Riyadh
|
||||
Asia/Saigon Asia/Ho_Chi_Minh
|
||||
Asia/Seoul Asia/Seoul
|
||||
Asia/Shanghai Asia/Shanghai
|
||||
Asia/Singapore Asia/Singapore
|
||||
Asia/Taipei Asia/Taipei
|
||||
Asia/Tashkent Asia/Tashkent
|
||||
Asia/Tbilisi Asia/Tbilisi
|
||||
Asia/Tehran Asia/Tehran
|
||||
Asia/Tel_Aviv Asia/Jerusalem
|
||||
Asia/Thimbu Asia/Thimbu
|
||||
Asia/Tokyo Asia/Tokyo
|
||||
Asia/Ujung_Pandang Asia/Ujung_Pandang
|
||||
Asia/Ulan_Bator Asia/Ulaanbaatar
|
||||
Asia/Urumqi Asia/Shanghai
|
||||
Asia/Vientiane Asia/Vientiane
|
||||
Asia/Vladivostok Asia/Vladivostok
|
||||
Asia/Yakutsk Asia/Yakutsk
|
||||
Asia/Yekaterinburg Asia/Yekaterinburg
|
||||
Asia/Yerevan Asia/Yerevan
|
||||
Atlantic/Azores Atlantic/Azores
|
||||
Atlantic/Bermuda Atlantic/Bermuda
|
||||
Atlantic/Canary Atlantic/Canary
|
||||
Atlantic/Cape_Verde Atlantic/Cape_Verde
|
||||
Atlantic/Faeroe Atlantic/Faeroe
|
||||
Atlantic/Jan_Mayen Atlantic/Jan_Mayen
|
||||
Atlantic/Madeira Europe/London
|
||||
Atlantic/Reykjavik Atlantic/Reykjavik
|
||||
Atlantic/South_Georgia Atlantic/South_Georgia
|
||||
Atlantic/St_Helena Atlantic/St_Helena
|
||||
Atlantic/Stanley Atlantic/Stanley
|
||||
Australia/ACT Australia/Sydney
|
||||
Australia/Adelaide Australia/Adelaide
|
||||
Australia/Brisbane Australia/Brisbane
|
||||
Australia/Broken_Hill Australia/Broken_Hill
|
||||
Australia/Canberra Australia/Sydney
|
||||
Australia/Darwin Australia/Darwin
|
||||
Australia/Hobart Australia/Hobart
|
||||
Australia/LHI Australia/Lord_Howe
|
||||
Australia/Lord_Howe Australia/Lord_Howe
|
||||
Australia/Melbourne Australia/Sydney
|
||||
Australia/NSW Australia/Sydney
|
||||
Australia/North Australia/Darwin
|
||||
Australia/Perth Australia/Perth
|
||||
Australia/Queensland Australia/Brisbane
|
||||
Australia/South Australia/Adelaide
|
||||
Australia/Sydney Australia/Sydney
|
||||
Australia/Tasmania Australia/Hobart
|
||||
Australia/Victoria Australia/Melbourne
|
||||
Australia/West Australia/Perth
|
||||
Australia/Yancowinna Australia/Broken_Hill
|
||||
BRT3BRST America/Sao_Paulo
|
||||
BST11 Pacific/Apia
|
||||
BST11BDT Pacific/Apia
|
||||
Brazil/Acre America/Rio_Branco
|
||||
Brazil/DeNoronha America/Noronha
|
||||
Brazil/East America/Sao_Paulo
|
||||
Brazil/West America/Manaus
|
||||
CET Europe/Paris
|
||||
CET-1CEST Europe/Paris
|
||||
CET-1CEST-2 Europe/Berlin
|
||||
CET-1CET-2 Europe/Paris
|
||||
CST6 America/Costa_Rica
|
||||
CST6CDT America/Chicago
|
||||
CUT0 UTC
|
||||
CUT0GDT Europe/London
|
||||
Canada/Atlantic America/Halifax
|
||||
Canada/Central America/Winnipeg
|
||||
Canada/East-Saskatchewan America/Regina
|
||||
Canada/Eastern America/Montreal
|
||||
Canada/Mountain America/Edmonton
|
||||
Canada/Newfoundland America/St_Johns
|
||||
Canada/Pacific America/Vancouver
|
||||
Canada/Saskatchewan America/Regina
|
||||
Canada/Yukon America/Whitehorse
|
||||
Chile/Continental America/Santiago
|
||||
Chile/EasterIsland Pacific/Easter
|
||||
Cuba America/Havana
|
||||
EET Europe/Istanbul
|
||||
EET-10 Australia/Brisbane
|
||||
EET-10EETDT Australia/Sydney
|
||||
EST America/Indianapolis
|
||||
EST5 America/Indianapolis
|
||||
EST5EDT America/New_York
|
||||
Egypt Africa/Cairo
|
||||
Eire Europe/Dublin
|
||||
Etc/GMT GMT
|
||||
Etc/GMT0 GMT
|
||||
Etc/Greenwich GMT
|
||||
Etc/UCT UTC
|
||||
Etc/UTC UTC
|
||||
Etc/Universal UTC
|
||||
Etc/Zulu UTC
|
||||
Europe/Amsterdam Europe/Amsterdam
|
||||
Europe/Andorra Europe/Andorra
|
||||
Europe/Athens Europe/Athens
|
||||
Europe/Belfast Europe/London
|
||||
Europe/Belgrade Europe/Belgrade
|
||||
Europe/Berlin Europe/Berlin
|
||||
Europe/Bratislava Europe/Prague
|
||||
Europe/Brussels Europe/Brussels
|
||||
Europe/Bucharest Europe/Bucharest
|
||||
Europe/Budapest Europe/Budapest
|
||||
Europe/Chisinau Europe/Chisinau
|
||||
Europe/Copenhagen Europe/Copenhagen
|
||||
Europe/Dublin Europe/Dublin
|
||||
Europe/Gibraltar Europe/Gibraltar
|
||||
Europe/Guernsey Europe/London
|
||||
Europe/Helsinki Europe/Helsinki
|
||||
Europe/Isle_of_Man Europe/London
|
||||
Europe/Istanbul Europe/Istanbul
|
||||
Europe/Jersey Europe/London
|
||||
Europe/Kaliningrad Europe/Kaliningrad
|
||||
Europe/Kiev Europe/Kiev
|
||||
Europe/Lisbon Europe/Lisbon
|
||||
Europe/Ljubljana Europe/Belgrade
|
||||
Europe/London Europe/London
|
||||
Europe/Luxembourg Europe/Luxembourg
|
||||
Europe/Madrid Europe/Madrid
|
||||
Europe/Malta Europe/Malta
|
||||
Europe/Mariehamn Europe/Helsinki
|
||||
Europe/Minsk Europe/Minsk
|
||||
Europe/Monaco Europe/Monaco
|
||||
Europe/Moscow Europe/Moscow
|
||||
Europe/Nicosia Asia/Nicosia
|
||||
Europe/Oslo Europe/Oslo
|
||||
Europe/Paris Europe/Paris
|
||||
Europe/Podgorica Europe/Belgrade
|
||||
Europe/Prague Europe/Prague
|
||||
Europe/Riga Europe/Riga
|
||||
Europe/Rome Europe/Rome
|
||||
Europe/Samara Europe/Samara
|
||||
Europe/San_Marino Europe/Rome
|
||||
Europe/Sarajevo Europe/Belgrade
|
||||
Europe/Simferopol Europe/Simferopol
|
||||
Europe/Skopje Europe/Belgrade
|
||||
Europe/Sofia Europe/Sofia
|
||||
Europe/Stockholm Europe/Stockholm
|
||||
Europe/Tallinn Europe/Tallinn
|
||||
Europe/Tirane Europe/Tirane
|
||||
Europe/Vaduz Europe/Vaduz
|
||||
Europe/Vatican Europe/Rome
|
||||
Europe/Vienna Europe/Vienna
|
||||
Europe/Vilnius Europe/Vilnius
|
||||
Europe/Warsaw Europe/Warsaw
|
||||
Europe/Zagreb Europe/Belgrade
|
||||
Europe/Zurich Europe/Zurich
|
||||
FALKST2 Atlantic/South_Georgia
|
||||
FALKST2FALKDT Atlantic/South_Georgia
|
||||
Factory GMT
|
||||
GB Europe/London
|
||||
GB-Eire Europe/London
|
||||
GMT GMT
|
||||
GMT0 GMT
|
||||
GMT0BST Europe/London
|
||||
GMT0BST-1 Europe/London
|
||||
GMT0WET Europe/Lisbon
|
||||
GRNLNDST3 America/Buenos_Aires
|
||||
GRNLNDST3GRNLNDDT America/Godthab
|
||||
Greenwich GMT
|
||||
HST Pacific/Honolulu
|
||||
HST10 Pacific/Honolulu
|
||||
HST10HDT America/Adak
|
||||
Hongkong Asia/Hong_Kong
|
||||
Iceland Atlantic/Reykjavik
|
||||
Indian/Antananarivo Indian/Antananarivo
|
||||
Indian/Chagos Indian/Chagos
|
||||
Indian/Christmas Indian/Christmas
|
||||
Indian/Cocos Indian/Cocos
|
||||
Indian/Comoro Indian/Comoro
|
||||
Indian/Kerguelen Indian/Kerguelen
|
||||
Indian/Mahe Indian/Mahe
|
||||
Indian/Maldives Indian/Maldives
|
||||
Indian/Mauritius Indian/Mauritius
|
||||
Indian/Mayotte Indian/Mayotte
|
||||
Indian/Reunion Indian/Reunion
|
||||
Iran Asia/Tehran
|
||||
Israel Asia/Jerusalem
|
||||
JST-9 Asia/Tokyo
|
||||
JST-9JSTDT Asia/Tokyo
|
||||
Jamaica America/Jamaica
|
||||
Japan Asia/Tokyo
|
||||
KORST-9 Asia/Seoul
|
||||
KORST-9KORDT Asia/Seoul
|
||||
Kwajalein Pacific/Kwajalein
|
||||
Libya Africa/Tripoli
|
||||
MEST-2 Europe/Istanbul
|
||||
MEST-2MEDT Europe/Istanbul
|
||||
MEST-3 Asia/Riyadh
|
||||
MEST-3MEDT Europe/Moscow
|
||||
MET Europe/Paris
|
||||
MET-11 Pacific/Guadalcanal
|
||||
MET-11METDT Asia/Magadan
|
||||
MET-1MEST Europe/Paris
|
||||
MET-1MST-2 Europe/Berlin
|
||||
MEZ-1MESZ Europe/Berlin
|
||||
MEZ-1MESZ-2 Europe/Berlin
|
||||
MSK-3MSD Europe/Moscow
|
||||
MST America/Phoenix
|
||||
MST7 America/Phoenix
|
||||
MST7MDT America/Denver
|
||||
Mexico/BajaNorte America/Tijuana
|
||||
Mexico/BajaSur America/Mazatlan
|
||||
Mexico/General America/Mexico_City
|
||||
Mideast/Riyadh87 Asia/Riyadh87
|
||||
Mideast/Riyadh88 Asia/Riyadh88
|
||||
Mideast/Riyadh89 Asia/Riyadh89
|
||||
NFT-1 Africa/Algiers
|
||||
NFT-1DFT Europe/Paris
|
||||
NFT-1DST Europe/Paris
|
||||
NZ Pacific/Auckland
|
||||
NZ-CHAT Pacific/Chatham
|
||||
NZST-12 Pacific/Fiji
|
||||
NZST-12NZDT Pacific/Auckland
|
||||
Navajo America/Denver
|
||||
PAKST-5 Asia/Karachi
|
||||
PAKST-5PAKDT Asia/Yekaterinburg
|
||||
PRC Asia/Shanghai
|
||||
PST8 Pacific/Pitcairn
|
||||
PST8PDT America/Los_Angeles
|
||||
PST8PDT7 America/Tijuana
|
||||
Pacific/Apia Pacific/Apia
|
||||
Pacific/Auckland Pacific/Auckland
|
||||
Pacific/Chatham Pacific/Chatham
|
||||
Pacific/Easter Pacific/Easter
|
||||
Pacific/Efate Pacific/Efate
|
||||
Pacific/Enderbury Pacific/Enderbury
|
||||
Pacific/Fakaofo Pacific/Fakaofo
|
||||
Pacific/Fiji Pacific/Fiji
|
||||
Pacific/Funafuti Pacific/Funafuti
|
||||
Pacific/Galapagos Pacific/Galapagos
|
||||
Pacific/Gambier Pacific/Gambier
|
||||
Pacific/Guadalcanal Pacific/Guadalcanal
|
||||
Pacific/Guam Pacific/Guam
|
||||
Pacific/Honolulu Pacific/Honolulu
|
||||
Pacific/Kiritimati Pacific/Kiritimati
|
||||
Pacific/Kosrae Pacific/Kosrae
|
||||
Pacific/Majuro Pacific/Majuro
|
||||
Pacific/Marquesas Pacific/Marquesas
|
||||
Pacific/Nauru Pacific/Nauru
|
||||
Pacific/Niue Pacific/Niue
|
||||
Pacific/Norfolk Pacific/Norfolk
|
||||
Pacific/Noumea Pacific/Noumea
|
||||
Pacific/Pago_Pago Pacific/Pago_Pago
|
||||
Pacific/Palau Pacific/Palau
|
||||
Pacific/Pitcairn Pacific/Pitcairn
|
||||
Pacific/Ponape Pacific/Ponape
|
||||
Pacific/Port_Moresby Pacific/Port_Moresby
|
||||
Pacific/Rarotonga Pacific/Rarotonga
|
||||
Pacific/Saipan Pacific/Saipan
|
||||
Pacific/Samoa Pacific/Pago_Pago
|
||||
Pacific/Tahiti Pacific/Tahiti
|
||||
Pacific/Tarawa Pacific/Tarawa
|
||||
Pacific/Tongatapu Pacific/Tongatapu
|
||||
Pacific/Truk Pacific/Truk
|
||||
Pacific/Wake Pacific/Wake
|
||||
Pacific/Wallis Pacific/Wallis
|
||||
Poland Europe/Warsaw
|
||||
Portugal Europe/Lisbon
|
||||
ROC Asia/Taipei
|
||||
ROK Asia/Seoul
|
||||
SAUST-3 Asia/Riyadh
|
||||
SAUST-3SAUDT Europe/Moscow
|
||||
Singapore Asia/Singapore
|
||||
SystemV/AST4ADT America/Thule
|
||||
SystemV/CST6CDT America/Chicago
|
||||
SystemV/EST5EDT America/New_York
|
||||
SystemV/MST7MDT America/Denver
|
||||
SystemV/PST8PDT America/Los_Angeles
|
||||
SystemV/YST9YDT America/Anchorage
|
||||
TAIST-8 Asia/Taipei
|
||||
TAIST-8TAIDT Asia/Irkutsk
|
||||
TASHST-6 Asia/Dacca
|
||||
TASHST-6TASHDT Asia/Novosibirsk
|
||||
THAIST-7 Asia/Bangkok
|
||||
THAIST-7THAIDT Asia/Krasnoyarsk
|
||||
Turkey Europe/Istanbul
|
||||
UCT UTC
|
||||
US/Alaska America/Anchorage
|
||||
US/Aleutian America/Adak
|
||||
US/Arizona America/Phoenix
|
||||
US/Central America/Chicago
|
||||
US/East-Indiana America/Indiana/Indianapolis
|
||||
US/Eastern America/New_York
|
||||
US/Hawaii Pacific/Honolulu
|
||||
US/Indiana-Starke America/Indiana/Knox
|
||||
US/Michigan America/New_York
|
||||
US/Mountain America/Denver
|
||||
US/Pacific America/Los_Angeles
|
||||
US/Samoa Pacific/Pago_Pago
|
||||
USAST-2 Africa/Johannesburg
|
||||
USAST-2USADT Europe/Istanbul
|
||||
UTC UTC
|
||||
UYT3UYST America/Montevideo
|
||||
Universal UTC
|
||||
W-SU Europe/Moscow
|
||||
WAUST-8 Australia/Perth
|
||||
WAUST-8WAUDT Australia/Perth
|
||||
WET WET
|
||||
WET-2 Africa/Johannesburg
|
||||
WET-2WET Europe/Helsinki
|
||||
WST-4 Asia/Dubai
|
||||
WST-4WDT Europe/Samara
|
||||
Zulu UTC
|
||||
49
src/java.base/aix/native/include/dl_info.h
Normal file
49
src/java.base/aix/native/include/dl_info.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2026 SAP SE. 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.
|
||||
*/
|
||||
|
||||
#ifndef AIX_INCLUDE_DL_INFO_H
|
||||
#define AIX_INCLUDE_DL_INFO_H
|
||||
|
||||
/* struct for dladdr
|
||||
* Differences between AIX dladdr and Linux dladdr:
|
||||
*
|
||||
* 1) Dl_info.dli_fbase: can never work, is not included in our struct
|
||||
* A loaded image on AIX is divided in multiple segments, at least two
|
||||
* (text and data) but potentially also far more. This is because the loader may
|
||||
* load each member into an own segment, as for instance happens with the libC.a
|
||||
* 2) Dl_info.dli_sname: This only works for code symbols (functions); for data, a
|
||||
* zero-length string is returned ("").
|
||||
* 3) Dl_info.dli_saddr: For code, this will return the entry point of the function,
|
||||
* not the function descriptor.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
const char *dli_fname; /* file path of loaded library */
|
||||
const char *dli_sname; /* symbol name; "" if not known */
|
||||
void *dli_saddr; /* address of *entry* of function; not function descriptor; */
|
||||
} Dl_info;
|
||||
|
||||
#endif
|
||||
246
src/java.base/aix/native/libjava/ProcessHandleImpl_aix.c
Normal file
246
src/java.base/aix/native/libjava/ProcessHandleImpl_aix.c
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025 SAP SE. 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
#include "ProcessHandleImpl_unix.h"
|
||||
|
||||
#include <sys/procfs.h>
|
||||
#include <procinfo.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Implementation of native ProcessHandleImpl functions for AIX.
|
||||
* See ProcessHandleImpl_unix.c for more details.
|
||||
*/
|
||||
|
||||
void os_initNative(JNIEnv *env, jclass clazz) {}
|
||||
|
||||
/*
|
||||
* Return pids of active processes, and optionally parent pids and
|
||||
* start times for each process.
|
||||
* For a specific non-zero pid, only the direct children are returned.
|
||||
* If the pid is zero, all active processes are returned.
|
||||
* Use getprocs64 to accumulate any process following the rules above.
|
||||
* The resulting pids are stored into an array of longs named jarray.
|
||||
* The number of pids is returned if they all fit.
|
||||
* If the parentArray is non-null, store also the parent pid.
|
||||
* In this case the parentArray must have the same length as the result pid array.
|
||||
* Of course in the case of a given non-zero pid all entries in the parentArray
|
||||
* will contain this pid, so this array does only make sense in the case of a given
|
||||
* zero pid.
|
||||
* If the jstimesArray is non-null, store also the start time of the pid.
|
||||
* In this case the jstimesArray must have the same length as the result pid array.
|
||||
* If the array(s) (is|are) too short, excess pids are not stored and
|
||||
* the desired length is returned.
|
||||
*/
|
||||
jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
|
||||
jlongArray jparentArray, jlongArray jstimesArray) {
|
||||
pid_t pid = (pid_t) jpid;
|
||||
jlong* pids = NULL;
|
||||
jlong* ppids = NULL;
|
||||
jlong* stimes = NULL;
|
||||
jsize parentArraySize = 0;
|
||||
jsize arraySize = 0;
|
||||
jsize stimesSize = 0;
|
||||
jsize count = 0;
|
||||
|
||||
arraySize = (*env)->GetArrayLength(env, jarray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
if (jparentArray != NULL) {
|
||||
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != parentArraySize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != stimesSize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const int chunk = 100;
|
||||
struct procentry64 ProcessBuffer[chunk];
|
||||
pid_t idxptr = 0;
|
||||
int i, num = 0;
|
||||
|
||||
do { // Block to break out of on Exception
|
||||
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
|
||||
if (pids == NULL) {
|
||||
break;
|
||||
}
|
||||
if (jparentArray != NULL) {
|
||||
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
|
||||
if (ppids == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
|
||||
if (stimes == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((num = getprocs64(ProcessBuffer, sizeof(struct procentry64), NULL,
|
||||
sizeof(struct fdsinfo64), &idxptr, chunk)) != -1) {
|
||||
for (i = 0; i < num; i++) {
|
||||
pid_t childpid = (pid_t) ProcessBuffer[i].pi_pid;
|
||||
pid_t ppid = (pid_t) ProcessBuffer[i].pi_ppid;
|
||||
|
||||
// Get the parent pid, and start time
|
||||
if (pid == 0 || ppid == pid) {
|
||||
if (count < arraySize) {
|
||||
// Only store if it fits
|
||||
pids[count] = (jlong) childpid;
|
||||
|
||||
if (ppids != NULL) {
|
||||
// Store the parentPid
|
||||
ppids[count] = (jlong) ppid;
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
// Store the process start time
|
||||
stimes[count] = ((jlong) ProcessBuffer[i].pi_start) * 1000;;
|
||||
}
|
||||
}
|
||||
count++; // Count to tabulate size needed
|
||||
}
|
||||
}
|
||||
if (num < chunk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (pids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
|
||||
}
|
||||
if (ppids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
|
||||
}
|
||||
|
||||
if (num == -1) {
|
||||
JNU_ThrowByNameWithLastError(env,
|
||||
"java/lang/RuntimeException", "Unable to retrieve Process info");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If more pids than array had size for; count will be greater than array size
|
||||
return count;
|
||||
}
|
||||
|
||||
pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid, jlong *total, jlong *start) {
|
||||
pid_t the_pid = pid;
|
||||
struct procentry64 ProcessBuffer;
|
||||
|
||||
if (getprocs64(&ProcessBuffer, sizeof(ProcessBuffer), NULL, sizeof(struct fdsinfo64), &the_pid, 1) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate the pid before returning the info
|
||||
if (kill(pid, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*total = ((ProcessBuffer.pi_ru.ru_utime.tv_sec + ProcessBuffer.pi_ru.ru_stime.tv_sec) * 1000000000L) +
|
||||
((ProcessBuffer.pi_ru.ru_utime.tv_usec + ProcessBuffer.pi_ru.ru_stime.tv_usec));
|
||||
|
||||
*start = ProcessBuffer.pi_start * (jlong)1000;
|
||||
|
||||
return (pid_t) ProcessBuffer.pi_ppid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the 'psinfo_t' data from "/proc/%d/psinfo".
|
||||
* Returns 0 on success and -1 on error.
|
||||
*/
|
||||
static int getPsinfo(pid_t pid, psinfo_t *psinfo) {
|
||||
FILE* fp;
|
||||
char fn[32];
|
||||
size_t ret;
|
||||
|
||||
/*
|
||||
* Try to open /proc/%d/psinfo
|
||||
*/
|
||||
snprintf(fn, sizeof fn, "/proc/%d/psinfo", pid);
|
||||
fp = fopen(fn, "r");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fread(psinfo, 1, sizeof(psinfo_t), fp);
|
||||
fclose(fp);
|
||||
if (ret < sizeof(psinfo_t)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
|
||||
psinfo_t psinfo;
|
||||
char prargs[PRARGSZ + 1];
|
||||
jstring cmdexe = NULL;
|
||||
|
||||
/*
|
||||
* Now try to open /proc/%d/psinfo
|
||||
*/
|
||||
if (getPsinfo(pid, &psinfo) < 0) {
|
||||
unix_fillArgArray(env, jinfo, 0, NULL, NULL, cmdexe, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
unix_getUserInfo(env, jinfo, psinfo.pr_uid);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
/*
|
||||
* Now read psinfo.pr_psargs which contains the first PRARGSZ characters of the
|
||||
* argument list (i.e. arg[0] arg[1] ...). Unfortunately, PRARGSZ is usually set
|
||||
* to 80 characters only. Nevertheless it's better than nothing :)
|
||||
*/
|
||||
strncpy(prargs, psinfo.pr_psargs, PRARGSZ);
|
||||
prargs[PRARGSZ] = '\0';
|
||||
if (prargs[0] == '\0') {
|
||||
/* If psinfo.pr_psargs didn't contain any strings, use psinfo.pr_fname
|
||||
* (which only contains the last component of exec()ed pathname) as a
|
||||
* last resort. This is true for AIX kernel processes for example.
|
||||
*/
|
||||
strncpy(prargs, psinfo.pr_fname, PRARGSZ);
|
||||
prargs[PRARGSZ] = '\0';
|
||||
}
|
||||
unix_fillArgArray(env, jinfo, 0, NULL, NULL, cmdexe,
|
||||
prargs[0] == '\0' ? NULL : prargs);
|
||||
}
|
||||
87
src/java.base/aix/native/libjli/java_md_aix.c
Normal file
87
src/java.base/aix/native/libjli/java_md_aix.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2019 SAP SE. 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.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ldr.h>
|
||||
|
||||
#include "java_md_aix.h"
|
||||
|
||||
static unsigned char dladdr_buffer[0x8000];
|
||||
|
||||
static int fill_dll_info(void) {
|
||||
return loadquery(L_GETINFO, dladdr_buffer, sizeof(dladdr_buffer));
|
||||
}
|
||||
|
||||
static int dladdr_dont_reload(void *addr, Dl_info *info) {
|
||||
const struct ld_info *p = (struct ld_info *)dladdr_buffer;
|
||||
memset((void *)info, 0, sizeof(Dl_info));
|
||||
for (;;) {
|
||||
if (addr >= p->ldinfo_textorg &&
|
||||
(char*)addr < (char*)(p->ldinfo_textorg) + p->ldinfo_textsize) {
|
||||
info->dli_fname = p->ldinfo_filename;
|
||||
return 1;
|
||||
}
|
||||
if (!p->ldinfo_next) {
|
||||
break;
|
||||
}
|
||||
p = (struct ld_info *)(((char *)p) + p->ldinfo_next);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dladdr(void *addr, Dl_info *info) {
|
||||
static int loaded = 0;
|
||||
int rc = 0;
|
||||
void *addr0;
|
||||
if (!addr) {
|
||||
return rc;
|
||||
}
|
||||
if (!loaded) {
|
||||
if (fill_dll_info() == -1)
|
||||
return rc;
|
||||
loaded = 1;
|
||||
}
|
||||
|
||||
// first try with addr on cached data
|
||||
rc = dladdr_dont_reload(addr, info);
|
||||
|
||||
// addr could be an AIX function descriptor, so try dereferenced version
|
||||
if (rc == 0) {
|
||||
addr0 = *((void **)addr);
|
||||
rc = dladdr_dont_reload(addr0, info);
|
||||
}
|
||||
|
||||
// if we had no success until now, maybe loadquery info is outdated.
|
||||
// refresh and retry
|
||||
if (rc == 0) {
|
||||
if (fill_dll_info() == -1)
|
||||
return rc;
|
||||
rc = dladdr_dont_reload(addr, info);
|
||||
if (rc == 0) {
|
||||
rc = dladdr_dont_reload(addr0, info);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
44
src/java.base/aix/native/libjli/java_md_aix.h
Normal file
44
src/java.base/aix/native/libjli/java_md_aix.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2026 SAP SE. 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.
|
||||
*/
|
||||
|
||||
#ifndef JAVA_MD_AIX_H
|
||||
#define JAVA_MD_AIX_H
|
||||
|
||||
/*
|
||||
* Very limited AIX port of dladdr() for libjli.so.
|
||||
*
|
||||
* We try to mimic dladdr(3) on Linux (see https://linux.die.net/man/3/dladdr)
|
||||
* dladdr(3) is not POSIX but a GNU extension, and is not available on AIX.
|
||||
*
|
||||
* We only support Dl_info.dli_fname here as this is the only thing that is
|
||||
* used of it by libjli.so. A more comprehensive port of dladdr can be found
|
||||
* in the hotspot implementation which is not available at this place, though.
|
||||
*/
|
||||
|
||||
#include "dl_info.h"
|
||||
|
||||
int dladdr(void *addr, Dl_info *info);
|
||||
|
||||
#endif /* JAVA_MD_AIX_H */
|
||||
232
src/java.base/aix/native/libnio/MappedMemoryUtils.c
Normal file
232
src/java.base/aix/native/libnio/MappedMemoryUtils.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2024, 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "java_nio_MappedMemoryUtils.h"
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef char mincore_vec_t;
|
||||
|
||||
static long calculate_number_of_pages_in_range(void* address, size_t len, size_t pagesize) {
|
||||
uintptr_t address_unaligned = (uintptr_t) address;
|
||||
uintptr_t address_aligned = address_unaligned & (~(pagesize - 1));
|
||||
size_t len2 = len + (address_unaligned - address_aligned);
|
||||
long numPages = (len2 + pagesize - 1) / pagesize;
|
||||
return numPages;
|
||||
}
|
||||
|
||||
jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len, jlong numPages)
|
||||
{
|
||||
jboolean loaded = JNI_TRUE;
|
||||
int result = 0;
|
||||
long i = 0;
|
||||
void *a = (void *) jlong_to_ptr(address);
|
||||
mincore_vec_t* vec = NULL;
|
||||
|
||||
/* See JDK-8186665 */
|
||||
size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
|
||||
if ((long)pagesize == -1) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
numPages = (jlong) calculate_number_of_pages_in_range(a, len, pagesize);
|
||||
|
||||
/* Include space for one sentinel byte at the end of the buffer
|
||||
* to catch overflows. */
|
||||
vec = (mincore_vec_t*) malloc(numPages + 1);
|
||||
|
||||
if (vec == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
vec[numPages] = '\x7f'; /* Write sentinel. */
|
||||
result = mincore(a, (size_t)len, vec);
|
||||
assert(vec[numPages] == '\x7f'); /* Check sentinel. */
|
||||
|
||||
if (result == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "mincore failed");
|
||||
free(vec);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
for (i=0; i<numPages; i++) {
|
||||
if (vec[i] == 0) {
|
||||
loaded = JNI_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(vec);
|
||||
return loaded;
|
||||
}
|
||||
|
||||
|
||||
void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
char *a = (char *)jlong_to_ptr(address);
|
||||
int result = madvise((caddr_t)a, (size_t)len, MADV_WILLNEED);
|
||||
if (result == -1) {
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env, "madvise with advise MADV_WILLNEED failed");
|
||||
}
|
||||
}
|
||||
|
||||
void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
char *a = (char *)jlong_to_ptr(address);
|
||||
int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED);
|
||||
if (result == -1) {
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env, "madvise with advise MADV_DONTNEED failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void set_error_if_shared(JNIEnv* env, prmap_t* map_entry)
|
||||
{
|
||||
if (map_entry->pr_mflags & MA_SHARED) {
|
||||
// MA_SHARED => MAP_SHARED => !MAP_PRIVATE. This error is valid and should be thrown.
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed (MAP_SHARED)");
|
||||
return;
|
||||
} else {
|
||||
// O.W. MAP_PRIVATE or no flag was specified and EINVAL is the expected behaviour.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_proc_map_array(JNIEnv* env, FILE* proc_file, prmap_t* map_entry, void* end_address)
|
||||
{
|
||||
while (!feof(proc_file)) {
|
||||
memset(map_entry, '\0', sizeof(prmap_t));
|
||||
fread((char*)map_entry, sizeof(prmap_t), 1, proc_file);
|
||||
if (ferror(proc_file)) {
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env,
|
||||
"msync with parameter MS_SYNC failed (could not read /proc/<pid>/map)");
|
||||
return;
|
||||
} else if (map_entry->pr_vaddr <= end_address &&
|
||||
(uint64_t)end_address <= (uint64_t)map_entry->pr_vaddr + map_entry->pr_size) {
|
||||
set_error_if_shared(env, map_entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env,
|
||||
"msync with parameter MS_SYNC failed (address not found)");
|
||||
}
|
||||
|
||||
// '/proc/' + <pid> + '/map' + '\0'
|
||||
#define PFNAME_LEN 32
|
||||
static void check_aix_einval(JNIEnv* env, void* end_address)
|
||||
{
|
||||
// If EINVAL is set for a mmap address on AIX, additional validation is required.
|
||||
// AIX will set EINVAL when msync is called on a mmap address that didn't receive MAP_SHARED
|
||||
// as a flag (since MAP_PRIVATE is the default).
|
||||
// https://www.ibm.com/docs/en/aix/7.2?topic=m-msync-subroutine
|
||||
|
||||
FILE* proc_file;
|
||||
{
|
||||
char* fname = (char*) malloc(sizeof(char) * PFNAME_LEN);
|
||||
if (fname == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
pid_t the_pid = getpid();
|
||||
jio_snprintf(fname, PFNAME_LEN, "/proc/%d/map", the_pid);
|
||||
proc_file = fopen(fname, "r");
|
||||
free(fname);
|
||||
}
|
||||
if (!proc_file) {
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env,
|
||||
"msync with parameter MS_SYNC failed (could not open /proc/<pid>/map)");
|
||||
return;
|
||||
}
|
||||
{
|
||||
prmap_t* map_entry = (prmap_t*) malloc(sizeof(prmap_t));
|
||||
if (map_entry == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
fclose(proc_file);
|
||||
return;
|
||||
}
|
||||
check_proc_map_array(env, proc_file, map_entry, end_address);
|
||||
free(map_entry);
|
||||
}
|
||||
fclose(proc_file);
|
||||
}
|
||||
|
||||
// Normally we would just let msync handle this, but since we'll be (potentially) ignoring
|
||||
// the error code returned by msync, we check the args before the call instead.
|
||||
static int validate_msync_address(size_t address)
|
||||
{
|
||||
size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
|
||||
if (address % pagesize != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||
jlong address, jlong len)
|
||||
{
|
||||
void* a = (void *)jlong_to_ptr(address);
|
||||
if (validate_msync_address((size_t)a) > 0) {
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env,
|
||||
"msync with parameter MS_SYNC failed (arguments invalid)");
|
||||
return;
|
||||
}
|
||||
int result = msync(a, (size_t)len, MS_SYNC);
|
||||
if (result == -1) {
|
||||
void* end_address = (void*)jlong_to_ptr(address + len);
|
||||
if (errno == EINVAL) {
|
||||
check_aix_einval(env, end_address);
|
||||
return;
|
||||
}
|
||||
JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed");
|
||||
}
|
||||
}
|
||||
|
||||
#define FD "Ljava/io/FileDescriptor;"
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0},
|
||||
{"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0},
|
||||
{"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0},
|
||||
{"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0},
|
||||
};
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls)
|
||||
{
|
||||
(*env)->RegisterNatives(env, cls,
|
||||
methods, sizeof(methods)/sizeof(methods[0]));
|
||||
}
|
||||
129
src/java.base/aix/native/libnio/ch/FileDispatcherImpl.c
Normal file
129
src/java.base/aix/native/libnio/ch/FileDispatcherImpl.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2022, 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.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jlong.h"
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
#include "java_lang_Integer.h"
|
||||
#include <assert.h>
|
||||
|
||||
static jlong
|
||||
handle(JNIEnv *env, jlong rv, char *msg)
|
||||
{
|
||||
if (rv >= 0)
|
||||
return rv;
|
||||
if (errno == EINTR)
|
||||
return IOS_INTERRUPTED;
|
||||
JNU_ThrowIOExceptionWithLastError(env, msg);
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
// AIX
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
|
||||
jobject fdo, jboolean md)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
int result = 0;
|
||||
|
||||
if (md == JNI_FALSE) {
|
||||
result = fdatasync(fd);
|
||||
} else {
|
||||
/* Calling fsync on a file descriptor that is opened only for
|
||||
* reading results in an error ("EBADF: The FileDescriptor parameter is
|
||||
* not a valid file descriptor open for writing.").
|
||||
* However, at this point it is not possibly anymore to read the
|
||||
* 'writable' attribute of the corresponding file channel so we have to
|
||||
* use 'fcntl'.
|
||||
*/
|
||||
int getfl = fcntl(fd, F_GETFL);
|
||||
if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) {
|
||||
return 0;
|
||||
}
|
||||
result = fsync(fd);
|
||||
}
|
||||
|
||||
return handle(env, result, "Force failed");
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this,
|
||||
jobject srcFDO,
|
||||
jlong position, jlong count,
|
||||
jobject dstFDO, jboolean append)
|
||||
{
|
||||
jint srcFD = fdval(env, srcFDO);
|
||||
jint dstFD = fdval(env, dstFDO);
|
||||
|
||||
jlong max = (jlong)java_lang_Integer_MAX_VALUE;
|
||||
struct sf_parms sf_iobuf;
|
||||
jlong result;
|
||||
|
||||
if (position > max)
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
|
||||
if (count > max)
|
||||
count = max;
|
||||
|
||||
memset(&sf_iobuf, 0, sizeof(sf_iobuf));
|
||||
sf_iobuf.file_descriptor = srcFD;
|
||||
sf_iobuf.file_offset = (off_t)position;
|
||||
sf_iobuf.file_bytes = count;
|
||||
|
||||
result = send_file(&dstFD, &sf_iobuf, SF_SYNC_CACHE);
|
||||
|
||||
/* AIX send_file() will return 0 when this operation complete successfully,
|
||||
* return 1 when partial bytes transferred and return -1 when an error has
|
||||
* occurred.
|
||||
*/
|
||||
if (result == -1) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
return IOS_UNAVAILABLE;
|
||||
if ((errno == EINVAL) && ((ssize_t)count >= 0))
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
if (errno == EINTR)
|
||||
return IOS_INTERRUPTED;
|
||||
if (errno == ENOTSOCK)
|
||||
return IOS_UNSUPPORTED;
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
if (sf_iobuf.bytes_sent > 0)
|
||||
return (jlong)sf_iobuf.bytes_sent;
|
||||
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
}
|
||||
168
src/java.base/aix/native/libnio/ch/Pollset.c
Normal file
168
src/java.base/aix/native/libnio/ch/Pollset.c
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2024 SAP SE. 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include "sun_nio_ch_Pollset.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/pollset.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef pollset_t pollset_create_func(int maxfd);
|
||||
typedef int pollset_destroy_func(pollset_t ps);
|
||||
typedef int pollset_ctl_func(pollset_t ps, struct poll_ctl *pollctl_array, int array_length);
|
||||
typedef int pollset_poll_func(pollset_t ps, struct pollfd *polldata_array, int array_length, int timeout);
|
||||
static pollset_create_func* _pollset_create = NULL;
|
||||
static pollset_destroy_func* _pollset_destroy = NULL;
|
||||
static pollset_ctl_func* _pollset_ctl = NULL;
|
||||
static pollset_poll_func* _pollset_poll = NULL;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_Pollset_init(JNIEnv* env, jclass this) {
|
||||
_pollset_create = (pollset_create_func*) dlsym(RTLD_DEFAULT, "pollset_create");
|
||||
_pollset_destroy = (pollset_destroy_func*) dlsym(RTLD_DEFAULT, "pollset_destroy");
|
||||
_pollset_ctl = (pollset_ctl_func*) dlsym(RTLD_DEFAULT, "pollset_ctl");
|
||||
_pollset_poll = (pollset_poll_func*) dlsym(RTLD_DEFAULT, "pollset_poll");
|
||||
if (_pollset_create == NULL || _pollset_destroy == NULL ||
|
||||
_pollset_ctl == NULL || _pollset_poll == NULL) {
|
||||
JNU_ThrowInternalError(env, "unable to get address of pollset functions");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_Pollset_eventSize(JNIEnv* env, jclass this) {
|
||||
return sizeof(struct pollfd);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_Pollset_eventsOffset(JNIEnv* env, jclass this) {
|
||||
return offsetof(struct pollfd, events);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_Pollset_reventsOffset(JNIEnv* env, jclass this) {
|
||||
return offsetof(struct pollfd, revents);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_Pollset_fdOffset(JNIEnv* env, jclass this) {
|
||||
return offsetof(struct pollfd, fd);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_Pollset_pollsetCreate(JNIEnv *env, jclass c) {
|
||||
/* pollset_create can take the maximum number of fds, but we
|
||||
* cannot predict this number so we leave it at OPEN_MAX. */
|
||||
pollset_t ps = _pollset_create(-1);
|
||||
if (ps < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "pollset_create failed");
|
||||
}
|
||||
return (int)ps;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_Pollset_pollsetCtl(JNIEnv *env, jclass c, jint ps,
|
||||
jint opcode, jint fd, jint events) {
|
||||
struct poll_ctl event;
|
||||
int res;
|
||||
|
||||
event.cmd = opcode;
|
||||
event.events = events;
|
||||
event.fd = fd;
|
||||
|
||||
RESTARTABLE(_pollset_ctl((pollset_t)ps, &event, 1 /* length */), res);
|
||||
|
||||
return (res == 0) ? 0 : errno;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_Pollset_pollsetPoll(JNIEnv *env, jclass c,
|
||||
jint ps, jlong address, jint numfds, jint timeout) {
|
||||
struct pollfd *events = jlong_to_ptr(address);
|
||||
int res;
|
||||
|
||||
RESTARTABLE(_pollset_poll(ps, events, numfds, timeout), res);
|
||||
if (res < 0) {
|
||||
perror("pollset_poll failed");
|
||||
JNU_ThrowIOExceptionWithLastError(env, "pollset_poll failed");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_Pollset_pollsetDestroy(JNIEnv *env, jclass c, jint ps) {
|
||||
int res;
|
||||
RESTARTABLE(_pollset_destroy((pollset_t)ps), res);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_Pollset_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
|
||||
int sp[2];
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
|
||||
} else {
|
||||
jint res[2];
|
||||
res[0] = (jint)sp[0];
|
||||
res[1] = (jint)sp[1];
|
||||
(*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_Pollset_interrupt(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
int buf[1];
|
||||
buf[0] = 1;
|
||||
RESTARTABLE(write(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "write failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_Pollset_drain1(JNIEnv *env, jclass cl, jint fd) {
|
||||
int res;
|
||||
char buf[1];
|
||||
RESTARTABLE(read(fd, buf, 1), res);
|
||||
if (res < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_Pollset_close0(JNIEnv *env, jclass c, jint fd) {
|
||||
int res;
|
||||
RESTARTABLE(close(fd), res);
|
||||
}
|
||||
235
src/java.base/aix/native/libnio/fs/AixNativeDispatcher.c
Normal file
235
src/java.base/aix/native/libnio/fs/AixNativeDispatcher.c
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2023 SAP SE. 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mntctl.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
#include "sun_nio_fs_AixNativeDispatcher.h"
|
||||
|
||||
static jfieldID entry_name;
|
||||
static jfieldID entry_dir;
|
||||
static jfieldID entry_fstype;
|
||||
static jfieldID entry_options;
|
||||
|
||||
static jclass entry_cls;
|
||||
|
||||
/**
|
||||
* Call this to throw an internal UnixException when a system/library
|
||||
* call fails
|
||||
*/
|
||||
static void throwUnixException(JNIEnv* env, int errnum) {
|
||||
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
|
||||
"(I)V", errnum);
|
||||
if (x != NULL) {
|
||||
(*env)->Throw(env, x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_AixNativeDispatcher_init(JNIEnv* env, jclass this)
|
||||
{
|
||||
jclass clazz;
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
|
||||
CHECK_NULL(clazz);
|
||||
entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
|
||||
CHECK_NULL(entry_name);
|
||||
entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
|
||||
CHECK_NULL(entry_dir);
|
||||
entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
|
||||
CHECK_NULL(entry_fstype);
|
||||
entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
|
||||
CHECK_NULL(entry_options);
|
||||
entry_cls = (*env)->NewGlobalRef(env, clazz);
|
||||
if (entry_cls == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special implementation of getextmntent (see SolarisNativeDispatcher.c)
|
||||
* that returns all entries at once.
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_sun_nio_fs_AixNativeDispatcher_getmntctl(JNIEnv* env, jclass this)
|
||||
{
|
||||
int must_free_buf = 0;
|
||||
char stack_buf[1024];
|
||||
char* buffer = stack_buf;
|
||||
size_t buffer_size = 1024;
|
||||
int num_entries;
|
||||
int i;
|
||||
jobjectArray ret;
|
||||
struct vmount * vm;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
num_entries = mntctl(MCTL_QUERY, buffer_size, buffer);
|
||||
if (num_entries != 0) {
|
||||
break;
|
||||
}
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
buffer_size *= 8;
|
||||
buffer = malloc(buffer_size);
|
||||
if (buffer == NULL) {
|
||||
throwUnixException(env, errno);
|
||||
return NULL;
|
||||
}
|
||||
must_free_buf = 1;
|
||||
}
|
||||
/* Treat zero entries like errors. */
|
||||
if (num_entries <= 0) {
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
throwUnixException(env, errno);
|
||||
return NULL;
|
||||
}
|
||||
ret = (*env)->NewObjectArray(env, num_entries, entry_cls, NULL);
|
||||
if (ret == NULL) {
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
vm = (struct vmount*)buffer;
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
jsize len;
|
||||
jbyteArray bytes;
|
||||
const char* fstype;
|
||||
/* We set all relevant attributes so there is no need to call constructor. */
|
||||
jobject entry = (*env)->AllocObject(env, entry_cls);
|
||||
if (entry == NULL) {
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetObjectArrayElement(env, ret, i, entry);
|
||||
|
||||
/* vm->vmt_data[...].vmt_size is 32 bit aligned and also includes NULL byte. */
|
||||
/* Since we only need the characters, it is necessary to check string size manually. */
|
||||
len = strlen((char*)vm + vm->vmt_data[VMT_OBJECT].vmt_off);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL) {
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_OBJECT].vmt_off));
|
||||
(*env)->SetObjectField(env, entry, entry_name, bytes);
|
||||
|
||||
len = strlen((char*)vm + vm->vmt_data[VMT_STUB].vmt_off);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL) {
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_STUB].vmt_off));
|
||||
(*env)->SetObjectField(env, entry, entry_dir, bytes);
|
||||
|
||||
switch (vm->vmt_gfstype) {
|
||||
case MNT_J2:
|
||||
fstype = "jfs2";
|
||||
break;
|
||||
case MNT_NAMEFS:
|
||||
fstype = "namefs";
|
||||
break;
|
||||
case MNT_NFS:
|
||||
fstype = "nfs";
|
||||
break;
|
||||
case MNT_JFS:
|
||||
fstype = "jfs";
|
||||
break;
|
||||
case MNT_CDROM:
|
||||
fstype = "cdrom";
|
||||
break;
|
||||
case MNT_PROCFS:
|
||||
fstype = "procfs";
|
||||
break;
|
||||
case MNT_NFS3:
|
||||
fstype = "nfs3";
|
||||
break;
|
||||
case MNT_AUTOFS:
|
||||
fstype = "autofs";
|
||||
break;
|
||||
case MNT_UDF:
|
||||
fstype = "udfs";
|
||||
break;
|
||||
case MNT_NFS4:
|
||||
fstype = "nfs4";
|
||||
break;
|
||||
case MNT_CIFS:
|
||||
fstype = "smbfs";
|
||||
break;
|
||||
default:
|
||||
fstype = "unknown";
|
||||
}
|
||||
len = strlen(fstype);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL) {
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
|
||||
(*env)->SetObjectField(env, entry, entry_fstype, bytes);
|
||||
|
||||
len = strlen((char*)vm + vm->vmt_data[VMT_ARGS].vmt_off);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL) {
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_ARGS].vmt_off));
|
||||
(*env)->SetObjectField(env, entry, entry_options, bytes);
|
||||
|
||||
/* goto the next vmount structure: */
|
||||
vm = (struct vmount *)((char *)vm + vm->vmt_length);
|
||||
}
|
||||
|
||||
if (must_free_buf) {
|
||||
free(buffer);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
208
src/java.base/aix/native/libsyslookup/syslookup.c
Normal file
208
src/java.base/aix/native/libsyslookup/syslookup.c
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, IBM Corp.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Note: the include below is not strictly required, as dependencies will be pulled using linker flags.
|
||||
// Adding at least one #include removes unwanted warnings on some platforms.
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "jni_util.h"
|
||||
|
||||
DEF_STATIC_JNI_OnLoad
|
||||
|
||||
// Addresses of functions to be referenced using static linking.
|
||||
void* funcs[] = {
|
||||
//string.h
|
||||
&strlen,
|
||||
&strcat,
|
||||
//math.h
|
||||
&abs,
|
||||
&fabs,
|
||||
&fabsf,
|
||||
&fabsl,
|
||||
&fmod,
|
||||
&fmodf,
|
||||
&fmodl,
|
||||
&remainder,
|
||||
&remainderf,
|
||||
&remainderl,
|
||||
&remquo,
|
||||
&remquof,
|
||||
&remquol,
|
||||
&fma,
|
||||
&fmaf,
|
||||
&fmal,
|
||||
&fmax,
|
||||
&fmaxf,
|
||||
&fmaxl,
|
||||
&fmin,
|
||||
&fminf,
|
||||
&fminl,
|
||||
&fdim,
|
||||
&fdimf,
|
||||
&fdiml,
|
||||
&nan,
|
||||
&nanf,
|
||||
&nanl,
|
||||
&exp,
|
||||
&expf,
|
||||
&expl,
|
||||
&exp2,
|
||||
&exp2f,
|
||||
&exp2l,
|
||||
&expm1,
|
||||
&expm1f,
|
||||
&expm1l,
|
||||
&log,
|
||||
&logf,
|
||||
&logl,
|
||||
&log10,
|
||||
&log10f,
|
||||
&log10l,
|
||||
&log2,
|
||||
&log2f,
|
||||
&log2l,
|
||||
&log1p,
|
||||
&log1pf,
|
||||
&log1pl,
|
||||
&pow,
|
||||
&powf,
|
||||
&powl,
|
||||
&sqrt,
|
||||
&sqrtf,
|
||||
&sqrtl,
|
||||
&cbrt,
|
||||
&cbrtf,
|
||||
&cbrtl,
|
||||
&hypot,
|
||||
&hypotf,
|
||||
&hypotl,
|
||||
&sin,
|
||||
&sinf,
|
||||
&sinl,
|
||||
&cos,
|
||||
&cosf,
|
||||
&cosl,
|
||||
&tan,
|
||||
&tanf,
|
||||
&tanl,
|
||||
&asin,
|
||||
&asinf,
|
||||
&asinl,
|
||||
&acos,
|
||||
&acosf,
|
||||
&acosl,
|
||||
&atan,
|
||||
&atanf,
|
||||
&atanl,
|
||||
&atan2,
|
||||
&atan2f,
|
||||
&atan2l,
|
||||
&sinh,
|
||||
&sinhf,
|
||||
&sinhl,
|
||||
&cosh,
|
||||
&coshf,
|
||||
&coshl,
|
||||
&tanh,
|
||||
&tanhf,
|
||||
&tanhl,
|
||||
&asinh,
|
||||
&asinhf,
|
||||
&asinhl,
|
||||
&acosh,
|
||||
&acoshf,
|
||||
&acoshl,
|
||||
&atanh,
|
||||
&atanhf,
|
||||
&atanhl,
|
||||
&erf,
|
||||
&erff,
|
||||
&erfl,
|
||||
&erfc,
|
||||
&erfcf,
|
||||
&erfcl,
|
||||
&tgamma,
|
||||
&tgammaf,
|
||||
&tgammal,
|
||||
&lgamma,
|
||||
&lgammaf,
|
||||
&lgammal,
|
||||
&ceil,
|
||||
&ceilf,
|
||||
&ceill,
|
||||
&floor,
|
||||
&floorf,
|
||||
&floorl,
|
||||
&trunc,
|
||||
&truncf,
|
||||
&truncl,
|
||||
&round,
|
||||
&roundf,
|
||||
&roundl,
|
||||
&lround,
|
||||
&lroundf,
|
||||
&lroundl,
|
||||
&llround,
|
||||
&llroundf,
|
||||
&llroundl,
|
||||
&nearbyint,
|
||||
&nearbyintf,
|
||||
&nearbyintl,
|
||||
&rintf,
|
||||
&rintl,
|
||||
&lrint,
|
||||
&lrintf,
|
||||
&lrintl,
|
||||
&llrint,
|
||||
&llrintf,
|
||||
&llrintl,
|
||||
&frexpf,
|
||||
&ldexpf,
|
||||
&modff,
|
||||
&scalbn,
|
||||
&scalbnf,
|
||||
&scalbnl,
|
||||
&scalbln,
|
||||
&scalblnf,
|
||||
&scalblnl,
|
||||
&ilogb,
|
||||
&ilogbf,
|
||||
&ilogbl,
|
||||
&logb,
|
||||
&logbf,
|
||||
&logbl,
|
||||
&nextafter,
|
||||
&nextafterf,
|
||||
&nextafterl,
|
||||
&nexttoward,
|
||||
&nexttowardf,
|
||||
&nexttowardl,
|
||||
©sign,
|
||||
©signf,
|
||||
©signl,
|
||||
&isnan
|
||||
};
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* 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 jdk.internal.platform;
|
||||
|
||||
/**
|
||||
* Data structure to hold info from /proc/self/cgroup,
|
||||
* /proc/cgroups and /proc/self/mountinfo
|
||||
*
|
||||
* man 7 cgroups
|
||||
*
|
||||
* @see CgroupSubsystemFactory
|
||||
*/
|
||||
public class CgroupInfo {
|
||||
|
||||
private final String name;
|
||||
private final int hierarchyId;
|
||||
private final boolean enabled;
|
||||
private String mountPoint;
|
||||
private String mountRoot;
|
||||
private String cgroupPath;
|
||||
|
||||
private CgroupInfo(String name, int hierarchyId, boolean enabled) {
|
||||
this.name = name;
|
||||
this.hierarchyId = hierarchyId;
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getHierarchyId() {
|
||||
return hierarchyId;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String getMountPoint() {
|
||||
return mountPoint;
|
||||
}
|
||||
|
||||
public void setMountPoint(String mountPoint) {
|
||||
this.mountPoint = mountPoint;
|
||||
}
|
||||
|
||||
public String getMountRoot() {
|
||||
return mountRoot;
|
||||
}
|
||||
|
||||
public void setMountRoot(String mountRoot) {
|
||||
this.mountRoot = mountRoot;
|
||||
}
|
||||
|
||||
public String getCgroupPath() {
|
||||
return cgroupPath;
|
||||
}
|
||||
|
||||
public void setCgroupPath(String cgroupPath) {
|
||||
this.cgroupPath = cgroupPath;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a CgroupInfo instance from a line in /proc/cgroups.
|
||||
* Comment token (hash) is handled by the caller.
|
||||
*
|
||||
* Example (annotated):
|
||||
*
|
||||
* #subsys_name hierarchy num_cgroups enabled
|
||||
* cpuset 10 1 1 (a)
|
||||
* cpu 7 8 1 (b)
|
||||
* [...]
|
||||
*
|
||||
* Line (a) would yield:
|
||||
* info = new CgroupInfo("cpuset", 10, true);
|
||||
* return info;
|
||||
* Line (b) results in:
|
||||
* info = new CgroupInfo("cpu", 7, true);
|
||||
* return info;
|
||||
*
|
||||
*
|
||||
* See CgroupSubsystemFactory.determineType()
|
||||
*
|
||||
*/
|
||||
static CgroupInfo fromCgroupsLine(String line) {
|
||||
String[] tokens = line.split("\\s+");
|
||||
if (tokens.length != 4) {
|
||||
return null;
|
||||
}
|
||||
// discard 3'rd field, num_cgroups
|
||||
return new CgroupInfo(tokens[0] /* name */,
|
||||
Integer.parseInt(tokens[1]) /* hierarchyId */,
|
||||
(Integer.parseInt(tokens[3]) == 1) /* enabled */);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2021, Red Hat Inc.
|
||||
* 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 jdk.internal.platform;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class CgroupMetrics implements Metrics {
|
||||
|
||||
private final CgroupSubsystem subsystem;
|
||||
|
||||
CgroupMetrics(CgroupSubsystem subsystem) {
|
||||
this.subsystem = Objects.requireNonNull(subsystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContainerized() {
|
||||
return isContainerized0();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProvider() {
|
||||
return subsystem.getProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuUsage() {
|
||||
return subsystem.getCpuUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getPerCpuUsage() {
|
||||
return subsystem.getPerCpuUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuUserUsage() {
|
||||
return subsystem.getCpuUserUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuSystemUsage() {
|
||||
return subsystem.getCpuSystemUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuPeriod() {
|
||||
return subsystem.getCpuPeriod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuQuota() {
|
||||
return subsystem.getCpuQuota();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuShares() {
|
||||
return subsystem.getCpuShares();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuNumPeriods() {
|
||||
return subsystem.getCpuNumPeriods();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuNumThrottled() {
|
||||
return subsystem.getCpuNumThrottled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuThrottledTime() {
|
||||
return subsystem.getCpuThrottledTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEffectiveCpuCount() {
|
||||
return subsystem.getEffectiveCpuCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getCpuSetCpus() {
|
||||
return subsystem.getCpuSetCpus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getEffectiveCpuSetCpus() {
|
||||
return subsystem.getEffectiveCpuSetCpus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getCpuSetMems() {
|
||||
return subsystem.getCpuSetMems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getEffectiveCpuSetMems() {
|
||||
return subsystem.getEffectiveCpuSetMems();
|
||||
}
|
||||
|
||||
public long getMemoryFailCount() {
|
||||
return subsystem.getMemoryFailCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryLimit() {
|
||||
long subsMem = subsystem.getMemoryLimit();
|
||||
long systemTotal = getTotalMemorySize0();
|
||||
assert(systemTotal > 0);
|
||||
// Catch the cgroup memory limit exceeding host physical memory.
|
||||
// Treat this as unlimited.
|
||||
if (subsMem >= systemTotal) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
return subsMem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryUsage() {
|
||||
return subsystem.getMemoryUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTcpMemoryUsage() {
|
||||
return subsystem.getTcpMemoryUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryAndSwapLimit() {
|
||||
long totalSystemMemSwap = getTotalMemorySize0() + getTotalSwapSize0();
|
||||
assert(totalSystemMemSwap > 0);
|
||||
// Catch the cgroup memory and swap limit exceeding host physical swap
|
||||
// and memory. Treat this case as unlimited.
|
||||
long subsSwapMem = subsystem.getMemoryAndSwapLimit();
|
||||
if (subsSwapMem >= totalSystemMemSwap) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
return subsSwapMem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryAndSwapUsage() {
|
||||
return subsystem.getMemoryAndSwapUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemorySoftLimit() {
|
||||
return subsystem.getMemorySoftLimit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPidsMax() {
|
||||
return subsystem.getPidsMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPidsCurrent() {
|
||||
return subsystem.getPidsCurrent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBlkIOServiceCount() {
|
||||
return subsystem.getBlkIOServiceCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBlkIOServiced() {
|
||||
return subsystem.getBlkIOServiced();
|
||||
}
|
||||
|
||||
public static Metrics getInstance() {
|
||||
if (!isUseContainerSupport()) {
|
||||
// Return null on -XX:-UseContainerSupport
|
||||
return null;
|
||||
}
|
||||
return CgroupSubsystemFactory.create();
|
||||
}
|
||||
|
||||
private static native boolean isUseContainerSupport();
|
||||
private static native boolean isContainerized0();
|
||||
private static native long getTotalMemorySize0();
|
||||
private static native long getTotalSwapSize0();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* 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 jdk.internal.platform;
|
||||
|
||||
/**
|
||||
* Marker interface for cgroup-based metrics
|
||||
*
|
||||
*/
|
||||
public interface CgroupSubsystem extends Metrics {
|
||||
|
||||
|
||||
default boolean isContainerized() {
|
||||
return false; // This default impl is never used
|
||||
}
|
||||
|
||||
/**
|
||||
* Returned for metrics of type long if the underlying implementation
|
||||
* has determined that no limit is being imposed.
|
||||
*/
|
||||
public static final long LONG_RETVAL_UNLIMITED = -1;
|
||||
public static final String MAX_VAL = "max";
|
||||
|
||||
public static long limitFromString(String strVal) {
|
||||
if (strVal == null || MAX_VAL.equals(strVal)) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
return Long.parseLong(strVal);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2022, Red Hat Inc.
|
||||
* Copyright (c) 2024, 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 jdk.internal.platform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Cgroup version agnostic controller logic
|
||||
*
|
||||
*/
|
||||
public interface CgroupSubsystemController {
|
||||
|
||||
public static final String EMPTY_STR = "";
|
||||
|
||||
public String path();
|
||||
|
||||
/**
|
||||
* getStringValue
|
||||
*
|
||||
* Return the first line of the file "param" argument from the controller.
|
||||
*
|
||||
* TODO: Consider using weak references for caching BufferedReader object.
|
||||
*
|
||||
* @param controller
|
||||
* @param param
|
||||
* @return Returns the contents of the file specified by param or null if
|
||||
* an error occurs.
|
||||
*/
|
||||
public static String getStringValue(CgroupSubsystemController controller, String param) {
|
||||
if (controller == null) return null;
|
||||
|
||||
Path filePath = Path.of(controller.path(), param);
|
||||
try (Stream<String> lines = Files.lines(filePath)) {
|
||||
Optional<String> firstLine = lines.findFirst();
|
||||
return firstLine.orElse(null);
|
||||
} catch (UncheckedIOException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an entry from file "param" within the "controller" directory path
|
||||
* which matches string "match". Applies "conversion" to the matching line.
|
||||
*
|
||||
* @param controller
|
||||
* @param param
|
||||
* @param match
|
||||
* @param conversion
|
||||
* @param defaultRetval
|
||||
* @return The long value as derived by applying "conversion" to the matching
|
||||
* line or "defaultRetval" if there was an error or no match found.
|
||||
*/
|
||||
public static long getLongValueMatchingLine(CgroupSubsystemController controller,
|
||||
String param,
|
||||
String match,
|
||||
Function<String, Long> conversion,
|
||||
long defaultRetval) {
|
||||
long retval = defaultRetval;
|
||||
if (controller == null) {
|
||||
return retval;
|
||||
}
|
||||
try {
|
||||
Path filePath = Path.of(controller.path(), param);
|
||||
List<String> lines = Files.readAllLines(filePath);
|
||||
for (String line : lines) {
|
||||
if (line.startsWith(match)) {
|
||||
retval = conversion.apply(line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore. Default is unlimited.
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long value from directory "controller" and file "param", by
|
||||
* applying "conversion" to the string value within the file.
|
||||
*
|
||||
* @param controller
|
||||
* @param param
|
||||
* @param conversion
|
||||
* @param defaultRetval
|
||||
* @return The converted long value or "defaultRetval" if there was an
|
||||
* error.
|
||||
*/
|
||||
public static long getLongValue(CgroupSubsystemController controller,
|
||||
String param,
|
||||
Function<String, Long> conversion,
|
||||
long defaultRetval) {
|
||||
String strval = getStringValue(controller, param);
|
||||
if (strval == null) return defaultRetval;
|
||||
return conversion.apply(strval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a double value from file "param" within "controller".
|
||||
*
|
||||
* @param controller
|
||||
* @param param
|
||||
* @param defaultRetval
|
||||
* @return The double value or "defaultRetval" if there was an error.
|
||||
*/
|
||||
public static double getDoubleValue(CgroupSubsystemController controller, String param, double defaultRetval) {
|
||||
String strval = getStringValue(controller, param);
|
||||
|
||||
if (strval == null) return defaultRetval;
|
||||
|
||||
double retval = Double.parseDouble(strval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* getLongEntry
|
||||
*
|
||||
* Return the long value from the line containing the string "entryname"
|
||||
* within file "param" in the "controller".
|
||||
*
|
||||
* TODO: Consider using weak references for caching BufferedReader object.
|
||||
*
|
||||
* @param controller
|
||||
* @param param
|
||||
* @param entryname
|
||||
* @return long value or "defaultRetval" if there was an error or no match
|
||||
* was found.
|
||||
*/
|
||||
public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname, long defaultRetval) {
|
||||
if (controller == null) return defaultRetval;
|
||||
|
||||
try (Stream<String> lines = Files.lines(Path.of(controller.path(), param))) {
|
||||
|
||||
Optional<String> result = lines.map(line -> line.split(" "))
|
||||
.filter(line -> (line.length == 2 &&
|
||||
line[0].equals(entryname)))
|
||||
.map(line -> line[1])
|
||||
.findFirst();
|
||||
|
||||
return result.isPresent() ? Long.parseLong(result.get()) : defaultRetval;
|
||||
} catch (UncheckedIOException | IOException e) {
|
||||
return defaultRetval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stringRangeToIntArray
|
||||
*
|
||||
* Convert a string in the form of 1,3-4,6 to an array of
|
||||
* integers containing all the numbers in the range.
|
||||
*
|
||||
* @param range
|
||||
* @return int[] containing a sorted list of numbers as represented by
|
||||
* the string range. Returns null if there was an error or the input
|
||||
* was an empty string.
|
||||
*/
|
||||
public static int[] stringRangeToIntArray(String range) {
|
||||
if (range == null || EMPTY_STR.equals(range)) return null;
|
||||
|
||||
ArrayList<Integer> results = new ArrayList<>();
|
||||
String strs[] = range.split(",");
|
||||
for (String str : strs) {
|
||||
if (str.contains("-")) {
|
||||
String lohi[] = str.split("-");
|
||||
// validate format
|
||||
if (lohi.length != 2) {
|
||||
continue;
|
||||
}
|
||||
int lo = Integer.parseInt(lohi[0]);
|
||||
int hi = Integer.parseInt(lohi[1]);
|
||||
for (int i = lo; i <= hi; i++) {
|
||||
results.add(i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
results.add(Integer.parseInt(str));
|
||||
}
|
||||
}
|
||||
|
||||
// sort results
|
||||
results.sort(null);
|
||||
|
||||
// convert ArrayList to primitive int array
|
||||
int[] ints = new int[results.size()];
|
||||
int i = 0;
|
||||
for (Integer n : results) {
|
||||
ints[i++] = n;
|
||||
}
|
||||
|
||||
return ints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a number from its string representation to a long.
|
||||
*
|
||||
* @param strval
|
||||
* @param overflowRetval
|
||||
* @param defaultRetval
|
||||
* @return The converted long value. "overflowRetval" is returned if the
|
||||
* string representation exceeds the range of type long.
|
||||
* "defaultRetval" is returned if another type of error occurred
|
||||
* during conversion.
|
||||
*/
|
||||
public static long convertStringToLong(String strval, long overflowRetval, long defaultRetval) {
|
||||
long retval = defaultRetval;
|
||||
if (strval == null) return retval;
|
||||
|
||||
try {
|
||||
retval = Long.parseLong(strval);
|
||||
} catch (NumberFormatException e) {
|
||||
// For some properties (e.g. memory.limit_in_bytes, cgroups v1) we may overflow
|
||||
// the range of signed long. In this case, return overflowRetval
|
||||
BigInteger b = new BigInteger(strval);
|
||||
if (b.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
|
||||
return overflowRetval;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2022, Red Hat Inc.
|
||||
* Copyright (c) 2024, 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 jdk.internal.platform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.platform.cgroupv1.CgroupV1Subsystem;
|
||||
import jdk.internal.platform.cgroupv2.CgroupV2Subsystem;
|
||||
|
||||
public class CgroupSubsystemFactory {
|
||||
|
||||
private static final String CPU_CTRL = "cpu";
|
||||
private static final String CPUACCT_CTRL = "cpuacct";
|
||||
private static final String CPUSET_CTRL = "cpuset";
|
||||
private static final String BLKIO_CTRL = "blkio";
|
||||
private static final String MEMORY_CTRL = "memory";
|
||||
private static final String PIDS_CTRL = "pids";
|
||||
|
||||
/*
|
||||
* From https://www.kernel.org/doc/Documentation/filesystems/proc.txt
|
||||
*
|
||||
* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
||||
* (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
|
||||
*
|
||||
* (1) mount ID: unique identifier of the mount (may be reused after umount)
|
||||
* (2) parent ID: ID of parent (or of self for the top of the mount tree)
|
||||
* (3) major:minor: value of st_dev for files on filesystem
|
||||
* (4) root: root of the mount within the filesystem
|
||||
* (5) mount point: mount point relative to the process's root
|
||||
* (6) mount options: per mount options
|
||||
* (7) optional fields: zero or more fields of the form "tag[:value]"
|
||||
* (8) separator: marks the end of the optional fields
|
||||
* (9) filesystem type: name of filesystem of the form "type[.subtype]"
|
||||
* (10) mount source: filesystem specific information or "none"
|
||||
* (11) super options: per super block options
|
||||
*/
|
||||
private static final Pattern MOUNTINFO_PATTERN = Pattern.compile(
|
||||
"^[^\\s]+\\s+[^\\s]+\\s+[^\\s]+\\s+" + // (1), (2), (3)
|
||||
"([^\\s]+)\\s+([^\\s]+)\\s+" + // (4), (5) - group 1, 2: root, mount point
|
||||
"[^-]+-\\s+" + // (6), (7), (8)
|
||||
"([^\\s]+)\\s+" + // (9) - group 3: filesystem type
|
||||
".*$"); // (10), (11)
|
||||
|
||||
static CgroupMetrics create() {
|
||||
Optional<CgroupTypeResult> optResult = null;
|
||||
try {
|
||||
optResult = determineType("/proc/self/mountinfo", "/proc/cgroups", "/proc/self/cgroup");
|
||||
} catch (IOException | UncheckedIOException e) {
|
||||
return null;
|
||||
}
|
||||
return create(optResult);
|
||||
}
|
||||
|
||||
public static CgroupMetrics create(Optional<CgroupTypeResult> optResult) {
|
||||
if (optResult.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
CgroupTypeResult result = optResult.get();
|
||||
|
||||
// If no controller is enabled, return no metrics.
|
||||
if (!result.isAnyControllersEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Warn about mixed cgroups v1 and cgroups v2 controllers. The code is
|
||||
// not ready to deal with that on a per-controller basis. Return no metrics
|
||||
// in that case
|
||||
if (result.isAnyCgroupV1Controllers() && result.isAnyCgroupV2Controllers()) {
|
||||
Logger logger = System.getLogger("jdk.internal.platform");
|
||||
logger.log(Level.DEBUG, "Mixed cgroupv1 and cgroupv2 not supported. Metrics disabled.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, CgroupInfo> infos = result.getInfos();
|
||||
if (result.isCgroupV2()) {
|
||||
// For unified it doesn't matter which controller we pick.
|
||||
CgroupInfo anyController = infos.values().iterator().next();
|
||||
CgroupSubsystem subsystem = CgroupV2Subsystem.getInstance(Objects.requireNonNull(anyController));
|
||||
return new CgroupMetrics(subsystem);
|
||||
} else {
|
||||
CgroupV1Subsystem subsystem = CgroupV1Subsystem.getInstance(infos);
|
||||
return subsystem != null ? new CgroupV1MetricsImpl(subsystem) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the type of the cgroup system (v1 - legacy or hybrid - or, v2 - unified)
|
||||
* based on three files:
|
||||
*
|
||||
* (1) mountInfo (i.e. /proc/self/mountinfo)
|
||||
* (2) cgroups (i.e. /proc/cgroups)
|
||||
* (3) selfCgroup (i.e. /proc/self/cgroup)
|
||||
*
|
||||
* File 'cgroups' is inspected for the hierarchy ID of the mounted cgroup pseudo
|
||||
* filesystem. The hierarchy ID, in turn, helps us distinguish cgroups v2 and
|
||||
* cgroup v1. For a system with zero hierarchy ID, but with >= 1 relevant cgroup
|
||||
* controllers mounted in 'mountInfo' we can infer it's cgroups v2. Anything else
|
||||
* will be cgroup v1 (hybrid or legacy). File 'selfCgroup' is being used for
|
||||
* figuring out the mount path of the controller in the cgroup hierarchy.
|
||||
*/
|
||||
public static Optional<CgroupTypeResult> determineType(String mountInfo,
|
||||
String cgroups,
|
||||
String selfCgroup) throws IOException {
|
||||
final Map<String, CgroupInfo> infos = new HashMap<>();
|
||||
List<String> lines = Files.readAllLines(Path.of(cgroups));
|
||||
for (String line : lines) {
|
||||
if (line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
CgroupInfo info = CgroupInfo.fromCgroupsLine(line);
|
||||
switch (info.getName()) {
|
||||
// Only the following controllers are important to Java. All
|
||||
// other controllers (such as freezer) are ignored and
|
||||
// are not considered in the checks below for
|
||||
// anyCgroupsV1Controller/anyCgroupsV2Controller.
|
||||
case CPU_CTRL: infos.put(CPU_CTRL, info); break;
|
||||
case CPUACCT_CTRL: infos.put(CPUACCT_CTRL, info); break;
|
||||
case CPUSET_CTRL: infos.put(CPUSET_CTRL, info); break;
|
||||
case MEMORY_CTRL: infos.put(MEMORY_CTRL, info); break;
|
||||
case BLKIO_CTRL: infos.put(BLKIO_CTRL, info); break;
|
||||
case PIDS_CTRL: infos.put(PIDS_CTRL, info); break;
|
||||
}
|
||||
}
|
||||
|
||||
// For cgroups v2 all controllers need to have zero hierarchy id
|
||||
// and /proc/self/mountinfo needs to have at least one cgroup filesystem
|
||||
// mounted. Note that hybrid hierarchy has controllers mounted via
|
||||
// cgroup v1. In that case hierarchy id's will be non-zero.
|
||||
boolean isCgroupsV2 = true;
|
||||
boolean anyControllersEnabled = false;
|
||||
boolean anyCgroupsV2Controller = false;
|
||||
boolean anyCgroupsV1Controller = false;
|
||||
for (CgroupInfo info: infos.values()) {
|
||||
anyCgroupsV1Controller = anyCgroupsV1Controller || info.getHierarchyId() != 0;
|
||||
anyCgroupsV2Controller = anyCgroupsV2Controller || info.getHierarchyId() == 0;
|
||||
isCgroupsV2 = isCgroupsV2 && info.getHierarchyId() == 0;
|
||||
anyControllersEnabled = anyControllersEnabled || info.isEnabled();
|
||||
}
|
||||
|
||||
// If there are no mounted, relevant cgroup controllers in 'mountinfo' and only
|
||||
// 0 hierarchy IDs in file 'cgroups' have been seen, we are on a cgroups v1 system.
|
||||
// However, continuing in that case does not make sense as we'd need
|
||||
// information from mountinfo for the mounted controller paths which we wouldn't
|
||||
// find anyway in that case.
|
||||
lines = Files.readAllLines(Path.of(mountInfo));
|
||||
boolean anyCgroupMounted = false;
|
||||
for (String line: lines) {
|
||||
boolean cgroupsControllerFound = amendCgroupInfos(line, infos, isCgroupsV2);
|
||||
anyCgroupMounted = anyCgroupMounted || cgroupsControllerFound;
|
||||
}
|
||||
if (!anyCgroupMounted) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// Map a cgroup version specific 'action' to a line in 'selfCgroup' (i.e.
|
||||
// /proc/self/cgroups) , split on the ':' token, so as to set the appropriate
|
||||
// path to the cgroup controller in cgroup data structures 'infos'.
|
||||
// See:
|
||||
// setCgroupV1Path() for the action run for cgroups v1 systems
|
||||
// setCgroupV2Path() for the action run for cgroups v2 systems
|
||||
try (Stream<String> selfCgroupLines = Files.lines(Path.of(selfCgroup))) {
|
||||
Consumer<String[]> action = (tokens -> setCgroupV1Path(infos, tokens));
|
||||
if (isCgroupsV2) {
|
||||
action = (tokens -> setCgroupV2Path(infos, tokens));
|
||||
}
|
||||
// The limit value of 3 is because /proc/self/cgroup contains three
|
||||
// colon-separated tokens per line. The last token, cgroup path, might
|
||||
// contain a ':'.
|
||||
selfCgroupLines.map(line -> line.split(":", 3)).forEach(action);
|
||||
}
|
||||
|
||||
CgroupTypeResult result = new CgroupTypeResult(isCgroupsV2,
|
||||
anyControllersEnabled,
|
||||
anyCgroupsV2Controller,
|
||||
anyCgroupsV1Controller,
|
||||
Collections.unmodifiableMap(infos));
|
||||
return Optional.of(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the path to the cgroup controller for cgroups v2 based on a line
|
||||
* in /proc/self/cgroup file (represented as the 'tokens' array).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 0::/
|
||||
*
|
||||
* => tokens = [ "0", "", "/" ]
|
||||
*/
|
||||
private static void setCgroupV2Path(Map<String, CgroupInfo> infos,
|
||||
String[] tokens) {
|
||||
String name = tokens[1];
|
||||
if (!name.equals("")) {
|
||||
// This must be a v1 controller that we have ignored (e.g., freezer)
|
||||
assert infos.get(name) == null;
|
||||
return;
|
||||
}
|
||||
int hierarchyId = Integer.parseInt(tokens[0]);
|
||||
String cgroupPath = tokens[2];
|
||||
for (CgroupInfo info: infos.values()) {
|
||||
assert hierarchyId == info.getHierarchyId() && hierarchyId == 0;
|
||||
info.setCgroupPath(cgroupPath);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the path to the cgroup controller for cgroups v1 based on a line
|
||||
* in /proc/self/cgroup file (represented as the 'tokens' array).
|
||||
*
|
||||
* Note that multiple controllers might be joined at a single path.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 7:cpu,cpuacct:/system.slice/docker-74ad896fb40bbefe0f181069e4417505fffa19052098f27edf7133f31423bc0b.scope
|
||||
*
|
||||
* => tokens = [ "7", "cpu,cpuacct", "/system.slice/docker-74ad896fb40bbefe0f181069e4417505fffa19052098f27edf7133f31423bc0b.scope" ]
|
||||
*/
|
||||
private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
|
||||
String[] tokens) {
|
||||
String controllerName = tokens[1];
|
||||
String cgroupPath = tokens[2];
|
||||
if (controllerName != null && cgroupPath != null) {
|
||||
for (String cName: controllerName.split(",")) {
|
||||
switch (cName) {
|
||||
case MEMORY_CTRL: // fall through
|
||||
case CPUSET_CTRL:
|
||||
case CPUACCT_CTRL:
|
||||
case CPU_CTRL:
|
||||
case BLKIO_CTRL:
|
||||
case PIDS_CTRL:
|
||||
CgroupInfo info = infos.get(cName);
|
||||
info.setCgroupPath(cgroupPath);
|
||||
break;
|
||||
// Ignore not recognized controllers
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Amends cgroup infos with mount path and mount root. The passed in
|
||||
* 'mntInfoLine' represents a single line in, for example,
|
||||
* /proc/self/mountinfo. Each line is matched with MOUNTINFO_PATTERN
|
||||
* (see above), so as to extract the relevant tokens from the line.
|
||||
*
|
||||
* Host example cgroups v1:
|
||||
*
|
||||
* 44 30 0:41 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,seclabel,devices
|
||||
*
|
||||
* Container example cgroups v1:
|
||||
*
|
||||
* 1901 1894 0:37 /system.slice/docker-2291eeb92093f9d761aaf971782b575e9be56bd5930d4b5759b51017df3c1387.scope /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime master:12 - cgroup cgroup rw,seclabel,cpu,cpuacct
|
||||
*
|
||||
* Container example cgroups v2:
|
||||
*
|
||||
* 1043 1034 0:27 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup2 rw,seclabel,nsdelegate
|
||||
*
|
||||
*
|
||||
* @return {@code true} iff a relevant controller has been found at the
|
||||
* given line
|
||||
*/
|
||||
private static boolean amendCgroupInfos(String mntInfoLine,
|
||||
Map<String, CgroupInfo> infos,
|
||||
boolean isCgroupsV2) {
|
||||
Matcher lineMatcher = MOUNTINFO_PATTERN.matcher(mntInfoLine.trim());
|
||||
boolean cgroupv1ControllerFound = false;
|
||||
boolean cgroupv2ControllerFound = false;
|
||||
if (lineMatcher.matches()) {
|
||||
String mountRoot = lineMatcher.group(1);
|
||||
String mountPath = lineMatcher.group(2);
|
||||
String fsType = lineMatcher.group(3);
|
||||
if (fsType.equals("cgroup")) {
|
||||
Path p = Path.of(mountPath);
|
||||
String[] controllerNames = p.getFileName().toString().split(",");
|
||||
for (String controllerName: controllerNames) {
|
||||
switch (controllerName) {
|
||||
case MEMORY_CTRL: // fall-through
|
||||
case CPU_CTRL:
|
||||
case CPUACCT_CTRL:
|
||||
case CPUSET_CTRL:
|
||||
case PIDS_CTRL:
|
||||
case BLKIO_CTRL: {
|
||||
CgroupInfo info = infos.get(controllerName);
|
||||
setMountPoints(info, mountPath, mountRoot);
|
||||
cgroupv1ControllerFound = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Ignore controllers which we don't recognize
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (fsType.equals("cgroup2")) {
|
||||
if (isCgroupsV2) { // will be false for hybrid
|
||||
// All controllers have the same mount point and root mount
|
||||
// for unified hierarchy.
|
||||
for (CgroupInfo info: infos.values()) {
|
||||
setMountPoints(info, mountPath, mountRoot);
|
||||
}
|
||||
}
|
||||
cgroupv2ControllerFound = true;
|
||||
}
|
||||
}
|
||||
return cgroupv1ControllerFound || cgroupv2ControllerFound;
|
||||
}
|
||||
|
||||
private static void setMountPoints(CgroupInfo info, String mountPath, String mountRoot) {
|
||||
if (info.getMountPoint() != null) {
|
||||
// On some systems duplicate controllers get mounted in addition to
|
||||
// the main cgroup controllers (which are under /sys/fs/cgroup). In that
|
||||
// case pick the main one and discard others as the limits
|
||||
// are associated with the ones in /sys/fs/cgroup.
|
||||
if (!info.getMountPoint().startsWith("/sys/fs/cgroup")) {
|
||||
info.setMountPoint(mountPath);
|
||||
info.setMountRoot(mountRoot);
|
||||
}
|
||||
} else {
|
||||
info.setMountPoint(mountPath);
|
||||
info.setMountRoot(mountRoot);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CgroupTypeResult {
|
||||
private final boolean isCgroupV2;
|
||||
private final boolean anyControllersEnabled;
|
||||
private final boolean anyCgroupV2Controllers;
|
||||
private final boolean anyCgroupV1Controllers;
|
||||
private final Map<String, CgroupInfo> infos;
|
||||
|
||||
private CgroupTypeResult(boolean isCgroupV2,
|
||||
boolean anyControllersEnabled,
|
||||
boolean anyCgroupV2Controllers,
|
||||
boolean anyCgroupV1Controllers,
|
||||
Map<String, CgroupInfo> infos) {
|
||||
this.isCgroupV2 = isCgroupV2;
|
||||
this.anyControllersEnabled = anyControllersEnabled;
|
||||
this.anyCgroupV1Controllers = anyCgroupV1Controllers;
|
||||
this.anyCgroupV2Controllers = anyCgroupV2Controllers;
|
||||
this.infos = infos;
|
||||
}
|
||||
|
||||
public boolean isCgroupV2() {
|
||||
return isCgroupV2;
|
||||
}
|
||||
|
||||
public boolean isAnyControllersEnabled() {
|
||||
return anyControllersEnabled;
|
||||
}
|
||||
|
||||
public boolean isAnyCgroupV2Controllers() {
|
||||
return anyCgroupV2Controllers;
|
||||
}
|
||||
|
||||
public boolean isAnyCgroupV1Controllers() {
|
||||
return anyCgroupV1Controllers;
|
||||
}
|
||||
|
||||
public Map<String, CgroupInfo> getInfos() {
|
||||
return infos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2020, 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 jdk.internal.platform;
|
||||
|
||||
/**
|
||||
*
|
||||
* Cgroup v1 extensions to the Metrics interface. Linux, only.
|
||||
*
|
||||
*/
|
||||
public interface CgroupV1Metrics extends Metrics {
|
||||
|
||||
/**
|
||||
* Returns the largest amount of physical memory, in bytes, that
|
||||
* have been allocated in the Isolation Group.
|
||||
*
|
||||
* @return The largest amount of memory in bytes or -1 if this
|
||||
* metric is not available. Returns -2 if this metric is not
|
||||
* supported.
|
||||
*
|
||||
*/
|
||||
public long getMemoryMaxUsage();
|
||||
|
||||
/**
|
||||
* Returns the number of times that kernel memory requests in the
|
||||
* Isolation Group have exceeded the kernel memory limit.
|
||||
*
|
||||
* @return The number of exceeded requests or -1 if metric
|
||||
* is not available.
|
||||
*
|
||||
*/
|
||||
public long getKernelMemoryFailCount();
|
||||
|
||||
/**
|
||||
* Returns the largest amount of kernel physical memory, in bytes, that
|
||||
* have been allocated in the Isolation Group.
|
||||
*
|
||||
* @return The largest amount of memory in bytes or -1 if this
|
||||
* metric is not available.
|
||||
*
|
||||
*/
|
||||
public long getKernelMemoryMaxUsage();
|
||||
|
||||
/**
|
||||
* Returns the amount of kernel physical memory, in bytes, that
|
||||
* is currently allocated in the current Isolation Group.
|
||||
*
|
||||
* @return The amount of memory in bytes allocated or -1 if this
|
||||
* metric is not available.
|
||||
*
|
||||
*/
|
||||
public long getKernelMemoryUsage();
|
||||
|
||||
/**
|
||||
* Returns the number of times that networking memory requests in the
|
||||
* Isolation Group have exceeded the kernel memory limit.
|
||||
*
|
||||
* @return The number of exceeded requests or -1 if the metric
|
||||
* is not available.
|
||||
*
|
||||
*/
|
||||
public long getTcpMemoryFailCount();
|
||||
|
||||
/**
|
||||
* Returns the largest amount of networking physical memory, in bytes,
|
||||
* that have been allocated in the Isolation Group.
|
||||
*
|
||||
* @return The largest amount of memory in bytes or -1 if this
|
||||
* metric is not available.
|
||||
*
|
||||
*/
|
||||
public long getTcpMemoryMaxUsage();
|
||||
|
||||
/**
|
||||
* Returns the number of times that user memory requests in the
|
||||
* Isolation Group have exceeded the memory + swap limit.
|
||||
*
|
||||
* @return The number of exceeded requests or -1 if the metric
|
||||
* is not available.
|
||||
*
|
||||
*/
|
||||
public long getMemoryAndSwapFailCount();
|
||||
|
||||
/**
|
||||
* Returns the largest amount of physical memory and swap space,
|
||||
* in bytes, that have been allocated in the Isolation Group.
|
||||
*
|
||||
* @return The largest amount of memory in bytes or -1 if this
|
||||
* metric is not available.
|
||||
*
|
||||
*/
|
||||
public long getMemoryAndSwapMaxUsage();
|
||||
|
||||
/**
|
||||
* Returns the state of the Operating System Out of Memory termination
|
||||
* policy.
|
||||
*
|
||||
* @return Returns true if operating system will terminate processes
|
||||
* in the Isolation Group that exceed the amount of available
|
||||
* memory, otherwise false. null will be returned if this
|
||||
* capability is not available on the current operating system.
|
||||
*
|
||||
*/
|
||||
public Boolean isMemoryOOMKillEnabled();
|
||||
|
||||
/**
|
||||
* Returns the (attempts per second * 1000), if enabled, that the
|
||||
* operating system tries to satisfy a memory request for any
|
||||
* process in the current Isolation Group when no free memory is
|
||||
* readily available. Use {@link #isCpuSetMemoryPressureEnabled()} to
|
||||
* determine if this support is enabled.
|
||||
*
|
||||
* @return Memory pressure or 0 if not enabled or -1 if metric is not
|
||||
* available.
|
||||
*
|
||||
*/
|
||||
public double getCpuSetMemoryPressure();
|
||||
|
||||
/**
|
||||
* Returns the state of the memory pressure detection support.
|
||||
*
|
||||
* @return true if support is available and enabled. false otherwise.
|
||||
*
|
||||
*/
|
||||
public Boolean isCpuSetMemoryPressureEnabled();
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* 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 jdk.internal.platform;
|
||||
|
||||
/**
|
||||
* Cgroup v1 Metrics extensions
|
||||
*
|
||||
*/
|
||||
public class CgroupV1MetricsImpl extends CgroupMetrics implements CgroupV1Metrics {
|
||||
|
||||
private final CgroupV1Metrics metrics;
|
||||
|
||||
CgroupV1MetricsImpl(CgroupV1Metrics metrics) {
|
||||
super((CgroupSubsystem)metrics);
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryMaxUsage() {
|
||||
return metrics.getMemoryMaxUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKernelMemoryFailCount() {
|
||||
return metrics.getKernelMemoryFailCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKernelMemoryMaxUsage() {
|
||||
return metrics.getKernelMemoryMaxUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getKernelMemoryUsage() {
|
||||
return metrics.getKernelMemoryUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTcpMemoryFailCount() {
|
||||
return metrics.getTcpMemoryFailCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTcpMemoryMaxUsage() {
|
||||
return metrics.getTcpMemoryMaxUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryAndSwapFailCount() {
|
||||
return metrics.getMemoryAndSwapFailCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryAndSwapMaxUsage() {
|
||||
return metrics.getMemoryAndSwapMaxUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isMemoryOOMKillEnabled() {
|
||||
return metrics.isMemoryOOMKillEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCpuSetMemoryPressure() {
|
||||
return metrics.getCpuSetMemoryPressure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isCpuSetMemoryPressureEnabled() {
|
||||
return metrics.isCpuSetMemoryPressureEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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 jdk.internal.platform;
|
||||
|
||||
public class SystemMetrics {
|
||||
public static Metrics instance() {
|
||||
return CgroupMetrics.getInstance();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* 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 jdk.internal.platform.cgroupv1;
|
||||
|
||||
public class CgroupV1MemorySubSystemController extends CgroupV1SubsystemController {
|
||||
|
||||
private boolean hierarchical;
|
||||
private boolean swapenabled;
|
||||
|
||||
public CgroupV1MemorySubSystemController(String root, String mountPoint) {
|
||||
super(root, mountPoint);
|
||||
}
|
||||
|
||||
boolean isHierarchical() {
|
||||
return hierarchical;
|
||||
}
|
||||
|
||||
void setHierarchical(boolean hierarchical) {
|
||||
this.hierarchical = hierarchical;
|
||||
}
|
||||
|
||||
boolean isSwapEnabled() {
|
||||
return swapenabled;
|
||||
}
|
||||
|
||||
void setSwapEnabled(boolean swapenabled) {
|
||||
this.swapenabled = swapenabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2022, 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 jdk.internal.platform.cgroupv1;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.platform.CgroupInfo;
|
||||
import jdk.internal.platform.CgroupSubsystem;
|
||||
import jdk.internal.platform.CgroupSubsystemController;
|
||||
import jdk.internal.platform.CgroupV1Metrics;
|
||||
|
||||
public class CgroupV1Subsystem implements CgroupSubsystem, CgroupV1Metrics {
|
||||
private CgroupV1MemorySubSystemController memory;
|
||||
private CgroupV1SubsystemController cpu;
|
||||
private CgroupV1SubsystemController cpuacct;
|
||||
private CgroupV1SubsystemController cpuset;
|
||||
private CgroupV1SubsystemController blkio;
|
||||
private CgroupV1SubsystemController pids;
|
||||
|
||||
private static volatile CgroupV1Subsystem INSTANCE;
|
||||
|
||||
private static final String PROVIDER_NAME = "cgroupv1";
|
||||
|
||||
private CgroupV1Subsystem() {}
|
||||
|
||||
/**
|
||||
* Get a singleton instance of CgroupV1Subsystem. Initially, it creates a new
|
||||
* object by retrieving the pre-parsed information from cgroup interface
|
||||
* files from the provided 'infos' map.
|
||||
*
|
||||
* See CgroupSubsystemFactory.determineType() where the actual parsing of
|
||||
* cgroup interface files happens.
|
||||
*
|
||||
* @return A singleton CgroupV1Subsystem instance, never null
|
||||
*/
|
||||
public static CgroupV1Subsystem getInstance(Map<String, CgroupInfo> infos) {
|
||||
if (INSTANCE == null) {
|
||||
CgroupV1Subsystem tmpSubsystem = initSubSystem(infos);
|
||||
synchronized (CgroupV1Subsystem.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = tmpSubsystem;
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static CgroupV1Subsystem initSubSystem(Map<String, CgroupInfo> infos) {
|
||||
CgroupV1Subsystem subsystem = new CgroupV1Subsystem();
|
||||
|
||||
boolean anyActiveControllers = false;
|
||||
/*
|
||||
* Find the cgroup mount points for subsystem controllers
|
||||
* by looking up relevant data in the infos map
|
||||
*/
|
||||
for (CgroupInfo info: infos.values()) {
|
||||
switch (info.getName()) {
|
||||
case "memory": {
|
||||
if (info.getMountRoot() != null && info.getMountPoint() != null) {
|
||||
CgroupV1MemorySubSystemController controller = new CgroupV1MemorySubSystemController(info.getMountRoot(), info.getMountPoint());
|
||||
controller.setPath(info.getCgroupPath());
|
||||
boolean isHierarchial = getHierarchical(controller);
|
||||
controller.setHierarchical(isHierarchial);
|
||||
boolean isSwapEnabled = getSwapEnabled(controller);
|
||||
controller.setSwapEnabled(isSwapEnabled);
|
||||
subsystem.setMemorySubSystem(controller);
|
||||
anyActiveControllers = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "cpuset": {
|
||||
if (info.getMountRoot() != null && info.getMountPoint() != null) {
|
||||
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
|
||||
controller.setPath(info.getCgroupPath());
|
||||
subsystem.setCpuSetController(controller);
|
||||
anyActiveControllers = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "cpuacct": {
|
||||
if (info.getMountRoot() != null && info.getMountPoint() != null) {
|
||||
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
|
||||
controller.setPath(info.getCgroupPath());
|
||||
subsystem.setCpuAcctController(controller);
|
||||
anyActiveControllers = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "cpu": {
|
||||
if (info.getMountRoot() != null && info.getMountPoint() != null) {
|
||||
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
|
||||
controller.setPath(info.getCgroupPath());
|
||||
subsystem.setCpuController(controller);
|
||||
anyActiveControllers = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "blkio": {
|
||||
if (info.getMountRoot() != null && info.getMountPoint() != null) {
|
||||
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
|
||||
controller.setPath(info.getCgroupPath());
|
||||
subsystem.setBlkIOController(controller);
|
||||
anyActiveControllers = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "pids": {
|
||||
if (info.getMountRoot() != null && info.getMountPoint() != null) {
|
||||
CgroupV1SubsystemController controller = new CgroupV1SubsystemController(info.getMountRoot(), info.getMountPoint());
|
||||
controller.setPath(info.getCgroupPath());
|
||||
subsystem.setPidsController(controller);
|
||||
anyActiveControllers = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new AssertionError("Unrecognized controller in infos: " + info.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Return Metrics object if we found any subsystems.
|
||||
if (anyActiveControllers) {
|
||||
return subsystem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean getSwapEnabled(CgroupV1MemorySubSystemController controller) {
|
||||
long memswBytes = getLongValue(controller, "memory.memsw.limit_in_bytes");
|
||||
long swappiness = getLongValue(controller, "memory.swappiness");
|
||||
return (memswBytes > 0 && swappiness > 0);
|
||||
}
|
||||
|
||||
|
||||
private static boolean getHierarchical(CgroupV1MemorySubSystemController controller) {
|
||||
long hierarchical = getLongValue(controller, "memory.use_hierarchy");
|
||||
return hierarchical > 0;
|
||||
}
|
||||
|
||||
private void setMemorySubSystem(CgroupV1MemorySubSystemController memory) {
|
||||
this.memory = memory;
|
||||
}
|
||||
|
||||
private void setCpuController(CgroupV1SubsystemController cpu) {
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
private void setCpuAcctController(CgroupV1SubsystemController cpuacct) {
|
||||
this.cpuacct = cpuacct;
|
||||
}
|
||||
|
||||
private void setCpuSetController(CgroupV1SubsystemController cpuset) {
|
||||
this.cpuset = cpuset;
|
||||
}
|
||||
|
||||
private void setBlkIOController(CgroupV1SubsystemController blkio) {
|
||||
this.blkio = blkio;
|
||||
}
|
||||
|
||||
private void setPidsController(CgroupV1SubsystemController pids) {
|
||||
this.pids = pids;
|
||||
}
|
||||
|
||||
private static long getLongValue(CgroupSubsystemController controller,
|
||||
String param) {
|
||||
return CgroupSubsystemController.getLongValue(controller,
|
||||
param,
|
||||
CgroupV1SubsystemController::convertStringToLong,
|
||||
CgroupSubsystem.LONG_RETVAL_UNLIMITED);
|
||||
}
|
||||
|
||||
public String getProvider() {
|
||||
return PROVIDER_NAME;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* CPU Accounting Subsystem
|
||||
****************************************************************/
|
||||
|
||||
|
||||
public long getCpuUsage() {
|
||||
return getLongValue(cpuacct, "cpuacct.usage");
|
||||
}
|
||||
|
||||
public long[] getPerCpuUsage() {
|
||||
String usagelist = CgroupSubsystemController.getStringValue(cpuacct, "cpuacct.usage_percpu");
|
||||
if (usagelist == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String list[] = usagelist.split(" ");
|
||||
long percpu[] = new long[list.length];
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
percpu[i] = Long.parseLong(list[i]);
|
||||
}
|
||||
return percpu;
|
||||
}
|
||||
|
||||
public long getCpuUserUsage() {
|
||||
return CgroupV1SubsystemController.getLongEntry(cpuacct, "cpuacct.stat", "user");
|
||||
}
|
||||
|
||||
public long getCpuSystemUsage() {
|
||||
return CgroupV1SubsystemController.getLongEntry(cpuacct, "cpuacct.stat", "system");
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* CPU Subsystem
|
||||
****************************************************************/
|
||||
|
||||
|
||||
public long getCpuPeriod() {
|
||||
return getLongValue(cpu, "cpu.cfs_period_us");
|
||||
}
|
||||
|
||||
public long getCpuQuota() {
|
||||
return getLongValue(cpu, "cpu.cfs_quota_us");
|
||||
}
|
||||
|
||||
public long getCpuShares() {
|
||||
long retval = getLongValue(cpu, "cpu.shares");
|
||||
if (retval == 0 || retval == 1024)
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
else
|
||||
return retval;
|
||||
}
|
||||
|
||||
public long getCpuNumPeriods() {
|
||||
return CgroupV1SubsystemController.getLongEntry(cpu, "cpu.stat", "nr_periods");
|
||||
}
|
||||
|
||||
public long getCpuNumThrottled() {
|
||||
return CgroupV1SubsystemController.getLongEntry(cpu, "cpu.stat", "nr_throttled");
|
||||
}
|
||||
|
||||
public long getCpuThrottledTime() {
|
||||
return CgroupV1SubsystemController.getLongEntry(cpu, "cpu.stat", "throttled_time");
|
||||
}
|
||||
|
||||
public long getEffectiveCpuCount() {
|
||||
return Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* CPUSet Subsystem
|
||||
****************************************************************/
|
||||
|
||||
public int[] getCpuSetCpus() {
|
||||
return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.cpus"));
|
||||
}
|
||||
|
||||
public int[] getEffectiveCpuSetCpus() {
|
||||
return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.effective_cpus"));
|
||||
}
|
||||
|
||||
public int[] getCpuSetMems() {
|
||||
return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.mems"));
|
||||
}
|
||||
|
||||
public int[] getEffectiveCpuSetMems() {
|
||||
return CgroupSubsystemController.stringRangeToIntArray(CgroupSubsystemController.getStringValue(cpuset, "cpuset.effective_mems"));
|
||||
}
|
||||
|
||||
public double getCpuSetMemoryPressure() {
|
||||
return CgroupV1SubsystemController.getDoubleValue(cpuset, "cpuset.memory_pressure");
|
||||
}
|
||||
|
||||
public Boolean isCpuSetMemoryPressureEnabled() {
|
||||
long val = getLongValue(cpuset, "cpuset.memory_pressure_enabled");
|
||||
return (val == 1);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* Memory Subsystem
|
||||
****************************************************************/
|
||||
|
||||
|
||||
public long getMemoryFailCount() {
|
||||
return getLongValue(memory, "memory.failcnt");
|
||||
}
|
||||
|
||||
public long getMemoryLimit() {
|
||||
long retval = getLongValue(memory, "memory.limit_in_bytes");
|
||||
if (retval > CgroupV1SubsystemController.UNLIMITED_MIN) {
|
||||
if (memory.isHierarchical()) {
|
||||
// memory.limit_in_bytes returned unlimited, attempt
|
||||
// hierarchical memory limit
|
||||
String match = "hierarchical_memory_limit";
|
||||
retval = CgroupV1SubsystemController.getLongValueMatchingLine(memory,
|
||||
"memory.stat",
|
||||
match);
|
||||
}
|
||||
}
|
||||
return CgroupV1SubsystemController.longValOrUnlimited(retval);
|
||||
}
|
||||
|
||||
public long getMemoryMaxUsage() {
|
||||
return getLongValue(memory, "memory.max_usage_in_bytes");
|
||||
}
|
||||
|
||||
public long getMemoryUsage() {
|
||||
return getLongValue(memory, "memory.usage_in_bytes");
|
||||
}
|
||||
|
||||
public long getKernelMemoryFailCount() {
|
||||
return getLongValue(memory, "memory.kmem.failcnt");
|
||||
}
|
||||
|
||||
public long getKernelMemoryMaxUsage() {
|
||||
return getLongValue(memory, "memory.kmem.max_usage_in_bytes");
|
||||
}
|
||||
|
||||
public long getKernelMemoryUsage() {
|
||||
return getLongValue(memory, "memory.kmem.usage_in_bytes");
|
||||
}
|
||||
|
||||
public long getTcpMemoryFailCount() {
|
||||
return getLongValue(memory, "memory.kmem.tcp.failcnt");
|
||||
}
|
||||
|
||||
public long getTcpMemoryMaxUsage() {
|
||||
return getLongValue(memory, "memory.kmem.tcp.max_usage_in_bytes");
|
||||
}
|
||||
|
||||
public long getTcpMemoryUsage() {
|
||||
return getLongValue(memory, "memory.kmem.tcp.usage_in_bytes");
|
||||
}
|
||||
|
||||
public long getMemoryAndSwapFailCount() {
|
||||
if (memory != null && !memory.isSwapEnabled()) {
|
||||
return getMemoryFailCount();
|
||||
}
|
||||
return getLongValue(memory, "memory.memsw.failcnt");
|
||||
}
|
||||
|
||||
public long getMemoryAndSwapLimit() {
|
||||
if (memory != null && !memory.isSwapEnabled()) {
|
||||
return getMemoryLimit();
|
||||
}
|
||||
long retval = getLongValue(memory, "memory.memsw.limit_in_bytes");
|
||||
if (retval > CgroupV1SubsystemController.UNLIMITED_MIN) {
|
||||
if (memory.isHierarchical()) {
|
||||
// memory.memsw.limit_in_bytes returned unlimited, attempt
|
||||
// hierarchical memory limit
|
||||
String match = "hierarchical_memsw_limit";
|
||||
retval = CgroupV1SubsystemController.getLongValueMatchingLine(memory,
|
||||
"memory.stat",
|
||||
match);
|
||||
}
|
||||
}
|
||||
return CgroupV1SubsystemController.longValOrUnlimited(retval);
|
||||
}
|
||||
|
||||
public long getMemoryAndSwapMaxUsage() {
|
||||
if (memory != null && !memory.isSwapEnabled()) {
|
||||
return getMemoryMaxUsage();
|
||||
}
|
||||
return getLongValue(memory, "memory.memsw.max_usage_in_bytes");
|
||||
}
|
||||
|
||||
public long getMemoryAndSwapUsage() {
|
||||
if (memory != null && !memory.isSwapEnabled()) {
|
||||
return getMemoryUsage();
|
||||
}
|
||||
return getLongValue(memory, "memory.memsw.usage_in_bytes");
|
||||
}
|
||||
|
||||
public Boolean isMemoryOOMKillEnabled() {
|
||||
long val = CgroupV1SubsystemController.getLongEntry(memory, "memory.oom_control", "oom_kill_disable");
|
||||
return (val == 0);
|
||||
}
|
||||
|
||||
public long getMemorySoftLimit() {
|
||||
return CgroupV1SubsystemController.longValOrUnlimited(getLongValue(memory, "memory.soft_limit_in_bytes"));
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* pids subsystem
|
||||
****************************************************************/
|
||||
public long getPidsMax() {
|
||||
String pidsMaxStr = CgroupSubsystemController.getStringValue(pids, "pids.max");
|
||||
return CgroupSubsystem.limitFromString(pidsMaxStr);
|
||||
}
|
||||
|
||||
public long getPidsCurrent() {
|
||||
return getLongValue(pids, "pids.current");
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* BlKIO Subsystem
|
||||
****************************************************************/
|
||||
|
||||
|
||||
public long getBlkIOServiceCount() {
|
||||
return CgroupV1SubsystemController.getLongEntry(blkio, "blkio.throttle.io_service_bytes", "Total");
|
||||
}
|
||||
|
||||
public long getBlkIOServiced() {
|
||||
return CgroupV1SubsystemController.getLongEntry(blkio, "blkio.throttle.io_serviced", "Total");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2025, 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 jdk.internal.platform.cgroupv1;
|
||||
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Files;
|
||||
import jdk.internal.platform.CgroupSubsystem;
|
||||
import jdk.internal.platform.CgroupSubsystemController;
|
||||
|
||||
public class CgroupV1SubsystemController implements CgroupSubsystemController {
|
||||
|
||||
private static final double DOUBLE_RETVAL_UNLIMITED = CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
// Values returned larger than this number are unlimited.
|
||||
static long UNLIMITED_MIN = 0x7FFFFFFFFF000000L;
|
||||
String root;
|
||||
String mountPoint;
|
||||
String path;
|
||||
|
||||
public CgroupV1SubsystemController(String root, String mountPoint) {
|
||||
this.root = root;
|
||||
this.mountPoint = mountPoint;
|
||||
}
|
||||
|
||||
public void setPath(String cgroupPath) {
|
||||
if (root != null && cgroupPath != null) {
|
||||
String path = mountPoint;
|
||||
if (root.equals("/")) {
|
||||
// host processes and containers with cgroupns=private
|
||||
if (!cgroupPath.equals("/")) {
|
||||
path += cgroupPath;
|
||||
}
|
||||
} else {
|
||||
// containers with cgroupns=host, default setting is _root==cgroup_path
|
||||
if (!cgroupPath.equals(root)) {
|
||||
if (!cgroupPath.equals("") && !cgroupPath.equals("/")) {
|
||||
// When moved to a subgroup, between subgroups, the path suffix will change.
|
||||
Path cgp = Path.of(cgroupPath);
|
||||
int nameCount = cgp.getNameCount();
|
||||
for (int i=0; i < nameCount; i++) {
|
||||
Path dir = Path.of(mountPoint, cgp.toString());
|
||||
if (Files.isDirectory(dir)) {
|
||||
path = dir.toString();
|
||||
if (i > 0) {
|
||||
System.getLogger("jdk.internal.platform").log(Level.DEBUG, String.format(
|
||||
"Cgroup v1 path reduced to: %s.", cgp));
|
||||
}
|
||||
break;
|
||||
}
|
||||
int currentNameCount = cgp.getNameCount();
|
||||
cgp = (currentNameCount > 1) ? cgp.subpath(1, currentNameCount) : Path.of("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname) {
|
||||
return CgroupSubsystemController.getLongEntry(controller,
|
||||
param,
|
||||
entryname,
|
||||
CgroupSubsystem.LONG_RETVAL_UNLIMITED /* retval on error */);
|
||||
}
|
||||
|
||||
public static double getDoubleValue(CgroupSubsystemController controller, String param) {
|
||||
return CgroupSubsystemController.getDoubleValue(controller,
|
||||
param,
|
||||
DOUBLE_RETVAL_UNLIMITED /* retval on error */);
|
||||
}
|
||||
|
||||
public static long convertStringToLong(String strval) {
|
||||
return CgroupSubsystemController.convertStringToLong(strval,
|
||||
Long.MAX_VALUE /* overflow value */,
|
||||
CgroupSubsystem.LONG_RETVAL_UNLIMITED /* retval on error */);
|
||||
}
|
||||
|
||||
public static long longValOrUnlimited(long value) {
|
||||
return value > UNLIMITED_MIN ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : value;
|
||||
}
|
||||
|
||||
public static long getLongValueMatchingLine(CgroupSubsystemController controller,
|
||||
String param,
|
||||
String match) {
|
||||
return CgroupSubsystemController.getLongValueMatchingLine(controller,
|
||||
param,
|
||||
match,
|
||||
CgroupV1SubsystemController::convertHierachicalLimitLine,
|
||||
CgroupSubsystem.LONG_RETVAL_UNLIMITED);
|
||||
}
|
||||
|
||||
public static long convertHierachicalLimitLine(String line) {
|
||||
String[] tokens = line.split("\\s");
|
||||
if (tokens.length == 2) {
|
||||
String strVal = tokens[1];
|
||||
return CgroupV1SubsystemController.convertStringToLong(strVal);
|
||||
}
|
||||
return CgroupV1SubsystemController.UNLIMITED_MIN + 1; // unlimited
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2022, Red Hat Inc.
|
||||
* Copyright (c) 2024, 2025, 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 jdk.internal.platform.cgroupv2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.platform.CgroupInfo;
|
||||
import jdk.internal.platform.CgroupSubsystem;
|
||||
import jdk.internal.platform.CgroupSubsystemController;
|
||||
|
||||
public class CgroupV2Subsystem implements CgroupSubsystem {
|
||||
|
||||
private static volatile CgroupV2Subsystem INSTANCE;
|
||||
private static final long[] LONG_ARRAY_NOT_SUPPORTED = null;
|
||||
private static final int[] INT_ARRAY_UNAVAILABLE = null;
|
||||
private final CgroupSubsystemController unified;
|
||||
private static final String PROVIDER_NAME = "cgroupv2";
|
||||
private static final int PER_CPU_SHARES = 1024;
|
||||
private static final Object EMPTY_STR = "";
|
||||
private static final long NO_SWAP = 0;
|
||||
|
||||
private CgroupV2Subsystem(CgroupSubsystemController unified) {
|
||||
this.unified = unified;
|
||||
}
|
||||
|
||||
private long getLongVal(String file, long defaultValue) {
|
||||
return CgroupSubsystemController.getLongValue(unified,
|
||||
file,
|
||||
CgroupV2SubsystemController::convertStringToLong,
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
private long getLongVal(String file) {
|
||||
return getLongVal(file, CgroupSubsystem.LONG_RETVAL_UNLIMITED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance of a cgroups v2 subsystem. On initialization,
|
||||
* a new object from the given cgroup information 'anyController' is being
|
||||
* created. Note that the cgroup information has been parsed from cgroup
|
||||
* interface files ahead of time.
|
||||
*
|
||||
* See CgroupSubsystemFactory.determineType() for the cgroup interface
|
||||
* files parsing logic.
|
||||
*
|
||||
* @return A singleton CgroupSubsystem instance, never null.
|
||||
*/
|
||||
public static CgroupSubsystem getInstance(CgroupInfo anyController) {
|
||||
if (INSTANCE == null) {
|
||||
CgroupSubsystemController unified = new CgroupV2SubsystemController(
|
||||
anyController.getMountPoint(),
|
||||
anyController.getCgroupPath());
|
||||
CgroupV2Subsystem tmpCgroupSystem = new CgroupV2Subsystem(unified);
|
||||
synchronized (CgroupV2Subsystem.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = tmpCgroupSystem;
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProvider() {
|
||||
return PROVIDER_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuUsage() {
|
||||
long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "usage_usec");
|
||||
if (micros < 0) {
|
||||
return micros;
|
||||
}
|
||||
return TimeUnit.MICROSECONDS.toNanos(micros);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getPerCpuUsage() {
|
||||
return LONG_ARRAY_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuUserUsage() {
|
||||
long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "user_usec");
|
||||
if (micros < 0) {
|
||||
return micros;
|
||||
}
|
||||
return TimeUnit.MICROSECONDS.toNanos(micros);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuSystemUsage() {
|
||||
long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "system_usec");
|
||||
if (micros < 0) {
|
||||
return micros;
|
||||
}
|
||||
return TimeUnit.MICROSECONDS.toNanos(micros);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuPeriod() {
|
||||
return getFromCpuMax(1 /* $PERIOD index */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuQuota() {
|
||||
return getFromCpuMax(0 /* $MAX index */);
|
||||
}
|
||||
|
||||
private long getFromCpuMax(int tokenIdx) {
|
||||
String cpuMaxRaw = CgroupSubsystemController.getStringValue(unified, "cpu.max");
|
||||
if (cpuMaxRaw == null) {
|
||||
// likely file not found
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
// $MAX $PERIOD
|
||||
String[] tokens = cpuMaxRaw.split("\\s+");
|
||||
if (tokens.length != 2) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
String quota = tokens[tokenIdx];
|
||||
return CgroupSubsystem.limitFromString(quota);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuShares() {
|
||||
long sharesRaw = getLongVal("cpu.weight");
|
||||
// cg v2 value must be in range [1,10000]
|
||||
if (sharesRaw == 100 || sharesRaw <= 0 || sharesRaw > 10000) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
int shares = (int)sharesRaw;
|
||||
// CPU shares (OCI) value needs to get translated into
|
||||
// a proper Cgroups v2 value. See:
|
||||
// https://github.com/containers/crun/blob/1.24/crun.1.md#cpu-controller
|
||||
//
|
||||
// Use the inverse of (x == OCI value, y == cgroupsv2 value):
|
||||
// y = 10^(log2(x)^2/612 + 125/612 * log2(x) - 7.0/34.0)
|
||||
//
|
||||
// By re-arranging it to the standard quadratic form:
|
||||
// log2(x)^2 + 125 * log2(x) - (126 + 612 * log_10(y)) = 0
|
||||
//
|
||||
// Therefore, log2(x) = (-125 + sqrt( 125^2 - 4 * (-(126 + 612 * log_10(y)))))/2
|
||||
//
|
||||
// As a result we have the inverse (we can discount substraction of the
|
||||
// square root value since those values result in very small numbers and the
|
||||
// cpu shares values - OCI - are in range [2-262144])
|
||||
//
|
||||
// x = 2^((-125 + sqrt(16129 + 2448* log10(y)))/2)
|
||||
//
|
||||
double logMultiplicand = Math.log10(shares);
|
||||
double discriminant = 16129 + 2448 * logMultiplicand;
|
||||
double squareRoot = Math.sqrt(discriminant);
|
||||
double exponent = (-125 + squareRoot)/2;
|
||||
double scaledValue = Math.pow(2, exponent);
|
||||
|
||||
int x = (int)scaledValue;
|
||||
if ( x <= PER_CPU_SHARES ) {
|
||||
// Return the back-mapped value.
|
||||
return x;
|
||||
}
|
||||
int f = x/PER_CPU_SHARES;
|
||||
int lower_multiple = f * PER_CPU_SHARES;
|
||||
int upper_multiple = (f + 1) * PER_CPU_SHARES;
|
||||
int distance_lower = Math.max(lower_multiple, x) - Math.min(lower_multiple, x);
|
||||
int distance_upper = Math.max(upper_multiple, x) - Math.min(upper_multiple, x);
|
||||
x = distance_lower <= distance_upper ? lower_multiple : upper_multiple;
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuNumPeriods() {
|
||||
return CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "nr_periods");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuNumThrottled() {
|
||||
return CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "nr_throttled");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCpuThrottledTime() {
|
||||
long micros = CgroupV2SubsystemController.getLongEntry(unified, "cpu.stat", "throttled_usec");
|
||||
if (micros < 0) {
|
||||
return micros;
|
||||
}
|
||||
return TimeUnit.MICROSECONDS.toNanos(micros);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEffectiveCpuCount() {
|
||||
return Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getCpuSetCpus() {
|
||||
String cpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus");
|
||||
return getCpuSet(cpuSetVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getEffectiveCpuSetCpus() {
|
||||
String effCpuSetVal = CgroupSubsystemController.getStringValue(unified, "cpuset.cpus.effective");
|
||||
return getCpuSet(effCpuSetVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getCpuSetMems() {
|
||||
String cpuSetMems = CgroupSubsystemController.getStringValue(unified, "cpuset.mems");
|
||||
return getCpuSet(cpuSetMems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getEffectiveCpuSetMems() {
|
||||
String effCpuSetMems = CgroupSubsystemController.getStringValue(unified, "cpuset.mems.effective");
|
||||
return getCpuSet(effCpuSetMems);
|
||||
}
|
||||
|
||||
private int[] getCpuSet(String cpuSetVal) {
|
||||
if (cpuSetVal == null || EMPTY_STR.equals(cpuSetVal)) {
|
||||
return INT_ARRAY_UNAVAILABLE;
|
||||
}
|
||||
return CgroupSubsystemController.stringRangeToIntArray(cpuSetVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryFailCount() {
|
||||
return CgroupV2SubsystemController.getLongEntry(unified, "memory.events", "max");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryLimit() {
|
||||
String strVal = CgroupSubsystemController.getStringValue(unified, "memory.max");
|
||||
return CgroupSubsystem.limitFromString(strVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemoryUsage() {
|
||||
return getLongVal("memory.current");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTcpMemoryUsage() {
|
||||
return CgroupV2SubsystemController.getLongEntry(unified, "memory.stat", "sock");
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that for cgroups v2 the actual limits set for swap and
|
||||
* memory live in two different files, memory.swap.max and memory.max
|
||||
* respectively. In order to properly report a cgroup v1 like
|
||||
* compound value we need to sum the two values. Setting a swap limit
|
||||
* without also setting a memory limit is not allowed.
|
||||
*/
|
||||
@Override
|
||||
public long getMemoryAndSwapLimit() {
|
||||
String strVal = CgroupSubsystemController.getStringValue(unified, "memory.swap.max");
|
||||
// We only get a null string when file memory.swap.max doesn't exist.
|
||||
// In that case we return the memory limit without any swap.
|
||||
if (strVal == null) {
|
||||
return getMemoryLimit();
|
||||
}
|
||||
long swapLimit = CgroupSubsystem.limitFromString(strVal);
|
||||
if (swapLimit >= 0) {
|
||||
long memoryLimit = getMemoryLimit();
|
||||
assert memoryLimit >= 0;
|
||||
return memoryLimit + swapLimit;
|
||||
}
|
||||
return swapLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that for cgroups v2 the actual values set for swap usage and
|
||||
* memory usage live in two different files, memory.current and memory.swap.current
|
||||
* respectively. In order to properly report a cgroup v1 like
|
||||
* compound value we need to sum the two values. Setting a swap limit
|
||||
* without also setting a memory limit is not allowed.
|
||||
*/
|
||||
@Override
|
||||
public long getMemoryAndSwapUsage() {
|
||||
long memoryUsage = getMemoryUsage();
|
||||
if (memoryUsage >= 0) {
|
||||
// If file memory.swap.current doesn't exist, only return the regular
|
||||
// memory usage (without swap). Thus, use default value of NO_SWAP.
|
||||
long swapUsage = getLongVal("memory.swap.current", NO_SWAP);
|
||||
return memoryUsage + swapUsage;
|
||||
}
|
||||
return memoryUsage; // case of no memory limits
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMemorySoftLimit() {
|
||||
String softLimitStr = CgroupSubsystemController.getStringValue(unified, "memory.low");
|
||||
return CgroupSubsystem.limitFromString(softLimitStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPidsMax() {
|
||||
String pidsMaxStr = CgroupSubsystemController.getStringValue(unified, "pids.max");
|
||||
return CgroupSubsystem.limitFromString(pidsMaxStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPidsCurrent() {
|
||||
return getLongVal("pids.current");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBlkIOServiceCount() {
|
||||
return sumTokensIOStat(CgroupV2Subsystem::lineToRandWIOs);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getBlkIOServiced() {
|
||||
return sumTokensIOStat(CgroupV2Subsystem::lineToRBytesAndWBytesIO);
|
||||
}
|
||||
|
||||
private long sumTokensIOStat(Function<String, Long> mapFunc) {
|
||||
try (Stream<String> lines = Files.lines(Path.of(unified.path(), "io.stat"))) {
|
||||
return lines.map(mapFunc)
|
||||
.collect(Collectors.summingLong(e -> e));
|
||||
} catch (UncheckedIOException | IOException e) {
|
||||
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] getRWIOMatchTokenNames() {
|
||||
return new String[] { "rios", "wios" };
|
||||
}
|
||||
|
||||
private static String[] getRWBytesIOMatchTokenNames() {
|
||||
return new String[] { "rbytes", "wbytes" };
|
||||
}
|
||||
|
||||
public static Long lineToRandWIOs(String line) {
|
||||
String[] matchNames = getRWIOMatchTokenNames();
|
||||
return ioStatLineToLong(line, matchNames);
|
||||
}
|
||||
|
||||
public static Long lineToRBytesAndWBytesIO(String line) {
|
||||
String[] matchNames = getRWBytesIOMatchTokenNames();
|
||||
return ioStatLineToLong(line, matchNames);
|
||||
}
|
||||
|
||||
private static Long ioStatLineToLong(String line, String[] matchNames) {
|
||||
if (line == null || EMPTY_STR.equals(line)) {
|
||||
return Long.valueOf(0);
|
||||
}
|
||||
String[] tokens = line.split("\\s+");
|
||||
long retval = 0;
|
||||
for (String t: tokens) {
|
||||
String[] valKeys = t.split("=");
|
||||
if (valKeys.length != 2) {
|
||||
// ignore device ids $MAJ:$MIN
|
||||
continue;
|
||||
}
|
||||
for (String match: matchNames) {
|
||||
if (match.equals(valKeys[0])) {
|
||||
retval += longOrZero(valKeys[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Long.valueOf(retval);
|
||||
}
|
||||
|
||||
private static long longOrZero(String val) {
|
||||
long lVal = 0;
|
||||
try {
|
||||
lVal = Long.parseLong(val);
|
||||
} catch (NumberFormatException e) {
|
||||
// keep at 0
|
||||
}
|
||||
return lVal;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Red Hat Inc.
|
||||
* 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 jdk.internal.platform.cgroupv2;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import jdk.internal.platform.CgroupSubsystem;
|
||||
import jdk.internal.platform.CgroupSubsystemController;
|
||||
|
||||
public class CgroupV2SubsystemController implements CgroupSubsystemController {
|
||||
|
||||
private final String path;
|
||||
|
||||
public CgroupV2SubsystemController(String mountPath, String cgroupPath) {
|
||||
this.path = Paths.get(mountPath, cgroupPath).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public static long convertStringToLong(String strval) {
|
||||
return CgroupSubsystemController.convertStringToLong(strval,
|
||||
CgroupSubsystem.LONG_RETVAL_UNLIMITED /* overflow retval */,
|
||||
CgroupSubsystem.LONG_RETVAL_UNLIMITED /* default retval on error */);
|
||||
}
|
||||
|
||||
public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname) {
|
||||
return CgroupSubsystemController.getLongEntry(controller,
|
||||
param,
|
||||
entryname,
|
||||
CgroupSubsystem.LONG_RETVAL_UNLIMITED /* retval on error */);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 LinuxAsynchronousChannelProvider();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2025, 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 jdk.internal.vm.ContinuationSupport;
|
||||
|
||||
/**
|
||||
* Default PollerProvider for Linux.
|
||||
*/
|
||||
class DefaultPollerProvider extends PollerProvider {
|
||||
DefaultPollerProvider(Poller.Mode mode) {
|
||||
super(mode);
|
||||
}
|
||||
|
||||
DefaultPollerProvider() {
|
||||
var mode = ContinuationSupport.isSupported()
|
||||
? Poller.Mode.VTHREAD_POLLERS
|
||||
: Poller.Mode.SYSTEM_THREADS;
|
||||
this(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
int defaultReadPollers() {
|
||||
int ncpus = Runtime.getRuntime().availableProcessors();
|
||||
return switch (pollerMode()) {
|
||||
case SYSTEM_THREADS -> Math.max(Integer.highestOneBit(ncpus / 4), 1);
|
||||
case VTHREAD_POLLERS -> Math.min(Integer.highestOneBit(ncpus), 32);
|
||||
default -> super.defaultReadPollers();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
Poller readPoller(boolean subPoller) throws IOException {
|
||||
return new EPollPoller(pollerMode(), subPoller, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
Poller writePoller(boolean subPoller) throws IOException {
|
||||
return new EPollPoller(pollerMode(), subPoller, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2024, 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;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE = new EPollSelectorProvider();
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
121
src/java.base/linux/classes/sun/nio/ch/EPoll.java
Normal file
121
src/java.base/linux/classes/sun/nio/ch/EPoll.java
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2022, 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 jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Provides access to the Linux epoll facility.
|
||||
*/
|
||||
|
||||
class EPoll {
|
||||
private EPoll() { }
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
/**
|
||||
* typedef union epoll_data {
|
||||
* void *ptr;
|
||||
* int fd;
|
||||
* __uint32_t u32;
|
||||
* __uint64_t u64;
|
||||
* } epoll_data_t;
|
||||
*
|
||||
* struct epoll_event {
|
||||
* __uint32_t events;
|
||||
* epoll_data_t data;
|
||||
* }
|
||||
*/
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
private static final int SIZEOF_EPOLLEVENT = eventSize();
|
||||
private static final int OFFSETOF_EVENTS = eventsOffset();
|
||||
private static final int OFFSETOF_FD = dataOffset();
|
||||
|
||||
// opcodes
|
||||
static final int EPOLL_CTL_ADD = 1;
|
||||
static final int EPOLL_CTL_DEL = 2;
|
||||
static final int EPOLL_CTL_MOD = 3;
|
||||
|
||||
// events
|
||||
static final int EPOLLIN = 0x1;
|
||||
static final int EPOLLOUT = 0x4;
|
||||
|
||||
// flags
|
||||
static final int EPOLLONESHOT = (1 << 30);
|
||||
|
||||
/**
|
||||
* Allocates a poll array to handle up to {@code count} events.
|
||||
*/
|
||||
static long allocatePollArray(int count) {
|
||||
return unsafe.allocateMemory(count * SIZEOF_EPOLLEVENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a poll array
|
||||
*/
|
||||
static void freePollArray(long address) {
|
||||
unsafe.freeMemory(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event[i];
|
||||
*/
|
||||
static long getEvent(long address, int i) {
|
||||
return address + (SIZEOF_EPOLLEVENT*i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event->data.fd
|
||||
*/
|
||||
static int getDescriptor(long eventAddress) {
|
||||
return unsafe.getInt(eventAddress + OFFSETOF_FD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event->events
|
||||
*/
|
||||
static int getEvents(long eventAddress) {
|
||||
return unsafe.getInt(eventAddress + OFFSETOF_EVENTS);
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native int eventSize();
|
||||
|
||||
private static native int eventsOffset();
|
||||
|
||||
private static native int dataOffset();
|
||||
|
||||
static native int create() throws IOException;
|
||||
|
||||
static native int ctl(int epfd, int opcode, int fd, int events);
|
||||
|
||||
static native int wait(int epfd, long pollAddress, int numfds, int timeout)
|
||||
throws IOException;
|
||||
}
|
||||
157
src/java.base/linux/classes/sun/nio/ch/EPollPoller.java
Normal file
157
src/java.base/linux/classes/sun/nio/ch/EPollPoller.java
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2025, 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.lang.ref.Cleaner.Cleanable;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
import static sun.nio.ch.EPoll.*;
|
||||
|
||||
/**
|
||||
* Poller implementation based on the epoll facility.
|
||||
*/
|
||||
|
||||
class EPollPoller extends Poller {
|
||||
private static final int ENOENT = 2;
|
||||
|
||||
private final int epfd;
|
||||
private final int event;
|
||||
private final int maxEvents;
|
||||
private final long address;
|
||||
private final EventFD eventfd; // wakeup event, used for shutdown
|
||||
|
||||
// close action, and cleaner if this is subpoller
|
||||
private final Runnable closer;
|
||||
private final Cleanable cleaner;
|
||||
|
||||
EPollPoller(Poller.Mode mode, boolean subPoller, boolean read) throws IOException {
|
||||
boolean wakeable = (mode == Mode.POLLER_PER_CARRIER) && subPoller;
|
||||
int maxEvents = (subPoller) ? 16 : 64;
|
||||
|
||||
int epfd = EPoll.create();
|
||||
long address = 0L;
|
||||
EventFD eventfd = null;
|
||||
try {
|
||||
address = EPoll.allocatePollArray(maxEvents);
|
||||
|
||||
// register one end of the pipe with epoll to allow for wakeup
|
||||
if (wakeable) {
|
||||
eventfd = new EventFD();
|
||||
IOUtil.configureBlocking(eventfd.efd(), false);
|
||||
EPoll.ctl(epfd, EPOLL_CTL_ADD, eventfd.efd(), EPOLLIN);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
if (address != 0L) EPoll.freePollArray(address);
|
||||
if (eventfd != null) eventfd.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.epfd = epfd;
|
||||
this.event = (read) ? EPOLLIN : EPOLLOUT;
|
||||
this.maxEvents = maxEvents;
|
||||
this.address = address;
|
||||
this.eventfd = eventfd;
|
||||
|
||||
// create action to close epoll instance, register cleaner when wakeable
|
||||
this.closer = closer(epfd, address, eventfd);
|
||||
if (wakeable) {
|
||||
this.cleaner = CleanerFactory.cleaner().register(this, closer);
|
||||
} else {
|
||||
this.cleaner = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an action to close the epoll instance and release other resources.
|
||||
*/
|
||||
private static Runnable closer(int epfd, long address, EventFD eventfd) {
|
||||
return () -> {
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
EPoll.freePollArray(address);
|
||||
if (eventfd != null) eventfd.close();
|
||||
} catch (IOException _) { }
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
void close() {
|
||||
if (cleaner != null) {
|
||||
cleaner.clean();
|
||||
} else {
|
||||
closer.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int fdVal() {
|
||||
return epfd;
|
||||
}
|
||||
|
||||
@Override
|
||||
void implStartPoll(int fdVal) throws IOException {
|
||||
// re-enable if already registered but disabled (previously polled)
|
||||
int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fdVal, (event | EPOLLONESHOT));
|
||||
if (err == ENOENT)
|
||||
err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fdVal, (event | EPOLLONESHOT));
|
||||
if (err != 0)
|
||||
throw new IOException("epoll_ctl failed: " + err);
|
||||
}
|
||||
|
||||
@Override
|
||||
void implStopPoll(int fdVal, boolean polled) {
|
||||
// event is disabled if already polled
|
||||
if (!polled) {
|
||||
EPoll.ctl(epfd, EPOLL_CTL_DEL, fdVal, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void wakeupPoller() throws IOException {
|
||||
if (eventfd == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
eventfd.set();
|
||||
}
|
||||
|
||||
@Override
|
||||
int poll(int timeout) throws IOException {
|
||||
int n = EPoll.wait(epfd, address, maxEvents, timeout);
|
||||
int polled = 0;
|
||||
int i = 0;
|
||||
while (i < n) {
|
||||
long eventAddress = EPoll.getEvent(address, i);
|
||||
int fd = EPoll.getDescriptor(eventAddress);
|
||||
if (eventfd == null || fd != eventfd.efd()) {
|
||||
polled(fd);
|
||||
polled++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return polled;
|
||||
}
|
||||
}
|
||||
|
||||
320
src/java.base/linux/classes/sun/nio/ch/EPollPort.java
Normal file
320
src/java.base/linux/classes/sun/nio/ch/EPollPort.java
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2022, 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.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static sun.nio.ch.EPoll.EPOLLIN;
|
||||
import static sun.nio.ch.EPoll.EPOLLONESHOT;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_ADD;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_MOD;
|
||||
|
||||
|
||||
/**
|
||||
* AsynchronousChannelGroup implementation based on the Linux epoll facility.
|
||||
*/
|
||||
|
||||
final class EPollPort
|
||||
extends Port
|
||||
{
|
||||
// maximum number of events to poll at a time
|
||||
private static final int MAX_EPOLL_EVENTS = 512;
|
||||
|
||||
// errors
|
||||
private static final int ENOENT = 2;
|
||||
|
||||
// epoll file descriptor
|
||||
private final int epfd;
|
||||
|
||||
// address of the poll array passed to epoll_wait
|
||||
private final long address;
|
||||
|
||||
// true if epoll closed
|
||||
private boolean closed;
|
||||
|
||||
// socket pair used for wakeup
|
||||
private final int sp[];
|
||||
|
||||
// number of wakeups pending
|
||||
private final AtomicInteger wakeupCount = new AtomicInteger();
|
||||
|
||||
// encapsulates an event for a channel
|
||||
static class Event {
|
||||
final PollableChannel channel;
|
||||
final int events;
|
||||
|
||||
Event(PollableChannel channel, int events) {
|
||||
this.channel = channel;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
PollableChannel channel() { return channel; }
|
||||
int events() { return events; }
|
||||
}
|
||||
|
||||
// queue of events for cases that a polling thread dequeues more than one
|
||||
// event
|
||||
private final ArrayBlockingQueue<Event> queue;
|
||||
private final Event NEED_TO_POLL = new Event(null, 0);
|
||||
private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
|
||||
|
||||
EPollPort(AsynchronousChannelProvider provider, ThreadPool pool)
|
||||
throws IOException
|
||||
{
|
||||
super(provider, pool);
|
||||
|
||||
this.epfd = EPoll.create();
|
||||
this.address = EPoll.allocatePollArray(MAX_EPOLL_EVENTS);
|
||||
|
||||
// create socket pair for wakeup mechanism
|
||||
try {
|
||||
long fds = IOUtil.makePipe(true);
|
||||
this.sp = new int[]{(int) (fds >>> 32), (int) fds};
|
||||
} catch (IOException ioe) {
|
||||
EPoll.freePollArray(address);
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
// register one end with epoll
|
||||
EPoll.ctl(epfd, EPOLL_CTL_ADD, sp[0], EPOLLIN);
|
||||
|
||||
// create the queue and offer the special event to ensure that the first
|
||||
// threads polls
|
||||
this.queue = new ArrayBlockingQueue<>(MAX_EPOLL_EVENTS);
|
||||
this.queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
|
||||
EPollPort start() {
|
||||
startThreads(new EventHandlerTask());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources
|
||||
*/
|
||||
private void implClose() {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
try { FileDispatcherImpl.closeIntFD(epfd); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { }
|
||||
EPoll.freePollArray(address);
|
||||
}
|
||||
|
||||
private void wakeup() {
|
||||
if (wakeupCount.incrementAndGet() == 1) {
|
||||
// write byte to socketpair to force wakeup
|
||||
try {
|
||||
IOUtil.write1(sp[1], (byte)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 wakeup to each thread
|
||||
while (nThreads-- > 0) {
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invoke by clients to register a file descriptor
|
||||
@Override
|
||||
void startPoll(int fd, int events) {
|
||||
// update events (or add to epoll on first usage)
|
||||
int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
|
||||
if (err == ENOENT)
|
||||
err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
|
||||
if (err != 0)
|
||||
throw new AssertionError(); // should not happen
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to process events from epoll and dispatch to the channel's
|
||||
* onEvent handler.
|
||||
*
|
||||
* Events are retrieved from epoll in batch and offered to a BlockingQueue
|
||||
* where they are consumed by handler threads. A special "NEED_TO_POLL"
|
||||
* event is used to signal one consumer to re-poll when all events have
|
||||
* been consumed.
|
||||
*/
|
||||
private class EventHandlerTask implements Runnable {
|
||||
private Event poll() throws IOException {
|
||||
try {
|
||||
for (;;) {
|
||||
int n;
|
||||
do {
|
||||
n = EPoll.wait(epfd, address, MAX_EPOLL_EVENTS, -1);
|
||||
} while (n == IOStatus.INTERRUPTED);
|
||||
|
||||
/**
|
||||
* 'n' events have been read. Here we map them to their
|
||||
* corresponding channel in batch and queue n-1 so that
|
||||
* they can be handled by other handler threads. The last
|
||||
* event is handled by this thread (and so is not queued).
|
||||
*/
|
||||
fdToChannelLock.readLock().lock();
|
||||
try {
|
||||
while (n-- > 0) {
|
||||
long eventAddress = EPoll.getEvent(address, n);
|
||||
int fd = EPoll.getDescriptor(eventAddress);
|
||||
|
||||
// wakeup
|
||||
if (fd == sp[0]) {
|
||||
if (wakeupCount.decrementAndGet() == 0) {
|
||||
// consume one wakeup byte, never more as this
|
||||
// would interfere with shutdown when there is
|
||||
// a wakeup byte queued to wake each thread
|
||||
int nread;
|
||||
do {
|
||||
nread = IOUtil.drain1(sp[0]);
|
||||
} while (nread == IOStatus.INTERRUPTED);
|
||||
}
|
||||
|
||||
// queue special event if there are more events
|
||||
// to handle.
|
||||
if (n > 0) {
|
||||
queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
|
||||
continue;
|
||||
}
|
||||
return EXECUTE_TASK_OR_SHUTDOWN;
|
||||
}
|
||||
|
||||
PollableChannel channel = fdToChannel.get(fd);
|
||||
if (channel != null) {
|
||||
int events = EPoll.getEvents(eventAddress);
|
||||
Event ev = new Event(channel, events);
|
||||
|
||||
// n-1 events are queued; This thread handles
|
||||
// the last one except for the wakeup
|
||||
if (n > 0) {
|
||||
queue.offer(ev);
|
||||
} else {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fdToChannelLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// to ensure that some thread will poll when all events have
|
||||
// been consumed
|
||||
queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
|
||||
Invoker.getGroupAndInvokeCount();
|
||||
final boolean isPooledThread = (myGroupAndInvokeCount != null);
|
||||
boolean replaceMe = false;
|
||||
Event ev;
|
||||
try {
|
||||
for (;;) {
|
||||
// reset invoke count
|
||||
if (isPooledThread)
|
||||
myGroupAndInvokeCount.resetInvokeCount();
|
||||
|
||||
try {
|
||||
replaceMe = false;
|
||||
ev = queue.take();
|
||||
|
||||
// no events and this thread has been "selected" to
|
||||
// poll for more.
|
||||
if (ev == NEED_TO_POLL) {
|
||||
try {
|
||||
ev = poll();
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle wakeup to execute task or shutdown
|
||||
if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
|
||||
Runnable task = pollTask();
|
||||
if (task == null) {
|
||||
// shutdown request
|
||||
return;
|
||||
}
|
||||
// run task (may throw error/exception)
|
||||
replaceMe = true;
|
||||
task.run();
|
||||
continue;
|
||||
}
|
||||
|
||||
// process event
|
||||
try {
|
||||
ev.channel().onEvent(ev.events(), isPooledThread);
|
||||
} catch (Error | RuntimeException x) {
|
||||
replaceMe = true;
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// last handler to exit when shutdown releases resources
|
||||
int remaining = threadExit(this, replaceMe);
|
||||
if (remaining == 0 && isShutdown()) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
300
src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java
Normal file
300
src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2024, 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.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static sun.nio.ch.EPoll.EPOLLIN;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_ADD;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_DEL;
|
||||
import static sun.nio.ch.EPoll.EPOLL_CTL_MOD;
|
||||
|
||||
|
||||
/**
|
||||
* Linux epoll based Selector implementation
|
||||
*/
|
||||
|
||||
class EPollSelectorImpl extends SelectorImpl {
|
||||
|
||||
// maximum number of events to poll in one call to epoll_wait
|
||||
private static final int NUM_EPOLLEVENTS = Math.min(IOUtil.fdLimit(), 1024);
|
||||
|
||||
// epoll file descriptor
|
||||
private final int epfd;
|
||||
|
||||
// address of poll array when polling with epoll_wait
|
||||
private final long pollArrayAddress;
|
||||
|
||||
// eventfd object used for interrupt
|
||||
private final EventFD eventfd;
|
||||
|
||||
// maps file descriptor to selection key, synchronize on selector
|
||||
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
|
||||
|
||||
// pending new registrations/updates, queued by setEventOps
|
||||
private final Object updateLock = new Object();
|
||||
private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
|
||||
|
||||
// interrupt triggering and clearing
|
||||
private final Object interruptLock = new Object();
|
||||
private boolean interruptTriggered;
|
||||
|
||||
EPollSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
|
||||
this.epfd = EPoll.create();
|
||||
this.pollArrayAddress = EPoll.allocatePollArray(NUM_EPOLLEVENTS);
|
||||
|
||||
try {
|
||||
this.eventfd = new EventFD();
|
||||
IOUtil.configureBlocking(IOUtil.newFD(eventfd.efd()), false);
|
||||
} catch (IOException ioe) {
|
||||
EPoll.freePollArray(pollArrayAddress);
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
// register the eventfd object for wakeups
|
||||
EPoll.ctl(epfd, EPOLL_CTL_ADD, eventfd.efd(), EPOLLIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doSelect(Consumer<SelectionKey> action, long timeout)
|
||||
throws IOException
|
||||
{
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
// epoll_wait timeout is int
|
||||
int to = (int) Math.min(timeout, Integer.MAX_VALUE);
|
||||
boolean blocking = (to != 0);
|
||||
boolean timedPoll = (to > 0);
|
||||
|
||||
int numEntries;
|
||||
processUpdateQueue();
|
||||
processDeregisterQueue();
|
||||
|
||||
if (Thread.currentThread().isVirtual()) {
|
||||
numEntries = (timedPoll)
|
||||
? timedPoll(TimeUnit.MILLISECONDS.toNanos(to))
|
||||
: untimedPoll(blocking);
|
||||
} else {
|
||||
try {
|
||||
begin(blocking);
|
||||
do {
|
||||
long startTime = timedPoll ? System.nanoTime() : 0;
|
||||
numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, to);
|
||||
if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
|
||||
// timed poll interrupted so need to adjust timeout
|
||||
long adjust = System.nanoTime() - startTime;
|
||||
to -= (int) TimeUnit.NANOSECONDS.toMillis(adjust);
|
||||
if (to <= 0) {
|
||||
// timeout expired so no retry
|
||||
numEntries = 0;
|
||||
}
|
||||
}
|
||||
} while (numEntries == IOStatus.INTERRUPTED);
|
||||
} finally {
|
||||
end(blocking);
|
||||
}
|
||||
}
|
||||
assert IOStatus.check(numEntries);
|
||||
|
||||
processDeregisterQueue();
|
||||
return processEvents(numEntries, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* If blocking, parks the current virtual thread until a file descriptor is polled
|
||||
* or the thread is interrupted.
|
||||
*/
|
||||
private int untimedPoll(boolean block) throws IOException {
|
||||
int numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, 0);
|
||||
if (block) {
|
||||
while (numEntries == 0 && !Thread.currentThread().isInterrupted()) {
|
||||
Poller.pollSelector(epfd, 0);
|
||||
numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, 0);
|
||||
}
|
||||
}
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parks the current virtual thread until a file descriptor is polled, or the thread
|
||||
* is interrupted, for up to the specified waiting time.
|
||||
*/
|
||||
private int timedPoll(long nanos) throws IOException {
|
||||
long startNanos = System.nanoTime();
|
||||
int numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, 0);
|
||||
while (numEntries == 0 && !Thread.currentThread().isInterrupted()) {
|
||||
long remainingNanos = nanos - (System.nanoTime() - startNanos);
|
||||
if (remainingNanos <= 0) {
|
||||
// timeout
|
||||
break;
|
||||
}
|
||||
Poller.pollSelector(epfd, remainingNanos);
|
||||
numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, 0);
|
||||
}
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process changes to the interest ops.
|
||||
*/
|
||||
private void processUpdateQueue() {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
synchronized (updateLock) {
|
||||
SelectionKeyImpl ski;
|
||||
while ((ski = updateKeys.pollFirst()) != null) {
|
||||
if (ski.isValid()) {
|
||||
int fd = ski.getFDVal();
|
||||
// add to fdToKey if needed
|
||||
SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
|
||||
assert (previous == null) || (previous == ski);
|
||||
|
||||
int newEvents = ski.translateInterestOps();
|
||||
int registeredEvents = ski.registeredEvents();
|
||||
if (newEvents != registeredEvents) {
|
||||
if (newEvents == 0) {
|
||||
// remove from epoll
|
||||
EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
|
||||
} else {
|
||||
if (registeredEvents == 0) {
|
||||
// add to epoll
|
||||
EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, newEvents);
|
||||
} else {
|
||||
// modify events
|
||||
EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, newEvents);
|
||||
}
|
||||
}
|
||||
ski.registeredEvents(newEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the polled events.
|
||||
* If the interrupt fd has been selected, drain it and clear the interrupt.
|
||||
*/
|
||||
private int processEvents(int numEntries, Consumer<SelectionKey> action)
|
||||
throws IOException
|
||||
{
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
boolean interrupted = false;
|
||||
int numKeysUpdated = 0;
|
||||
for (int i=0; i<numEntries; i++) {
|
||||
long event = EPoll.getEvent(pollArrayAddress, i);
|
||||
int fd = EPoll.getDescriptor(event);
|
||||
if (fd == eventfd.efd()) {
|
||||
interrupted = true;
|
||||
} else {
|
||||
SelectionKeyImpl ski = fdToKey.get(fd);
|
||||
if (ski != null) {
|
||||
int rOps = EPoll.getEvents(event);
|
||||
numKeysUpdated += processReadyEvents(rOps, ski, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interrupted) {
|
||||
clearInterrupt();
|
||||
}
|
||||
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implClose() throws IOException {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcherImpl.closeIntFD(epfd);
|
||||
EPoll.freePollArray(pollArrayAddress);
|
||||
|
||||
eventfd.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
assert !ski.isValid();
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
int fd = ski.getFDVal();
|
||||
if (fdToKey.remove(fd) != null) {
|
||||
if (ski.registeredEvents() != 0) {
|
||||
EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
|
||||
ski.registeredEvents(0);
|
||||
}
|
||||
} else {
|
||||
assert ski.registeredEvents() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventOps(SelectionKeyImpl ski) {
|
||||
synchronized (updateLock) {
|
||||
updateKeys.addLast(ski);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
try {
|
||||
eventfd.set();
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void clearInterrupt() throws IOException {
|
||||
synchronized (interruptLock) {
|
||||
eventfd.reset();
|
||||
interruptTriggered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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 EPollSelectorProvider
|
||||
extends SelectorProviderImpl
|
||||
{
|
||||
public AbstractSelector openSelector() throws IOException {
|
||||
return new EPollSelectorImpl(this);
|
||||
}
|
||||
|
||||
public Channel inheritedChannel() throws IOException {
|
||||
return InheritedChannel.getChannel();
|
||||
}
|
||||
}
|
||||
73
src/java.base/linux/classes/sun/nio/ch/EventFD.java
Normal file
73
src/java.base/linux/classes/sun/nio/ch/EventFD.java
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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;
|
||||
|
||||
/*
|
||||
* Provides access to the Linux eventfd object.
|
||||
*/
|
||||
final class EventFD {
|
||||
private final int efd;
|
||||
|
||||
/**
|
||||
* Creates a blocking eventfd object with initial value zero.
|
||||
*/
|
||||
EventFD() throws IOException {
|
||||
efd = eventfd0();
|
||||
}
|
||||
|
||||
int efd() {
|
||||
return efd;
|
||||
}
|
||||
|
||||
void set() throws IOException {
|
||||
set0(efd);
|
||||
}
|
||||
|
||||
void reset() throws IOException {
|
||||
IOUtil.drain(efd);
|
||||
}
|
||||
|
||||
void close() throws IOException {
|
||||
FileDispatcherImpl.closeIntFD(efd);
|
||||
}
|
||||
|
||||
private static native int eventfd0() throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the value 1 to the eventfd object as a long in the
|
||||
* native byte order of the platform.
|
||||
*
|
||||
* @param the integral eventfd file descriptor
|
||||
* @return the number of bytes written; should equal 8
|
||||
*/
|
||||
private static native int set0(int efd) throws IOException;
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2022, 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.FileDescriptor;
|
||||
|
||||
class FileDispatcherImpl extends UnixFileDispatcherImpl {
|
||||
FileDispatcherImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
int maxDirectTransferSize() {
|
||||
return 0x7ffff000; // 2,147,479,552 maximum for sendfile()
|
||||
}
|
||||
|
||||
long transferTo(FileDescriptor src, long position, long count,
|
||||
FileDescriptor dst, boolean append) {
|
||||
return transferTo0(src, position, count, dst, append);
|
||||
}
|
||||
|
||||
long transferFrom(FileDescriptor src, FileDescriptor dst,
|
||||
long position, long count, boolean append) {
|
||||
return transferFrom0(src, dst, position, count, append);
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
static native long transferTo0(FileDescriptor src, long position,
|
||||
long count, FileDescriptor dst,
|
||||
boolean append);
|
||||
|
||||
static native long transferFrom0(FileDescriptor src, FileDescriptor dst,
|
||||
long position, long count, boolean append);
|
||||
|
||||
static native void init0();
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
init0();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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 LinuxAsynchronousChannelProvider
|
||||
extends AsynchronousChannelProvider
|
||||
{
|
||||
private static volatile EPollPort defaultPort;
|
||||
|
||||
private EPollPort defaultEventPort() throws IOException {
|
||||
if (defaultPort == null) {
|
||||
synchronized (LinuxAsynchronousChannelProvider.class) {
|
||||
if (defaultPort == null) {
|
||||
defaultPort = new EPollPort(this, ThreadPool.getDefault()).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
public LinuxAsynchronousChannelProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
|
||||
throws IOException
|
||||
{
|
||||
return new EPollPort(this, ThreadPool.create(nThreads, factory)).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
|
||||
throws IOException
|
||||
{
|
||||
return new EPollPort(this, ThreadPool.wrap(executor, initialSize)).start();
|
||||
}
|
||||
|
||||
private Port toPort(AsynchronousChannelGroup group) throws IOException {
|
||||
if (group == null) {
|
||||
return defaultEventPort();
|
||||
} else {
|
||||
if (!(group instanceof EPollPort))
|
||||
throw new IllegalChannelGroupException();
|
||||
return (Port)group;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousServerSocketChannelImpl(toPort(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousSocketChannelImpl(toPort(group));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2018, 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.FileSystem;
|
||||
|
||||
/**
|
||||
* Creates this platform's default FileSystemProvider.
|
||||
*/
|
||||
|
||||
public class DefaultFileSystemProvider {
|
||||
private static final LinuxFileSystemProvider INSTANCE
|
||||
= new LinuxFileSystemProvider();
|
||||
|
||||
private DefaultFileSystemProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the platform's default file system provider.
|
||||
*/
|
||||
public static LinuxFileSystemProvider instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform's default file system.
|
||||
*/
|
||||
public static FileSystem theFileSystem() {
|
||||
return INSTANCE.theFileSystem();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2024, 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.util.Map;
|
||||
import java.util.Set;
|
||||
import java.io.IOException;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Linux implementation of DosFileAttributeView for use on file systems such
|
||||
* as ext3 that have extended attributes enabled and SAMBA configured to store
|
||||
* DOS attributes.
|
||||
*/
|
||||
|
||||
class LinuxDosFileAttributeView
|
||||
extends UnixFileAttributeViews.Basic implements DosFileAttributeView
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
private static final String READONLY_NAME = "readonly";
|
||||
private static final String ARCHIVE_NAME = "archive";
|
||||
private static final String SYSTEM_NAME = "system";
|
||||
private static final String HIDDEN_NAME = "hidden";
|
||||
|
||||
private static final String DOS_XATTR_NAME = "user.DOSATTRIB";
|
||||
private static final byte[] DOS_XATTR_NAME_AS_BYTES = Util.toBytes(DOS_XATTR_NAME);
|
||||
|
||||
private static final int DOS_XATTR_READONLY = 0x01;
|
||||
private static final int DOS_XATTR_HIDDEN = 0x02;
|
||||
private static final int DOS_XATTR_SYSTEM = 0x04;
|
||||
private static final int DOS_XATTR_ARCHIVE = 0x20;
|
||||
|
||||
// the names of the DOS attributes (includes basic)
|
||||
private static final Set<String> dosAttributeNames =
|
||||
Util.newSet(basicAttributeNames, READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME);
|
||||
|
||||
LinuxDosFileAttributeView(UnixPath file, boolean followLinks) {
|
||||
super(file, followLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "dos";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String attribute, Object value)
|
||||
throws IOException
|
||||
{
|
||||
if (attribute.equals(READONLY_NAME)) {
|
||||
setReadOnly((Boolean)value);
|
||||
return;
|
||||
}
|
||||
if (attribute.equals(ARCHIVE_NAME)) {
|
||||
setArchive((Boolean)value);
|
||||
return;
|
||||
}
|
||||
if (attribute.equals(SYSTEM_NAME)) {
|
||||
setSystem((Boolean)value);
|
||||
return;
|
||||
}
|
||||
if (attribute.equals(HIDDEN_NAME)) {
|
||||
setHidden((Boolean)value);
|
||||
return;
|
||||
}
|
||||
super.setAttribute(attribute, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,Object> readAttributes(String[] attributes)
|
||||
throws IOException
|
||||
{
|
||||
AttributesBuilder builder =
|
||||
AttributesBuilder.create(dosAttributeNames, attributes);
|
||||
DosFileAttributes attrs = readAttributes();
|
||||
addRequestedBasicAttributes(attrs, builder);
|
||||
if (builder.match(READONLY_NAME))
|
||||
builder.add(READONLY_NAME, attrs.isReadOnly());
|
||||
if (builder.match(ARCHIVE_NAME))
|
||||
builder.add(ARCHIVE_NAME, attrs.isArchive());
|
||||
if (builder.match(SYSTEM_NAME))
|
||||
builder.add(SYSTEM_NAME, attrs.isSystem());
|
||||
if (builder.match(HIDDEN_NAME))
|
||||
builder.add(HIDDEN_NAME, attrs.isHidden());
|
||||
return builder.unmodifiableMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DosFileAttributes readAttributes() throws IOException {
|
||||
int fd = -1;
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
final UnixFileAttributes attrs = UnixFileAttributes.get(fd);
|
||||
final int dosAttribute = getDosAttribute(fd);
|
||||
|
||||
return new DosFileAttributes() {
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
return attrs.lastModifiedTime();
|
||||
}
|
||||
@Override
|
||||
public FileTime lastAccessTime() {
|
||||
return attrs.lastAccessTime();
|
||||
}
|
||||
@Override
|
||||
public FileTime creationTime() {
|
||||
return attrs.creationTime();
|
||||
}
|
||||
@Override
|
||||
public boolean isRegularFile() {
|
||||
return attrs.isRegularFile();
|
||||
}
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return attrs.isDirectory();
|
||||
}
|
||||
@Override
|
||||
public boolean isSymbolicLink() {
|
||||
return attrs.isSymbolicLink();
|
||||
}
|
||||
@Override
|
||||
public boolean isOther() {
|
||||
return attrs.isOther();
|
||||
}
|
||||
@Override
|
||||
public long size() {
|
||||
return attrs.size();
|
||||
}
|
||||
@Override
|
||||
public Object fileKey() {
|
||||
return attrs.fileKey();
|
||||
}
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return (dosAttribute & DOS_XATTR_READONLY) != 0;
|
||||
}
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
return (dosAttribute & DOS_XATTR_HIDDEN) != 0;
|
||||
}
|
||||
@Override
|
||||
public boolean isArchive() {
|
||||
return (dosAttribute & DOS_XATTR_ARCHIVE) != 0;
|
||||
}
|
||||
@Override
|
||||
public boolean isSystem() {
|
||||
return (dosAttribute & DOS_XATTR_SYSTEM) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
} finally {
|
||||
close(fd, e -> null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean value) throws IOException {
|
||||
updateDosAttribute(DOS_XATTR_READONLY, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHidden(boolean value) throws IOException {
|
||||
updateDosAttribute(DOS_XATTR_HIDDEN, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArchive(boolean value) throws IOException {
|
||||
updateDosAttribute(DOS_XATTR_ARCHIVE, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystem(boolean value) throws IOException {
|
||||
updateDosAttribute(DOS_XATTR_SYSTEM, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the value of the user.DOSATTRIB extended attribute
|
||||
*/
|
||||
private int getDosAttribute(int fd) throws UnixException {
|
||||
final int size = 24;
|
||||
|
||||
try (NativeBuffer buffer = NativeBuffers.getNativeBuffer(size)) {
|
||||
int len = LinuxNativeDispatcher
|
||||
.fgetxattr(fd, DOS_XATTR_NAME_AS_BYTES, buffer.address(), size);
|
||||
|
||||
if (len > 0) {
|
||||
// ignore null terminator
|
||||
if (unsafe.getByte(buffer.address()+len-1) == 0)
|
||||
len--;
|
||||
|
||||
// convert to String and parse
|
||||
byte[] buf = new byte[len];
|
||||
unsafe.copyMemory(null, buffer.address(), buf,
|
||||
Unsafe.ARRAY_BYTE_BASE_OFFSET, len);
|
||||
String value = Util.toString(buf);
|
||||
|
||||
// should be something like 0x20
|
||||
if (value.length() >= 3 && value.startsWith("0x")) {
|
||||
try {
|
||||
return Integer.parseInt(value.substring(2), 16);
|
||||
} catch (NumberFormatException x) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnixException("Value of " + DOS_XATTR_NAME + " attribute is invalid");
|
||||
} catch (UnixException x) {
|
||||
// default value when attribute does not exist
|
||||
if (x.errno() == ENODATA)
|
||||
return 0;
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value of the user.DOSATTRIB extended attribute
|
||||
*/
|
||||
private void updateDosAttribute(int flag, boolean enable) throws IOException {
|
||||
int fd = -1;
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
int oldValue = getDosAttribute(fd);
|
||||
int newValue = oldValue;
|
||||
if (enable) {
|
||||
newValue |= flag;
|
||||
} else {
|
||||
newValue &= ~flag;
|
||||
}
|
||||
if (newValue != oldValue) {
|
||||
byte[] value = Util.toBytes("0x" + Integer.toHexString(newValue));
|
||||
try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(value)) {
|
||||
LinuxNativeDispatcher.fsetxattr(fd, DOS_XATTR_NAME_AS_BYTES,
|
||||
buffer.address(), value.length+1);
|
||||
}
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
} finally {
|
||||
close(fd, e -> null);
|
||||
}
|
||||
}
|
||||
}
|
||||
159
src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java
Normal file
159
src/java.base/linux/classes/sun/nio/fs/LinuxFileStore.java
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2023, 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.io.IOException;
|
||||
import java.nio.file.attribute.DosFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.PosixFileAttributeView;
|
||||
import java.nio.file.attribute.UserDefinedFileAttributeView;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Linux implementation of FileStore
|
||||
*/
|
||||
|
||||
class LinuxFileStore
|
||||
extends UnixFileStore
|
||||
{
|
||||
// used when checking if extended attributes are enabled or not
|
||||
private volatile boolean xattrChecked;
|
||||
private volatile boolean xattrEnabled;
|
||||
|
||||
LinuxFileStore(UnixPath file) throws IOException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
LinuxFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
|
||||
super(fs, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds, and returns, the mount entry for the file system where the file
|
||||
* resides.
|
||||
*/
|
||||
@Override
|
||||
UnixMountEntry findMountEntry() throws IOException {
|
||||
LinuxFileSystem fs = (LinuxFileSystem)file().getFileSystem();
|
||||
|
||||
// step 1: get realpath
|
||||
UnixPath path = null;
|
||||
try {
|
||||
byte[] rp = UnixNativeDispatcher.realpath(file());
|
||||
path = new UnixPath(fs, rp);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(file());
|
||||
}
|
||||
|
||||
// step 2: find mount point
|
||||
List<UnixMountEntry> procMountsEntries =
|
||||
fs.getMountEntries("/proc/mounts");
|
||||
UnixPath parent = path.getParent();
|
||||
while (parent != null) {
|
||||
UnixFileAttributes attrs = null;
|
||||
try {
|
||||
attrs = UnixFileAttributes.get(parent, true);
|
||||
} catch (UnixException x) {
|
||||
x.rethrowAsIOException(parent);
|
||||
}
|
||||
if (attrs.dev() != dev()) {
|
||||
// step 3: lookup mounted file systems (use /proc/mounts to
|
||||
// ensure we find the file system even when not in /etc/mtab)
|
||||
byte[] dir = path.asByteArray();
|
||||
for (UnixMountEntry entry : procMountsEntries) {
|
||||
if (Arrays.equals(dir, entry.dir()))
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
path = parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
// step 3: lookup mounted file systems (use /proc/mounts to
|
||||
// ensure we find the file system even when not in /etc/mtab)
|
||||
byte[] dir = path.asByteArray();
|
||||
for (UnixMountEntry entry : procMountsEntries) {
|
||||
if (Arrays.equals(dir, entry.dir()))
|
||||
return entry;
|
||||
}
|
||||
|
||||
throw new IOException("Mount point not found");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||
// support DosFileAttributeView and UserDefinedAttributeView if extended
|
||||
// attributes enabled
|
||||
if (type == DosFileAttributeView.class ||
|
||||
type == UserDefinedFileAttributeView.class)
|
||||
{
|
||||
// lookup fstypes.properties
|
||||
FeatureStatus status = checkIfFeaturePresent("user_xattr");
|
||||
if (status == FeatureStatus.PRESENT)
|
||||
return true;
|
||||
if (status == FeatureStatus.NOT_PRESENT)
|
||||
return false;
|
||||
|
||||
// if file system is mounted with user_xattr option then assume
|
||||
// extended attributes are enabled
|
||||
if ((entry().hasOption("user_xattr")))
|
||||
return true;
|
||||
|
||||
// check for explicit disabling of extended attributes
|
||||
if (entry().hasOption("nouser_xattr")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// user_xattr option not present but we special-case ext4 as we
|
||||
// know that extended attributes are enabled by default
|
||||
if (entry().fstype().equals("ext4")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// not ext4 so probe mount point
|
||||
if (!xattrChecked) {
|
||||
UnixPath dir = new UnixPath(file().getFileSystem(), entry().dir());
|
||||
xattrEnabled = isExtendedAttributesEnabled(dir);
|
||||
xattrChecked = true;
|
||||
}
|
||||
return xattrEnabled;
|
||||
}
|
||||
// POSIX attributes not supported on FAT32
|
||||
if (type == PosixFileAttributeView.class && entry().fstype().equals("vfat"))
|
||||
return false;
|
||||
return super.supportsFileAttributeView(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(String name) {
|
||||
if (name.equals("dos"))
|
||||
return supportsFileAttributeView(DosFileAttributeView.class);
|
||||
if (name.equals("user"))
|
||||
return supportsFileAttributeView(UserDefinedFileAttributeView.class);
|
||||
return super.supportsFileAttributeView(name);
|
||||
}
|
||||
}
|
||||
161
src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java
Normal file
161
src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2022, 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.FileStore;
|
||||
import java.nio.file.WatchService;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import static sun.nio.fs.LinuxNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Linux implementation of FileSystem
|
||||
*/
|
||||
|
||||
class LinuxFileSystem extends UnixFileSystem {
|
||||
LinuxFileSystem(UnixFileSystemProvider provider, String dir) {
|
||||
super(provider, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchService newWatchService()
|
||||
throws IOException
|
||||
{
|
||||
// assume 2.6.13 or newer
|
||||
return new LinuxWatchService(this);
|
||||
}
|
||||
|
||||
|
||||
// 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 Linux-specific views
|
||||
result.add("dos");
|
||||
result.add("user");
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedFileAttributeViews() {
|
||||
return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
|
||||
}
|
||||
|
||||
@Override
|
||||
void copyNonPosixAttributes(int ofd, int nfd) {
|
||||
UnixUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object to iterate over the mount entries in the given fstab file.
|
||||
*/
|
||||
List<UnixMountEntry> getMountEntries(String fstab) {
|
||||
ArrayList<UnixMountEntry> entries = new ArrayList<>();
|
||||
try {
|
||||
long fp = setmntent(Util.toBytes(fstab), Util.toBytes("r"));
|
||||
int maxLineSize = 1024;
|
||||
try {
|
||||
for (;;) {
|
||||
int lineSize = getlinelen(fp);
|
||||
if (lineSize == -1)
|
||||
break;
|
||||
if (lineSize > maxLineSize)
|
||||
maxLineSize = lineSize;
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
// nothing we need to do
|
||||
} finally {
|
||||
rewind(fp);
|
||||
}
|
||||
|
||||
try {
|
||||
for (;;) {
|
||||
UnixMountEntry entry = new UnixMountEntry();
|
||||
// count in NUL character at the end
|
||||
int res = getmntent(fp, entry, maxLineSize + 1);
|
||||
if (res < 0)
|
||||
break;
|
||||
entries.add(entry);
|
||||
}
|
||||
} finally {
|
||||
endmntent(fp);
|
||||
}
|
||||
|
||||
} catch (UnixException x) {
|
||||
// nothing we can do
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object to iterate over the mount entries in /etc/mtab
|
||||
*/
|
||||
@Override
|
||||
List<UnixMountEntry> getMountEntries() {
|
||||
return getMountEntries("/etc/mtab");
|
||||
}
|
||||
|
||||
@Override
|
||||
FileStore getFileStore(UnixMountEntry entry) throws IOException {
|
||||
return new LinuxFileStore(this, entry);
|
||||
}
|
||||
|
||||
// --- file copying ---
|
||||
|
||||
@Override
|
||||
void bufferedCopy(int dst, int src, long address,
|
||||
int size, long addressToPollForCancel)
|
||||
throws UnixException
|
||||
{
|
||||
int advice = POSIX_FADV_SEQUENTIAL | // sequential data access
|
||||
POSIX_FADV_NOREUSE | // will access only once
|
||||
POSIX_FADV_WILLNEED; // will access in near future
|
||||
posix_fadvise(src, 0, 0, advice);
|
||||
|
||||
super.bufferedCopy(dst, src, address, size, addressToPollForCancel);
|
||||
}
|
||||
|
||||
@Override
|
||||
int directCopy(int dst, int src, long addressToPollForCancel)
|
||||
throws UnixException
|
||||
{
|
||||
int advice = POSIX_FADV_SEQUENTIAL | // sequential data access
|
||||
POSIX_FADV_NOREUSE | // will access only once
|
||||
POSIX_FADV_WILLNEED; // will access in near future
|
||||
posix_fadvise(src, 0, 0, advice);
|
||||
|
||||
return directCopy0(dst, src, addressToPollForCancel);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2018, 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 jdk.internal.util.StaticProperty;
|
||||
|
||||
/**
|
||||
* Linux implementation of FileSystemProvider
|
||||
*/
|
||||
|
||||
class LinuxFileSystemProvider extends UnixFileSystemProvider {
|
||||
public LinuxFileSystemProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
LinuxFileSystem newFileSystem(String dir) {
|
||||
return new LinuxFileSystem(this, dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
LinuxFileStore getFileStore(UnixPath path) throws IOException {
|
||||
return new LinuxFileStore(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileAttributeView> V getFileAttributeView(Path obj,
|
||||
Class<V> type,
|
||||
LinkOption... options)
|
||||
{
|
||||
if (type == DosFileAttributeView.class) {
|
||||
return (V) new LinuxDosFileAttributeView(UnixPath.toUnixPath(obj),
|
||||
Util.followLinks(options));
|
||||
}
|
||||
if (type == UserDefinedFileAttributeView.class) {
|
||||
return (V) new LinuxUserDefinedFileAttributeView(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("dos")) {
|
||||
return new LinuxDosFileAttributeView(UnixPath.toUnixPath(obj),
|
||||
Util.followLinks(options));
|
||||
}
|
||||
if (name.equals("user")) {
|
||||
return new LinuxUserDefinedFileAttributeView(UnixPath.toUnixPath(obj),
|
||||
Util.followLinks(options));
|
||||
}
|
||||
return super.getFileAttributeView(obj, name, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends BasicFileAttributes> A readAttributes(Path file,
|
||||
Class<A> type,
|
||||
LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
if (type == DosFileAttributes.class) {
|
||||
DosFileAttributeView view =
|
||||
getFileAttributeView(file, DosFileAttributeView.class, options);
|
||||
return (A) view.readAttributes();
|
||||
} else {
|
||||
return super.readAttributes(file, type, options);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
FileTypeDetector getFileTypeDetector() {
|
||||
String userHome = StaticProperty.userHome();
|
||||
Path userMimeTypes = Path.of(userHome, ".mime.types");
|
||||
Path etcMimeTypes = Path.of("/etc/mime.types");
|
||||
|
||||
return chain(new MimeTypesFileTypeDetector(userMimeTypes),
|
||||
new MimeTypesFileTypeDetector(etcMimeTypes));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2022, 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;
|
||||
|
||||
/**
|
||||
* Linux specific system calls.
|
||||
*/
|
||||
|
||||
class LinuxNativeDispatcher extends UnixNativeDispatcher {
|
||||
private LinuxNativeDispatcher() { }
|
||||
|
||||
/**
|
||||
* FILE *setmntent(const char *filename, const char *type);
|
||||
*/
|
||||
static long setmntent(byte[] filename, byte[] type) throws UnixException {
|
||||
try (NativeBuffer pathBuffer = NativeBuffers.asNativeBuffer(filename);
|
||||
NativeBuffer typeBuffer = NativeBuffers.asNativeBuffer(type)) {
|
||||
return setmntent0(pathBuffer.address(), typeBuffer.address());
|
||||
}
|
||||
}
|
||||
private static native long setmntent0(long pathAddress, long typeAddress)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* int getmntent(FILE *fp, struct mnttab *mp, int len);
|
||||
*/
|
||||
|
||||
static int getmntent(long fp, UnixMountEntry entry, int buflen) throws UnixException {
|
||||
try (NativeBuffer buffer = NativeBuffers.getNativeBuffer(buflen)) {
|
||||
return getmntent0(fp, entry, buffer.address(), buflen);
|
||||
}
|
||||
}
|
||||
|
||||
static native int getmntent0(long fp, UnixMountEntry entry, long buffer, int bufLen)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* int endmntent(FILE* filep);
|
||||
*/
|
||||
static native void endmntent(long stream) throws UnixException;
|
||||
|
||||
/**
|
||||
* int posix_fadvise(int fd, off_t offset, off_t len, int advice);
|
||||
*/
|
||||
static native int posix_fadvise(int fd, long offset, long len, int advice)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* Copies data between file descriptors {@code src} and {@code dst} using
|
||||
* a platform-specific function or system call possibly having kernel
|
||||
* support.
|
||||
*
|
||||
* @param dst destination file descriptor
|
||||
* @param src source file descriptor
|
||||
* @param addressToPollForCancel address to check for cancellation
|
||||
* (a non-zero value written to this address indicates cancel)
|
||||
*
|
||||
* @return 0 on success, UNAVAILABLE if the platform function would block,
|
||||
* UNSUPPORTED_CASE if the call does not work with the given
|
||||
* parameters, or UNSUPPORTED if direct copying is not supported
|
||||
* on this platform
|
||||
*/
|
||||
static native int directCopy0(int dst, int src, long addressToPollForCancel)
|
||||
throws UnixException;
|
||||
|
||||
// initialize
|
||||
private static native void init();
|
||||
|
||||
static {
|
||||
jdk.internal.loader.BootLoader.loadLibrary("nio");
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
class LinuxUserDefinedFileAttributeView
|
||||
extends UnixUserDefinedFileAttributeView
|
||||
{
|
||||
|
||||
LinuxUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
|
||||
super(file, followLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int maxNameLength() {
|
||||
return 255;
|
||||
}
|
||||
|
||||
}
|
||||
455
src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java
Normal file
455
src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2022, 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.util.*;
|
||||
import java.io.IOException;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
||||
/**
|
||||
* Linux implementation of WatchService based on inotify.
|
||||
*
|
||||
* In summary a background thread polls inotify plus a socket used for the wakeup
|
||||
* mechanism. Requests to add or remove a watch, or close the watch service,
|
||||
* cause the thread to wakeup and process the request. Events are processed
|
||||
* by the thread which causes it to signal/queue the corresponding watch keys.
|
||||
*/
|
||||
|
||||
class LinuxWatchService
|
||||
extends AbstractWatchService
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
// background thread to read change events
|
||||
private final Poller poller;
|
||||
|
||||
LinuxWatchService(UnixFileSystem fs) throws IOException {
|
||||
// initialize inotify
|
||||
int ifd = - 1;
|
||||
try {
|
||||
ifd = inotifyInit();
|
||||
} catch (UnixException x) {
|
||||
String msg = (x.errno() == EMFILE) ?
|
||||
"User limit of inotify instances reached or too many open files" :
|
||||
x.errorString();
|
||||
throw new IOException(msg);
|
||||
}
|
||||
|
||||
// configure inotify to be non-blocking
|
||||
// create socketpair used in the close mechanism
|
||||
int sp[] = new int[2];
|
||||
try {
|
||||
configureBlocking(ifd, false);
|
||||
socketpair(sp);
|
||||
configureBlocking(sp[0], false);
|
||||
} catch (UnixException x) {
|
||||
UnixNativeDispatcher.close(ifd, e -> null);
|
||||
throw new IOException(x.errorString());
|
||||
}
|
||||
|
||||
this.poller = new Poller(fs, this, ifd, sp);
|
||||
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 static class LinuxWatchKey extends AbstractWatchKey {
|
||||
// inotify descriptor
|
||||
private final int ifd;
|
||||
// watch descriptor
|
||||
private volatile int wd;
|
||||
|
||||
LinuxWatchKey(UnixPath dir, LinuxWatchService watcher, int ifd, int wd) {
|
||||
super(dir, watcher);
|
||||
this.ifd = ifd;
|
||||
this.wd = wd;
|
||||
}
|
||||
|
||||
int descriptor() {
|
||||
return wd;
|
||||
}
|
||||
|
||||
void invalidate(boolean remove) {
|
||||
if (remove) {
|
||||
try {
|
||||
inotifyRmWatch(ifd, wd);
|
||||
} catch (UnixException x) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
wd = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return (wd != -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (isValid()) {
|
||||
// delegate to poller
|
||||
((LinuxWatchService)watcher()).poller.cancel(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Background thread to read from inotify
|
||||
*/
|
||||
private static class Poller extends AbstractPoller {
|
||||
/**
|
||||
* struct inotify_event {
|
||||
* int wd;
|
||||
* uint32_t mask;
|
||||
* uint32_t len;
|
||||
* char name __flexarr; // present if len > 0
|
||||
* } act_t;
|
||||
*/
|
||||
private static final int SIZEOF_INOTIFY_EVENT = eventSize();
|
||||
private static final int[] offsets = eventOffsets();
|
||||
private static final int OFFSETOF_WD = offsets[0];
|
||||
private static final int OFFSETOF_MASK = offsets[1];
|
||||
private static final int OFFSETOF_LEN = offsets[3];
|
||||
private static final int OFFSETOF_NAME = offsets[4];
|
||||
|
||||
private static final int IN_MODIFY = 0x00000002;
|
||||
private static final int IN_ATTRIB = 0x00000004;
|
||||
private static final int IN_MOVED_FROM = 0x00000040;
|
||||
private static final int IN_MOVED_TO = 0x00000080;
|
||||
private static final int IN_CREATE = 0x00000100;
|
||||
private static final int IN_DELETE = 0x00000200;
|
||||
|
||||
private static final int IN_UNMOUNT = 0x00002000;
|
||||
private static final int IN_Q_OVERFLOW = 0x00004000;
|
||||
private static final int IN_IGNORED = 0x00008000;
|
||||
|
||||
// sizeof buffer for when polling inotify
|
||||
private static final int BUFFER_SIZE = 8192;
|
||||
|
||||
private final UnixFileSystem fs;
|
||||
private final LinuxWatchService watcher;
|
||||
|
||||
// inotify file descriptor
|
||||
private final int ifd;
|
||||
// socketpair used to shutdown polling thread
|
||||
private final int socketpair[];
|
||||
// maps watch descriptor to Key
|
||||
private final Map<Integer,LinuxWatchKey> wdToKey;
|
||||
// address of read buffer
|
||||
private final long address;
|
||||
|
||||
Poller(UnixFileSystem fs, LinuxWatchService watcher, int ifd, int[] sp) {
|
||||
this.fs = fs;
|
||||
this.watcher = watcher;
|
||||
this.ifd = ifd;
|
||||
this.socketpair = sp;
|
||||
this.wdToKey = new HashMap<>();
|
||||
this.address = unsafe.allocateMemory(BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
void wakeup() throws IOException {
|
||||
// write to socketpair to wakeup polling thread
|
||||
try {
|
||||
write(socketpair[1], address, 1);
|
||||
} catch (UnixException x) {
|
||||
throw new IOException(x.errorString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object implRegister(Path obj,
|
||||
Set<? extends WatchEvent.Kind<?>> events,
|
||||
WatchEvent.Modifier... modifiers)
|
||||
{
|
||||
UnixPath dir = (UnixPath)obj;
|
||||
|
||||
int mask = 0;
|
||||
for (WatchEvent.Kind<?> event: events) {
|
||||
if (event == StandardWatchEventKinds.ENTRY_CREATE) {
|
||||
mask |= IN_CREATE | IN_MOVED_TO;
|
||||
continue;
|
||||
}
|
||||
if (event == StandardWatchEventKinds.ENTRY_DELETE) {
|
||||
mask |= IN_DELETE | IN_MOVED_FROM;
|
||||
continue;
|
||||
}
|
||||
if (event == StandardWatchEventKinds.ENTRY_MODIFY) {
|
||||
mask |= IN_MODIFY | IN_ATTRIB;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// no modifiers supported at this time
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
// register with inotify (replaces existing mask if already registered)
|
||||
int wd;
|
||||
try (NativeBuffer buffer =
|
||||
NativeBuffers.asNativeBuffer(dir.getByteArrayForSysCalls())) {
|
||||
wd = inotifyAddWatch(ifd, buffer.address(), mask);
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() == ENOSPC) {
|
||||
return new IOException("User limit of inotify watches reached");
|
||||
}
|
||||
return x.asIOException(dir);
|
||||
}
|
||||
|
||||
// ensure watch descriptor is in map
|
||||
LinuxWatchKey key = wdToKey.get(wd);
|
||||
if (key == null) {
|
||||
key = new LinuxWatchKey(dir, watcher, ifd, wd);
|
||||
wdToKey.put(wd, key);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
// cancel single key
|
||||
@Override
|
||||
void implCancelKey(WatchKey obj) {
|
||||
LinuxWatchKey key = (LinuxWatchKey)obj;
|
||||
if (key.isValid()) {
|
||||
wdToKey.remove(key.descriptor());
|
||||
key.invalidate(true);
|
||||
}
|
||||
}
|
||||
|
||||
// close watch service
|
||||
@Override
|
||||
void implCloseAll() {
|
||||
// invalidate all keys
|
||||
for (Map.Entry<Integer,LinuxWatchKey> entry: wdToKey.entrySet()) {
|
||||
entry.getValue().invalidate(true);
|
||||
}
|
||||
wdToKey.clear();
|
||||
|
||||
// free resources
|
||||
unsafe.freeMemory(address);
|
||||
UnixNativeDispatcher.close(socketpair[0], e -> null);
|
||||
UnixNativeDispatcher.close(socketpair[1], e -> null);
|
||||
UnixNativeDispatcher.close(ifd, e -> null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Poller main loop
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (;;) {
|
||||
int nReady, bytesRead;
|
||||
|
||||
// wait for close or inotify event
|
||||
nReady = poll(ifd, socketpair[0]);
|
||||
|
||||
// read from inotify
|
||||
try {
|
||||
bytesRead = read(ifd, address, BUFFER_SIZE);
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() != EAGAIN && x.errno() != EWOULDBLOCK)
|
||||
throw x;
|
||||
bytesRead = 0;
|
||||
}
|
||||
|
||||
// iterate over buffer to decode events
|
||||
int offset = 0;
|
||||
while (offset < bytesRead) {
|
||||
long event = address + offset;
|
||||
int wd = unsafe.getInt(event + OFFSETOF_WD);
|
||||
int mask = unsafe.getInt(event + OFFSETOF_MASK);
|
||||
int len = unsafe.getInt(event + OFFSETOF_LEN);
|
||||
|
||||
// file name
|
||||
UnixPath name = null;
|
||||
if (len > 0) {
|
||||
int actual = len;
|
||||
|
||||
// null-terminated and maybe additional null bytes to
|
||||
// align the next event
|
||||
while (actual > 0) {
|
||||
long last = event + OFFSETOF_NAME + actual - 1;
|
||||
if (unsafe.getByte(last) != 0)
|
||||
break;
|
||||
actual--;
|
||||
}
|
||||
if (actual > 0) {
|
||||
byte[] buf = new byte[actual];
|
||||
unsafe.copyMemory(null, event + OFFSETOF_NAME,
|
||||
buf, Unsafe.ARRAY_BYTE_BASE_OFFSET, actual);
|
||||
name = new UnixPath(fs, buf);
|
||||
}
|
||||
}
|
||||
|
||||
// process event
|
||||
processEvent(wd, mask, name);
|
||||
|
||||
offset += (SIZEOF_INOTIFY_EVENT + len);
|
||||
}
|
||||
|
||||
// process any pending requests
|
||||
if ((nReady > 1) || (nReady == 1 && bytesRead == 0)) {
|
||||
try {
|
||||
read(socketpair[0], address, BUFFER_SIZE);
|
||||
boolean shutdown = processRequests();
|
||||
if (shutdown)
|
||||
break;
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() != EAGAIN && x.errno() != EWOULDBLOCK)
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* map inotify event to WatchEvent.Kind
|
||||
*/
|
||||
private WatchEvent.Kind<?> maskToEventKind(int mask) {
|
||||
if ((mask & IN_MODIFY) > 0)
|
||||
return StandardWatchEventKinds.ENTRY_MODIFY;
|
||||
if ((mask & IN_ATTRIB) > 0)
|
||||
return StandardWatchEventKinds.ENTRY_MODIFY;
|
||||
if ((mask & IN_CREATE) > 0)
|
||||
return StandardWatchEventKinds.ENTRY_CREATE;
|
||||
if ((mask & IN_MOVED_TO) > 0)
|
||||
return StandardWatchEventKinds.ENTRY_CREATE;
|
||||
if ((mask & IN_DELETE) > 0)
|
||||
return StandardWatchEventKinds.ENTRY_DELETE;
|
||||
if ((mask & IN_MOVED_FROM) > 0)
|
||||
return StandardWatchEventKinds.ENTRY_DELETE;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process event from inotify
|
||||
*/
|
||||
private void processEvent(int wd, int mask, final UnixPath name) {
|
||||
// overflow - signal all keys
|
||||
if ((mask & IN_Q_OVERFLOW) > 0) {
|
||||
for (Map.Entry<Integer,LinuxWatchKey> entry: wdToKey.entrySet()) {
|
||||
entry.getValue()
|
||||
.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// lookup wd to get key
|
||||
LinuxWatchKey key = wdToKey.get(wd);
|
||||
if (key == null)
|
||||
return; // should not happen
|
||||
|
||||
// file deleted
|
||||
if ((mask & IN_IGNORED) > 0) {
|
||||
wdToKey.remove(wd);
|
||||
key.invalidate(false);
|
||||
key.signal();
|
||||
return;
|
||||
}
|
||||
|
||||
// event for directory itself
|
||||
if (name == null)
|
||||
return;
|
||||
|
||||
// map to event and queue to key
|
||||
WatchEvent.Kind<?> kind = maskToEventKind(mask);
|
||||
if (kind != null) {
|
||||
key.signalEvent(kind, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- native methods --
|
||||
|
||||
// sizeof inotify_event
|
||||
private static native int eventSize();
|
||||
|
||||
// offsets of inotify_event
|
||||
private static native int[] eventOffsets();
|
||||
|
||||
private static native int inotifyInit() throws UnixException;
|
||||
|
||||
private static native int inotifyAddWatch(int fd, long pathAddress, int mask)
|
||||
throws UnixException;
|
||||
|
||||
private static native void inotifyRmWatch(int fd, int wd)
|
||||
throws UnixException;
|
||||
|
||||
private static native void configureBlocking(int fd, boolean blocking)
|
||||
throws UnixException;
|
||||
|
||||
private static native void socketpair(int[] sv) throws UnixException;
|
||||
|
||||
private static native int poll(int fd1, int fd2) throws UnixException;
|
||||
|
||||
static {
|
||||
jdk.internal.loader.BootLoader.loadLibrary("nio");
|
||||
}
|
||||
}
|
||||
64
src/java.base/linux/native/libjava/CgroupMetrics.c
Normal file
64
src/java.base/linux/native/libjava/CgroupMetrics.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2024, Red Hat, Inc.
|
||||
* 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.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvm.h"
|
||||
|
||||
#include "jdk_internal_platform_CgroupMetrics.h"
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_internal_platform_CgroupMetrics_isUseContainerSupport(JNIEnv *env, jclass ignored)
|
||||
{
|
||||
return JVM_IsUseContainerSupport();
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_jdk_internal_platform_CgroupMetrics_isContainerized0(JNIEnv *env, jclass ignored)
|
||||
{
|
||||
return JVM_IsContainerized();
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_platform_CgroupMetrics_getTotalMemorySize0
|
||||
(JNIEnv *env, jclass ignored)
|
||||
{
|
||||
jlong pages = sysconf(_SC_PHYS_PAGES);
|
||||
jlong page_size = sysconf(_SC_PAGESIZE);
|
||||
return pages * page_size;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_platform_CgroupMetrics_getTotalSwapSize0
|
||||
(JNIEnv *env, jclass ignored)
|
||||
{
|
||||
struct sysinfo si;
|
||||
int retval = sysinfo(&si);
|
||||
if (retval < 0) {
|
||||
return 0; // syinfo failed, treat as no swap
|
||||
}
|
||||
return (jlong)(si.totalswap * si.mem_unit);
|
||||
}
|
||||
393
src/java.base/linux/native/libjava/ProcessHandleImpl_linux.c
Normal file
393
src/java.base/linux/native/libjava/ProcessHandleImpl_linux.c
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2025, 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "java_lang_ProcessHandleImpl.h"
|
||||
#include "java_lang_ProcessHandleImpl_Info.h"
|
||||
|
||||
#include "ProcessHandleImpl_unix.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* Implementation of native ProcessHandleImpl functions for Linux.
|
||||
* See ProcessHandleImpl_unix.c for more details.
|
||||
*/
|
||||
|
||||
/* Signatures for internal OS specific functions. */
|
||||
static long long getBoottime(JNIEnv *env);
|
||||
|
||||
/* A static offset in milliseconds since boot. */
|
||||
static long long bootTime_ms;
|
||||
static long clock_ticks_per_second;
|
||||
static int pageSize;
|
||||
|
||||
void os_initNative(JNIEnv *env, jclass clazz) {
|
||||
bootTime_ms = getBoottime(env);
|
||||
clock_ticks_per_second = sysconf(_SC_CLK_TCK);
|
||||
pageSize = sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pids of active processes, and optionally parent pids and
|
||||
* start times for each process.
|
||||
* For a specific non-zero pid, only the direct children are returned.
|
||||
* If the pid is zero, all active processes are returned.
|
||||
* Reads /proc and accumulates any process following the rules above.
|
||||
* The resulting pids are stored into an array of longs named jarray.
|
||||
* The number of pids is returned if they all fit.
|
||||
* If the parentArray is non-null, store also the parent pid.
|
||||
* In this case the parentArray must have the same length as the result pid array.
|
||||
* Of course in the case of a given non-zero pid all entries in the parentArray
|
||||
* will contain this pid, so this array does only make sense in the case of a given
|
||||
* zero pid.
|
||||
* If the jstimesArray is non-null, store also the start time of the pid.
|
||||
* In this case the jstimesArray must have the same length as the result pid array.
|
||||
* If the array(s) (is|are) too short, excess pids are not stored and
|
||||
* the desired length is returned.
|
||||
*/
|
||||
jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
|
||||
jlongArray jparentArray, jlongArray jstimesArray) {
|
||||
DIR* dir;
|
||||
struct dirent* ptr;
|
||||
pid_t pid = (pid_t) jpid;
|
||||
jlong* pids = NULL;
|
||||
jlong* ppids = NULL;
|
||||
jlong* stimes = NULL;
|
||||
jsize parentArraySize = 0;
|
||||
jsize arraySize = 0;
|
||||
jsize stimesSize = 0;
|
||||
jsize count = 0;
|
||||
|
||||
arraySize = (*env)->GetArrayLength(env, jarray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
if (jparentArray != NULL) {
|
||||
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != parentArraySize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != stimesSize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* To locate the children we scan /proc looking for files that have a
|
||||
* position integer as a filename.
|
||||
*/
|
||||
if ((dir = opendir("/proc")) == NULL) {
|
||||
JNU_ThrowByNameWithMessageAndLastError(env,
|
||||
"java/lang/RuntimeException", "Unable to open /proc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
do { // Block to break out of on Exception
|
||||
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
|
||||
if (pids == NULL) {
|
||||
break;
|
||||
}
|
||||
if (jparentArray != NULL) {
|
||||
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
|
||||
if (ppids == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
|
||||
if (stimes == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((ptr = readdir(dir)) != NULL) {
|
||||
pid_t ppid = 0;
|
||||
jlong totalTime = 0L;
|
||||
jlong startTime = 0L;
|
||||
|
||||
/* skip files that aren't numbers */
|
||||
pid_t childpid = (pid_t) atoi(ptr->d_name);
|
||||
if ((int) childpid <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the parent pid, and start time
|
||||
ppid = os_getParentPidAndTimings(env, childpid, &totalTime, &startTime);
|
||||
if (ppid >= 0 && (pid == 0 || ppid == pid)) {
|
||||
if (count < arraySize) {
|
||||
// Only store if it fits
|
||||
pids[count] = (jlong) childpid;
|
||||
|
||||
if (ppids != NULL) {
|
||||
// Store the parentPid
|
||||
ppids[count] = (jlong) ppid;
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
// Store the process start time
|
||||
stimes[count] = startTime;
|
||||
}
|
||||
}
|
||||
count++; // Count to tabulate size needed
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (pids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
|
||||
}
|
||||
if (ppids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
// If more pids than array had size for; count will be greater than array size
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read /proc/<pid>/stat and return the ppid, total cputime and start time.
|
||||
* -1 is fail; >= 0 is parent pid
|
||||
* 'total' will contain the running time of 'pid' in nanoseconds.
|
||||
* 'start' will contain the start time of 'pid' in milliseconds since epoch.
|
||||
*/
|
||||
pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid,
|
||||
jlong *totalTime, jlong* startTime) {
|
||||
FILE* fp;
|
||||
char buffer[2048];
|
||||
int statlen;
|
||||
char fn[32];
|
||||
char* s;
|
||||
int parentPid;
|
||||
long unsigned int utime = 0; // clock tics
|
||||
long unsigned int stime = 0; // clock tics
|
||||
long long unsigned int start = 0; // microseconds
|
||||
|
||||
/*
|
||||
* Try to stat and then open /proc/%d/stat
|
||||
*/
|
||||
snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
|
||||
|
||||
fp = fopen(fn, "r");
|
||||
if (fp == NULL) {
|
||||
return -1; // fail, no such /proc/pid/stat
|
||||
}
|
||||
|
||||
/*
|
||||
* The format is: pid (command) state ppid ...
|
||||
* As the command could be anything we must find the right most
|
||||
* ")" and then skip the white spaces that follow it.
|
||||
*/
|
||||
statlen = fread(buffer, 1, (sizeof buffer - 1), fp);
|
||||
fclose(fp);
|
||||
if (statlen < 0) {
|
||||
return -1; // parent pid is not available
|
||||
}
|
||||
|
||||
buffer[statlen] = '\0';
|
||||
s = strchr(buffer, '(');
|
||||
if (s == NULL) {
|
||||
return -1; // parent pid is not available
|
||||
}
|
||||
// Found start of command, skip to end
|
||||
s++;
|
||||
s = strrchr(s, ')');
|
||||
if (s == NULL) {
|
||||
return -1; // parent pid is not available
|
||||
}
|
||||
s++;
|
||||
|
||||
// Scan the needed fields from status, retaining only ppid(4),
|
||||
// utime (14), stime(15), starttime(22)
|
||||
if (4 != sscanf(s, " %*c %d %*d %*d %*d %*d %*d %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %llu",
|
||||
&parentPid, &utime, &stime, &start)) {
|
||||
return 0; // not all values parsed; return error
|
||||
}
|
||||
|
||||
*totalTime = (utime + stime) * (jlong)(1000000000 / clock_ticks_per_second);
|
||||
|
||||
*startTime = bootTime_ms + ((start * 1000) / clock_ticks_per_second);
|
||||
|
||||
return parentPid;
|
||||
}
|
||||
|
||||
void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
|
||||
int fd;
|
||||
int cmdlen = 0;
|
||||
char *cmdline = NULL, *cmdEnd = NULL; // used for command line args and exe
|
||||
char *args = NULL;
|
||||
jstring cmdexe = NULL;
|
||||
char fn[32];
|
||||
struct stat stat_buf;
|
||||
|
||||
/*
|
||||
* Stat /proc/<pid> to get the user id
|
||||
*/
|
||||
snprintf(fn, sizeof fn, "/proc/%d", pid);
|
||||
if (stat(fn, &stat_buf) == 0) {
|
||||
unix_getUserInfo(env, jinfo, stat_buf.st_uid);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to open /proc/<pid>/cmdline
|
||||
*/
|
||||
strncat(fn, "/cmdline", sizeof fn - strnlen(fn, sizeof fn) - 1);
|
||||
if ((fd = open(fn, O_RDONLY)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
do { // Block to break out of on errors
|
||||
int i, truncated = 0;
|
||||
int count;
|
||||
char *s;
|
||||
|
||||
/*
|
||||
* The path name read by readlink() is limited to PATH_MAX characters.
|
||||
* The content of /proc/<pid>/cmdline is limited to PAGE_SIZE characters.
|
||||
*/
|
||||
cmdline = (char*)malloc((PATH_MAX > pageSize ? PATH_MAX : pageSize) + 1);
|
||||
if (cmdline == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* On Linux, the full path to the executable command is the link in
|
||||
* /proc/<pid>/exe. But it is only readable for processes we own.
|
||||
*/
|
||||
snprintf(fn, sizeof fn, "/proc/%d/exe", pid);
|
||||
if ((cmdlen = readlink(fn, cmdline, PATH_MAX)) > 0) {
|
||||
// null terminate and create String to store for command
|
||||
cmdline[cmdlen] = '\0';
|
||||
cmdexe = JNU_NewStringPlatform(env, cmdline);
|
||||
(*env)->ExceptionClear(env); // unconditionally clear any exception
|
||||
}
|
||||
|
||||
/*
|
||||
* The command-line arguments appear as a set of strings separated by
|
||||
* null bytes ('\0'), with a further null byte after the last
|
||||
* string. The last string is only null terminated if the whole command
|
||||
* line is not exceeding (PAGE_SIZE - 1) characters.
|
||||
*/
|
||||
cmdlen = 0;
|
||||
s = cmdline;
|
||||
while ((count = read(fd, s, pageSize - cmdlen)) > 0) {
|
||||
cmdlen += count;
|
||||
s += count;
|
||||
}
|
||||
if (count < 0) {
|
||||
break;
|
||||
}
|
||||
// We have to null-terminate because the process may have changed argv[]
|
||||
// or because the content in /proc/<pid>/cmdline is truncated.
|
||||
cmdline[cmdlen] = '\0';
|
||||
if (cmdlen == pageSize && cmdline[pageSize - 1] != '\0') {
|
||||
truncated = 1;
|
||||
} else if (cmdlen == 0) {
|
||||
// /proc/<pid>/cmdline was empty. This usually happens for kernel processes
|
||||
// like '[kthreadd]'. We could try to read /proc/<pid>/comm in the future.
|
||||
}
|
||||
if (cmdlen > 0 && (cmdexe == NULL || truncated)) {
|
||||
// We have no exact command or the arguments are truncated.
|
||||
// In this case we save the command line from /proc/<pid>/cmdline.
|
||||
args = (char*)malloc(pageSize + 1);
|
||||
if (args != NULL) {
|
||||
memcpy(args, cmdline, cmdlen + 1);
|
||||
for (i = 0; i < cmdlen; i++) {
|
||||
if (args[i] == '\0') {
|
||||
args[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
if (!truncated) {
|
||||
// Count the arguments
|
||||
cmdEnd = &cmdline[cmdlen];
|
||||
for (s = cmdline; *s != '\0' && (s < cmdEnd); i++) {
|
||||
s += strnlen(s, (cmdEnd - s)) + 1;
|
||||
}
|
||||
}
|
||||
unix_fillArgArray(env, jinfo, i, cmdline, cmdEnd, cmdexe, args);
|
||||
} while (0);
|
||||
|
||||
if (cmdline != NULL) {
|
||||
free(cmdline);
|
||||
}
|
||||
if (args != NULL) {
|
||||
free(args);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the boottime from /proc/stat.
|
||||
*/
|
||||
static long long getBoottime(JNIEnv *env) {
|
||||
FILE *fp;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
long long bootTime = 0;
|
||||
|
||||
fp = fopen("/proc/stat", "r");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (getline(&line, &len, fp) != -1) {
|
||||
if (sscanf(line, "btime %llu", &bootTime) == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
|
||||
if (fp != 0) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return bootTime * 1000;
|
||||
}
|
||||
96
src/java.base/linux/native/libnio/ch/EPoll.c
Normal file
96
src/java.base/linux/native/libnio/ch/EPoll.c
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2020, 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.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_EPoll.h"
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return sizeof(struct epoll_event);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return offsetof(struct epoll_event, events);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
return offsetof(struct epoll_event, data);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_create(JNIEnv *env, jclass clazz) {
|
||||
int epfd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (epfd < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_create1 failed");
|
||||
}
|
||||
return epfd;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_ctl(JNIEnv *env, jclass clazz, jint epfd,
|
||||
jint opcode, jint fd, jint events)
|
||||
{
|
||||
struct epoll_event event;
|
||||
int res;
|
||||
|
||||
event.events = events;
|
||||
event.data.fd = fd;
|
||||
|
||||
res = epoll_ctl(epfd, (int)opcode, (int)fd, &event);
|
||||
return (res == 0) ? 0 : errno;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EPoll_wait(JNIEnv *env, jclass clazz, jint epfd,
|
||||
jlong address, jint numfds, jint timeout)
|
||||
{
|
||||
struct epoll_event *events = jlong_to_ptr(address);
|
||||
int res = epoll_wait(epfd, events, numfds, timeout);
|
||||
if (res < 0) {
|
||||
if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
} else {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
54
src/java.base/linux/native/libnio/ch/EventFD.c
Normal file
54
src/java.base/linux/native/libnio/ch/EventFD.c
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_EventFD.h"
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EventFD_eventfd0(JNIEnv *env, jclass klazz)
|
||||
{
|
||||
int efd = eventfd((uint64_t)0, 0);
|
||||
if (efd == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "eventfd failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return efd;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_EventFD_set0(JNIEnv *env, jclass klazz, jint efd)
|
||||
{
|
||||
uint64_t one = 1ULL;
|
||||
return convertReturnVal(env, write(efd, (void*)&one, sizeof(uint64_t)),
|
||||
JNI_FALSE);
|
||||
}
|
||||
131
src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c
Normal file
131
src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2026, 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.
|
||||
*/
|
||||
|
||||
#include <sys/sendfile.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
#include "sun_nio_ch_FileDispatcherImpl.h"
|
||||
|
||||
typedef ssize_t copy_file_range_func(int, loff_t*, int, loff_t*, size_t,
|
||||
unsigned int);
|
||||
static copy_file_range_func* my_copy_file_range_func = NULL;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_init0(JNIEnv *env, jclass klass)
|
||||
{
|
||||
my_copy_file_range_func =
|
||||
(copy_file_range_func*) dlsym(RTLD_DEFAULT, "copy_file_range");
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_transferFrom0(JNIEnv *env, jobject this,
|
||||
jobject srcFDO, jobject dstFDO,
|
||||
jlong position, jlong count,
|
||||
jboolean append)
|
||||
{
|
||||
if (my_copy_file_range_func == NULL)
|
||||
return IOS_UNSUPPORTED;
|
||||
// copy_file_range fails with EBADF when appending
|
||||
if (append == JNI_TRUE)
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
|
||||
jint srcFD = fdval(env, srcFDO);
|
||||
jint dstFD = fdval(env, dstFDO);
|
||||
|
||||
loff_t offset = (loff_t)position;
|
||||
size_t len = (size_t)count;
|
||||
jlong n = my_copy_file_range_func(srcFD, NULL, dstFD, &offset, len, 0);
|
||||
if (n < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return IOS_UNAVAILABLE;
|
||||
if (errno == ENOSYS || errno == EOPNOTSUPP)
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
if ((errno == EBADF || errno == EINVAL || errno == EXDEV) &&
|
||||
((ssize_t)count >= 0))
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
}
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this,
|
||||
jobject srcFDO,
|
||||
jlong position, jlong count,
|
||||
jobject dstFDO, jboolean append)
|
||||
{
|
||||
jint srcFD = fdval(env, srcFDO);
|
||||
jint dstFD = fdval(env, dstFDO);
|
||||
|
||||
// copy_file_range fails with EBADF when appending, and sendfile
|
||||
// fails with EINVAL
|
||||
if (append == JNI_TRUE)
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
|
||||
loff_t offset = (loff_t)position;
|
||||
jlong n;
|
||||
if (my_copy_file_range_func != NULL) {
|
||||
size_t len = (size_t)count;
|
||||
n = my_copy_file_range_func(srcFD, &offset, dstFD, NULL, len, 0);
|
||||
if (n < 0) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
return IOS_INTERRUPTED;
|
||||
case EINVAL:
|
||||
case ENOSYS:
|
||||
case EXDEV:
|
||||
case EOPNOTSUPP:
|
||||
// ignore and try sendfile()
|
||||
break;
|
||||
default:
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Copy failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
if (n >= 0)
|
||||
return n;
|
||||
}
|
||||
|
||||
n = sendfile(dstFD, srcFD, &offset, (size_t)count);
|
||||
if (n < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return IOS_UNAVAILABLE;
|
||||
if ((errno == EINVAL) && ((ssize_t)count >= 0))
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
}
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
231
src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c
Normal file
231
src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2026, 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include "nio.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <mntent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/sendfile.h>
|
||||
|
||||
#include "sun_nio_fs_LinuxNativeDispatcher.h"
|
||||
|
||||
static jfieldID entry_name;
|
||||
static jfieldID entry_dir;
|
||||
static jfieldID entry_fstype;
|
||||
static jfieldID entry_options;
|
||||
|
||||
typedef ssize_t copy_file_range_func(int, loff_t*, int, loff_t*, size_t,
|
||||
unsigned int);
|
||||
static copy_file_range_func* my_copy_file_range_func = NULL;
|
||||
|
||||
static void throwUnixException(JNIEnv* env, int errnum) {
|
||||
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
|
||||
"(I)V", errnum);
|
||||
if (x != NULL) {
|
||||
(*env)->Throw(env, x);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
|
||||
CHECK_NULL(clazz);
|
||||
entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
|
||||
CHECK_NULL(entry_name);
|
||||
entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
|
||||
CHECK_NULL(entry_dir);
|
||||
entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
|
||||
CHECK_NULL(entry_fstype);
|
||||
entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
|
||||
CHECK_NULL(entry_options);
|
||||
|
||||
my_copy_file_range_func =
|
||||
(copy_file_range_func*) dlsym(RTLD_DEFAULT, "copy_file_range");
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress,
|
||||
jlong modeAddress)
|
||||
{
|
||||
FILE* fp = NULL;
|
||||
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||
const char* mode = (const char*)jlong_to_ptr(modeAddress);
|
||||
|
||||
do {
|
||||
fp = setmntent(path, mode);
|
||||
} while (fp == NULL && errno == EINTR);
|
||||
if (fp == NULL) {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
return ptr_to_jlong(fp);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_LinuxNativeDispatcher_getmntent0(JNIEnv* env, jclass this,
|
||||
jlong value, jobject entry, jlong buffer, jint bufLen)
|
||||
{
|
||||
struct mntent ent;
|
||||
char * buf = (char*)jlong_to_ptr(buffer);
|
||||
struct mntent* m;
|
||||
FILE* fp = jlong_to_ptr(value);
|
||||
jsize len;
|
||||
jbyteArray bytes;
|
||||
char* name;
|
||||
char* dir;
|
||||
char* fstype;
|
||||
char* options;
|
||||
|
||||
m = getmntent_r(fp, &ent, buf, (int)bufLen);
|
||||
if (m == NULL)
|
||||
return -1;
|
||||
name = m->mnt_fsname;
|
||||
dir = m->mnt_dir;
|
||||
fstype = m->mnt_type;
|
||||
options = m->mnt_opts;
|
||||
|
||||
len = strlen(name);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name);
|
||||
(*env)->SetObjectField(env, entry, entry_name, bytes);
|
||||
|
||||
len = strlen(dir);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir);
|
||||
(*env)->SetObjectField(env, entry, entry_dir, bytes);
|
||||
|
||||
len = strlen(fstype);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
|
||||
(*env)->SetObjectField(env, entry, entry_fstype, bytes);
|
||||
|
||||
len = strlen(options);
|
||||
bytes = (*env)->NewByteArray(env, len);
|
||||
if (bytes == NULL)
|
||||
return -1;
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options);
|
||||
(*env)->SetObjectField(env, entry, entry_options, bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv* env, jclass this, jlong stream)
|
||||
{
|
||||
FILE* fp = jlong_to_ptr(stream);
|
||||
// The endmntent() function always returns 1.
|
||||
endmntent(fp);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_LinuxNativeDispatcher_posix_1fadvise(JNIEnv* env, jclass this,
|
||||
jint fd, jlong offset, jlong len, jint advice)
|
||||
{
|
||||
return posix_fadvise((int)fd, (off_t)offset, (off_t)len, (int)advice);
|
||||
}
|
||||
|
||||
// Copy all bytes from src to dst, within the kernel if possible,
|
||||
// and return zero, otherwise return the appropriate status code.
|
||||
//
|
||||
// Return value
|
||||
// 0 on success
|
||||
// IOS_UNAVAILABLE if the platform function would block
|
||||
// IOS_UNSUPPORTED_CASE if the call does not work with the given parameters
|
||||
// IOS_UNSUPPORTED if direct copying is not supported on this platform
|
||||
// IOS_THROWN if a Java exception is thrown
|
||||
//
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_LinuxNativeDispatcher_directCopy0
|
||||
(JNIEnv* env, jclass this, jint dst, jint src, jlong cancelAddress)
|
||||
{
|
||||
volatile jint* cancel = (jint*)jlong_to_ptr(cancelAddress);
|
||||
|
||||
// Transfer within the kernel
|
||||
const size_t count = cancel != NULL ?
|
||||
1048576 : // 1 MB to give cancellation a chance
|
||||
0x7ffff000; // maximum number of bytes that sendfile() can transfer
|
||||
|
||||
ssize_t bytes_sent;
|
||||
if (my_copy_file_range_func != NULL) {
|
||||
do {
|
||||
RESTARTABLE(my_copy_file_range_func(src, NULL, dst, NULL, count, 0),
|
||||
bytes_sent);
|
||||
if (bytes_sent < 0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
case ENOSYS:
|
||||
case EXDEV:
|
||||
case EOPNOTSUPP:
|
||||
// ignore and try sendfile()
|
||||
break;
|
||||
default:
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Copy failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
if (cancel != NULL && *cancel != 0) {
|
||||
throwUnixException(env, ECANCELED);
|
||||
return IOS_THROWN;
|
||||
}
|
||||
} while (bytes_sent > 0);
|
||||
|
||||
if (bytes_sent == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
RESTARTABLE(sendfile(dst, src, NULL, count), bytes_sent);
|
||||
if (bytes_sent < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return IOS_UNAVAILABLE;
|
||||
if (errno == EINVAL || errno == ENOSYS)
|
||||
return IOS_UNSUPPORTED_CASE;
|
||||
throwUnixException(env, errno);
|
||||
return IOS_THROWN;
|
||||
}
|
||||
if (cancel != NULL && *cancel != 0) {
|
||||
throwUnixException(env, ECANCELED);
|
||||
return IOS_THROWN;
|
||||
}
|
||||
} while (bytes_sent > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
153
src/java.base/linux/native/libnio/fs/LinuxWatchService.c
Normal file
153
src/java.base/linux/native/libnio/fs/LinuxWatchService.c
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2011, 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <poll.h>
|
||||
#include <sys/inotify.h>
|
||||
|
||||
#include "sun_nio_fs_LinuxWatchService.h"
|
||||
|
||||
static void throwUnixException(JNIEnv* env, int errnum) {
|
||||
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
|
||||
"(I)V", errnum);
|
||||
if (x != NULL) {
|
||||
(*env)->Throw(env, x);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_eventSize(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
return (jint)sizeof(struct inotify_event);
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_eventOffsets(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
jintArray result = (*env)->NewIntArray(env, 5);
|
||||
if (result != NULL) {
|
||||
jint arr[5];
|
||||
arr[0] = (jint)offsetof(struct inotify_event, wd);
|
||||
arr[1] = (jint)offsetof(struct inotify_event, mask);
|
||||
arr[2] = (jint)offsetof(struct inotify_event, cookie);
|
||||
arr[3] = (jint)offsetof(struct inotify_event, len);
|
||||
arr[4] = (jint)offsetof(struct inotify_event, name);
|
||||
(*env)->SetIntArrayRegion(env, result, 0, 5, arr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_inotifyInit
|
||||
(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
int ifd = inotify_init();
|
||||
if (ifd == -1) {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
return (jint)ifd;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_inotifyAddWatch
|
||||
(JNIEnv* env, jclass clazz, jint fd, jlong address, jint mask)
|
||||
{
|
||||
int wfd = -1;
|
||||
const char* path = (const char*)jlong_to_ptr(address);
|
||||
|
||||
wfd = inotify_add_watch((int)fd, path, mask);
|
||||
if (wfd == -1) {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
return (jint)wfd;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_inotifyRmWatch
|
||||
(JNIEnv* env, jclass clazz, jint fd, jint wd)
|
||||
{
|
||||
int err = inotify_rm_watch((int)fd, (int)wd);
|
||||
if (err == -1)
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_configureBlocking
|
||||
(JNIEnv* env, jclass clazz, jint fd, jboolean blocking)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
|
||||
if ((blocking == JNI_FALSE) && !(flags & O_NONBLOCK))
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
else if ((blocking == JNI_TRUE) && (flags & O_NONBLOCK))
|
||||
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_socketpair
|
||||
(JNIEnv* env, jclass clazz, jintArray sv)
|
||||
{
|
||||
int sp[2];
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
|
||||
throwUnixException(env, errno);
|
||||
} else {
|
||||
jint res[2];
|
||||
res[0] = (jint)sp[0];
|
||||
res[1] = (jint)sp[1];
|
||||
(*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_LinuxWatchService_poll
|
||||
(JNIEnv* env, jclass clazz, jint fd1, jint fd2)
|
||||
{
|
||||
struct pollfd ufds[2];
|
||||
int n;
|
||||
|
||||
ufds[0].fd = fd1;
|
||||
ufds[0].events = POLLIN;
|
||||
ufds[1].fd = fd2;
|
||||
ufds[1].events = POLLIN;
|
||||
|
||||
n = poll(&ufds[0], 2, -1);
|
||||
if (n == -1) {
|
||||
if (errno == EINTR) {
|
||||
n = 0;
|
||||
} else {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
}
|
||||
return (jint)n;
|
||||
}
|
||||
367
src/java.base/linux/native/libsimdsort/avx2-32bit-qsort.hpp
Normal file
367
src/java.base/linux/native/libsimdsort/avx2-32bit-qsort.hpp
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
#ifndef AVX2_QSORT_32BIT
|
||||
#define AVX2_QSORT_32BIT
|
||||
|
||||
#include "avx2-emu-funcs.hpp"
|
||||
#include "xss-common-qsort.h"
|
||||
|
||||
/*
|
||||
* Constants used in sorting 8 elements in a ymm registers. Based on Bitonic
|
||||
* sorting network (see
|
||||
* https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg)
|
||||
*/
|
||||
|
||||
// ymm 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define NETWORK_32BIT_AVX2_1 4, 5, 6, 7, 0, 1, 2, 3
|
||||
#define NETWORK_32BIT_AVX2_2 0, 1, 2, 3, 4, 5, 6, 7
|
||||
#define NETWORK_32BIT_AVX2_3 5, 4, 7, 6, 1, 0, 3, 2
|
||||
#define NETWORK_32BIT_AVX2_4 3, 2, 1, 0, 7, 6, 5, 4
|
||||
|
||||
/*
|
||||
* Assumes ymm is random and performs a full sorting network defined in
|
||||
* https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg
|
||||
*/
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_INLINE reg_t sort_ymm_32bit(reg_t ymm) {
|
||||
const typename vtype::opmask_t oxAA = _mm256_set_epi32(
|
||||
0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF, 0);
|
||||
const typename vtype::opmask_t oxCC = _mm256_set_epi32(
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0);
|
||||
const typename vtype::opmask_t oxF0 = _mm256_set_epi32(
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0, 0);
|
||||
|
||||
const typename vtype::ymmi_t rev_index = vtype::seti(NETWORK_32BIT_AVX2_2);
|
||||
ymm = cmp_merge<vtype>(
|
||||
ymm, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(ymm), oxAA);
|
||||
ymm = cmp_merge<vtype>(
|
||||
ymm, vtype::permutexvar(vtype::seti(NETWORK_32BIT_AVX2_1), ymm), oxCC);
|
||||
ymm = cmp_merge<vtype>(
|
||||
ymm, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(ymm), oxAA);
|
||||
ymm = cmp_merge<vtype>(ymm, vtype::permutexvar(rev_index, ymm), oxF0);
|
||||
ymm = cmp_merge<vtype>(
|
||||
ymm, vtype::permutexvar(vtype::seti(NETWORK_32BIT_AVX2_3), ymm), oxCC);
|
||||
ymm = cmp_merge<vtype>(
|
||||
ymm, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(ymm), oxAA);
|
||||
return ymm;
|
||||
}
|
||||
|
||||
struct avx2_32bit_swizzle_ops;
|
||||
|
||||
template <>
|
||||
struct avx2_vector<int32_t> {
|
||||
using type_t = int32_t;
|
||||
using reg_t = __m256i;
|
||||
using ymmi_t = __m256i;
|
||||
using opmask_t = __m256i;
|
||||
static const uint8_t numlanes = 8;
|
||||
#ifdef XSS_MINIMAL_NETWORK_SORT
|
||||
static constexpr int network_sort_threshold = numlanes;
|
||||
#else
|
||||
static constexpr int network_sort_threshold = 256;
|
||||
#endif
|
||||
static constexpr int partition_unroll_factor = 4;
|
||||
|
||||
using swizzle_ops = avx2_32bit_swizzle_ops;
|
||||
|
||||
static type_t type_max() { return X86_SIMD_SORT_MAX_INT32; }
|
||||
static type_t type_min() { return X86_SIMD_SORT_MIN_INT32; }
|
||||
static reg_t zmm_max() {
|
||||
return _mm256_set1_epi32(type_max());
|
||||
} // TODO: this should broadcast bits as is?
|
||||
static opmask_t get_partial_loadmask(uint64_t num_to_read) {
|
||||
auto mask = ((0x1ull << num_to_read) - 0x1ull);
|
||||
return convert_int_to_avx2_mask(mask);
|
||||
}
|
||||
static ymmi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
|
||||
int v8) {
|
||||
return _mm256_set_epi32(v1, v2, v3, v4, v5, v6, v7, v8);
|
||||
}
|
||||
static opmask_t kxor_opmask(opmask_t x, opmask_t y) {
|
||||
return _mm256_xor_si256(x, y);
|
||||
}
|
||||
static opmask_t ge(reg_t x, reg_t y) {
|
||||
opmask_t equal = eq(x, y);
|
||||
opmask_t greater = _mm256_cmpgt_epi32(x, y);
|
||||
return _mm256_castps_si256(_mm256_or_ps(_mm256_castsi256_ps(equal),
|
||||
_mm256_castsi256_ps(greater)));
|
||||
}
|
||||
static opmask_t gt(reg_t x, reg_t y) { return _mm256_cmpgt_epi32(x, y); }
|
||||
static opmask_t eq(reg_t x, reg_t y) { return _mm256_cmpeq_epi32(x, y); }
|
||||
template <int scale>
|
||||
static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
|
||||
void const *base) {
|
||||
return _mm256_mask_i32gather_epi32(src, base, index, mask, scale);
|
||||
}
|
||||
template <int scale>
|
||||
static reg_t i64gather(__m256i index, void const *base) {
|
||||
return _mm256_i32gather_epi32((int const *)base, index, scale);
|
||||
}
|
||||
static reg_t loadu(void const *mem) {
|
||||
return _mm256_loadu_si256((reg_t const *)mem);
|
||||
}
|
||||
static reg_t max(reg_t x, reg_t y) { return _mm256_max_epi32(x, y); }
|
||||
static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
|
||||
return avx2_emu_mask_compressstoreu32<type_t>(mem, mask, x);
|
||||
}
|
||||
static reg_t maskz_loadu(opmask_t mask, void const *mem) {
|
||||
return _mm256_maskload_epi32((const int *)mem, mask);
|
||||
}
|
||||
static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
|
||||
reg_t dst = _mm256_maskload_epi32((type_t *)mem, mask);
|
||||
return mask_mov(x, mask, dst);
|
||||
}
|
||||
static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
|
||||
return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(x),
|
||||
_mm256_castsi256_ps(y),
|
||||
_mm256_castsi256_ps(mask)));
|
||||
}
|
||||
static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm256_maskstore_epi32((type_t *)mem, mask, x);
|
||||
}
|
||||
static reg_t min(reg_t x, reg_t y) { return _mm256_min_epi32(x, y); }
|
||||
static reg_t permutexvar(__m256i idx, reg_t ymm) {
|
||||
return _mm256_permutevar8x32_epi32(ymm, idx);
|
||||
// return avx2_emu_permutexvar_epi32(idx, ymm);
|
||||
}
|
||||
static reg_t permutevar(reg_t ymm, __m256i idx) {
|
||||
return _mm256_permutevar8x32_epi32(ymm, idx);
|
||||
}
|
||||
static reg_t reverse(reg_t ymm) {
|
||||
const __m256i rev_index = _mm256_set_epi32(NETWORK_32BIT_AVX2_2);
|
||||
return permutexvar(rev_index, ymm);
|
||||
}
|
||||
static type_t reducemax(reg_t v) {
|
||||
return avx2_emu_reduce_max32<type_t>(v);
|
||||
}
|
||||
static type_t reducemin(reg_t v) {
|
||||
return avx2_emu_reduce_min32<type_t>(v);
|
||||
}
|
||||
static reg_t set1(type_t v) { return _mm256_set1_epi32(v); }
|
||||
template <uint8_t mask>
|
||||
static reg_t shuffle(reg_t ymm) {
|
||||
return _mm256_shuffle_epi32(ymm, mask);
|
||||
}
|
||||
static void storeu(void *mem, reg_t x) {
|
||||
_mm256_storeu_si256((__m256i *)mem, x);
|
||||
}
|
||||
static reg_t sort_vec(reg_t x) {
|
||||
return sort_ymm_32bit<avx2_vector<type_t>>(x);
|
||||
}
|
||||
static reg_t cast_from(__m256i v) { return v; }
|
||||
static __m256i cast_to(reg_t v) { return v; }
|
||||
static int double_compressstore(type_t *left_addr, type_t *right_addr,
|
||||
opmask_t k, reg_t reg) {
|
||||
return avx2_double_compressstore32<type_t>(left_addr, right_addr, k,
|
||||
reg);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct avx2_vector<float> {
|
||||
using type_t = float;
|
||||
using reg_t = __m256;
|
||||
using ymmi_t = __m256i;
|
||||
using opmask_t = __m256i;
|
||||
static const uint8_t numlanes = 8;
|
||||
#ifdef XSS_MINIMAL_NETWORK_SORT
|
||||
static constexpr int network_sort_threshold = numlanes;
|
||||
#else
|
||||
static constexpr int network_sort_threshold = 256;
|
||||
#endif
|
||||
static constexpr int partition_unroll_factor = 4;
|
||||
|
||||
using swizzle_ops = avx2_32bit_swizzle_ops;
|
||||
|
||||
static type_t type_max() { return X86_SIMD_SORT_INFINITYF; }
|
||||
static type_t type_min() { return -X86_SIMD_SORT_INFINITYF; }
|
||||
static reg_t zmm_max() { return _mm256_set1_ps(type_max()); }
|
||||
|
||||
static ymmi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
|
||||
int v8) {
|
||||
return _mm256_set_epi32(v1, v2, v3, v4, v5, v6, v7, v8);
|
||||
}
|
||||
|
||||
static reg_t maskz_loadu(opmask_t mask, void const *mem) {
|
||||
return _mm256_maskload_ps((const float *)mem, mask);
|
||||
}
|
||||
static opmask_t ge(reg_t x, reg_t y) {
|
||||
return _mm256_castps_si256(_mm256_cmp_ps(x, y, _CMP_GE_OQ));
|
||||
}
|
||||
static opmask_t gt(reg_t x, reg_t y) {
|
||||
return _mm256_castps_si256(_mm256_cmp_ps(x, y, _CMP_GT_OQ));
|
||||
}
|
||||
static opmask_t eq(reg_t x, reg_t y) {
|
||||
return _mm256_castps_si256(_mm256_cmp_ps(x, y, _CMP_EQ_OQ));
|
||||
}
|
||||
static opmask_t get_partial_loadmask(uint64_t num_to_read) {
|
||||
auto mask = ((0x1ull << num_to_read) - 0x1ull);
|
||||
return convert_int_to_avx2_mask(mask);
|
||||
}
|
||||
static int32_t convert_mask_to_int(opmask_t mask) {
|
||||
return convert_avx2_mask_to_int(mask);
|
||||
}
|
||||
template <int type>
|
||||
static opmask_t fpclass(reg_t x) {
|
||||
if constexpr (type == (0x01 | 0x80)) {
|
||||
return _mm256_castps_si256(_mm256_cmp_ps(x, x, _CMP_UNORD_Q));
|
||||
} else {
|
||||
static_assert(type == (0x01 | 0x80), "should not reach here");
|
||||
}
|
||||
}
|
||||
template <int scale>
|
||||
static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
|
||||
void const *base) {
|
||||
return _mm256_mask_i32gather_ps(src, base, index,
|
||||
_mm256_castsi256_ps(mask), scale);
|
||||
;
|
||||
}
|
||||
template <int scale>
|
||||
static reg_t i64gather(__m256i index, void const *base) {
|
||||
return _mm256_i32gather_ps((float *)base, index, scale);
|
||||
}
|
||||
static reg_t loadu(void const *mem) {
|
||||
return _mm256_loadu_ps((float const *)mem);
|
||||
}
|
||||
static reg_t max(reg_t x, reg_t y) { return _mm256_max_ps(x, y); }
|
||||
static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
|
||||
return avx2_emu_mask_compressstoreu32<type_t>(mem, mask, x);
|
||||
}
|
||||
static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
|
||||
reg_t dst = _mm256_maskload_ps((type_t *)mem, mask);
|
||||
return mask_mov(x, mask, dst);
|
||||
}
|
||||
static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
|
||||
return _mm256_blendv_ps(x, y, _mm256_castsi256_ps(mask));
|
||||
}
|
||||
static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm256_maskstore_ps((type_t *)mem, mask, x);
|
||||
}
|
||||
static reg_t min(reg_t x, reg_t y) { return _mm256_min_ps(x, y); }
|
||||
static reg_t permutexvar(__m256i idx, reg_t ymm) {
|
||||
return _mm256_permutevar8x32_ps(ymm, idx);
|
||||
}
|
||||
static reg_t permutevar(reg_t ymm, __m256i idx) {
|
||||
return _mm256_permutevar8x32_ps(ymm, idx);
|
||||
}
|
||||
static reg_t reverse(reg_t ymm) {
|
||||
const __m256i rev_index = _mm256_set_epi32(NETWORK_32BIT_AVX2_2);
|
||||
return permutexvar(rev_index, ymm);
|
||||
}
|
||||
static type_t reducemax(reg_t v) {
|
||||
return avx2_emu_reduce_max32<type_t>(v);
|
||||
}
|
||||
static type_t reducemin(reg_t v) {
|
||||
return avx2_emu_reduce_min32<type_t>(v);
|
||||
}
|
||||
static reg_t set1(type_t v) { return _mm256_set1_ps(v); }
|
||||
template <uint8_t mask>
|
||||
static reg_t shuffle(reg_t ymm) {
|
||||
return _mm256_castsi256_ps(
|
||||
_mm256_shuffle_epi32(_mm256_castps_si256(ymm), mask));
|
||||
}
|
||||
static void storeu(void *mem, reg_t x) {
|
||||
_mm256_storeu_ps((float *)mem, x);
|
||||
}
|
||||
static reg_t sort_vec(reg_t x) {
|
||||
return sort_ymm_32bit<avx2_vector<type_t>>(x);
|
||||
}
|
||||
static reg_t cast_from(__m256i v) { return _mm256_castsi256_ps(v); }
|
||||
static __m256i cast_to(reg_t v) { return _mm256_castps_si256(v); }
|
||||
static int double_compressstore(type_t *left_addr, type_t *right_addr,
|
||||
opmask_t k, reg_t reg) {
|
||||
return avx2_double_compressstore32<type_t>(left_addr, right_addr, k,
|
||||
reg);
|
||||
}
|
||||
};
|
||||
|
||||
struct avx2_32bit_swizzle_ops {
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t swap_n(
|
||||
typename vtype::reg_t reg) {
|
||||
__m256i v = vtype::cast_to(reg);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
__m256 vf = _mm256_castsi256_ps(v);
|
||||
vf = _mm256_permute_ps(vf, 0b10110001);
|
||||
v = _mm256_castps_si256(vf);
|
||||
} else if constexpr (scale == 4) {
|
||||
__m256 vf = _mm256_castsi256_ps(v);
|
||||
vf = _mm256_permute_ps(vf, 0b01001110);
|
||||
v = _mm256_castps_si256(vf);
|
||||
} else if constexpr (scale == 8) {
|
||||
v = _mm256_permute2x128_si256(v, v, 0b00000001);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v);
|
||||
}
|
||||
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t reverse_n(
|
||||
typename vtype::reg_t reg) {
|
||||
__m256i v = vtype::cast_to(reg);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
return swap_n<vtype, 2>(reg);
|
||||
} else if constexpr (scale == 4) {
|
||||
constexpr uint64_t mask = 0b00011011;
|
||||
__m256 vf = _mm256_castsi256_ps(v);
|
||||
vf = _mm256_permute_ps(vf, mask);
|
||||
v = _mm256_castps_si256(vf);
|
||||
} else if constexpr (scale == 8) {
|
||||
return vtype::reverse(reg);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v);
|
||||
}
|
||||
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t merge_n(
|
||||
typename vtype::reg_t reg, typename vtype::reg_t other) {
|
||||
__m256i v1 = vtype::cast_to(reg);
|
||||
__m256i v2 = vtype::cast_to(other);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
v1 = _mm256_blend_epi32(v1, v2, 0b01010101);
|
||||
} else if constexpr (scale == 4) {
|
||||
v1 = _mm256_blend_epi32(v1, v2, 0b00110011);
|
||||
} else if constexpr (scale == 8) {
|
||||
v1 = _mm256_blend_epi32(v1, v2, 0b00001111);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v1);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // AVX2_QSORT_32BIT
|
||||
183
src/java.base/linux/native/libsimdsort/avx2-emu-funcs.hpp
Normal file
183
src/java.base/linux/native/libsimdsort/avx2-emu-funcs.hpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
#ifndef AVX2_EMU_FUNCS
|
||||
#define AVX2_EMU_FUNCS
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include "xss-common-qsort.h"
|
||||
|
||||
constexpr auto avx2_mask_helper_lut32 = [] {
|
||||
std::array<std::array<int32_t, 8>, 256> lut{};
|
||||
for (int64_t i = 0; i <= 0xFF; i++) {
|
||||
std::array<int32_t, 8> entry{};
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (((i >> j) & 1) == 1)
|
||||
entry[j] = 0xFFFFFFFF;
|
||||
else
|
||||
entry[j] = 0;
|
||||
}
|
||||
lut[i] = entry;
|
||||
}
|
||||
return lut;
|
||||
}();
|
||||
|
||||
constexpr auto avx2_compressstore_lut32_gen = [] {
|
||||
std::array<std::array<std::array<int32_t, 8>, 256>, 2> lutPair{};
|
||||
auto &permLut = lutPair[0];
|
||||
auto &leftLut = lutPair[1];
|
||||
for (int64_t i = 0; i <= 0xFF; i++) {
|
||||
std::array<int32_t, 8> indices{};
|
||||
std::array<int32_t, 8> leftEntry = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int right = 7;
|
||||
int left = 0;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
bool ge = (i >> j) & 1;
|
||||
if (ge) {
|
||||
indices[right] = j;
|
||||
right--;
|
||||
} else {
|
||||
indices[left] = j;
|
||||
leftEntry[left] = 0xFFFFFFFF;
|
||||
left++;
|
||||
}
|
||||
}
|
||||
permLut[i] = indices;
|
||||
leftLut[i] = leftEntry;
|
||||
}
|
||||
return lutPair;
|
||||
}();
|
||||
|
||||
constexpr auto avx2_compressstore_lut32_perm = avx2_compressstore_lut32_gen[0];
|
||||
constexpr auto avx2_compressstore_lut32_left = avx2_compressstore_lut32_gen[1];
|
||||
|
||||
|
||||
X86_SIMD_SORT_INLINE
|
||||
__m256i convert_int_to_avx2_mask(int32_t m) {
|
||||
return _mm256_loadu_si256(
|
||||
(const __m256i *)avx2_mask_helper_lut32[m].data());
|
||||
}
|
||||
|
||||
X86_SIMD_SORT_INLINE
|
||||
int32_t convert_avx2_mask_to_int(__m256i m) {
|
||||
return _mm256_movemask_ps(_mm256_castsi256_ps(m));
|
||||
}
|
||||
|
||||
// Emulators for intrinsics missing from AVX2 compared to AVX512
|
||||
template <typename T>
|
||||
T avx2_emu_reduce_max32(typename avx2_vector<T>::reg_t x) {
|
||||
using vtype = avx2_vector<T>;
|
||||
using reg_t = typename vtype::reg_t;
|
||||
|
||||
reg_t inter1 =
|
||||
vtype::max(x, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(x));
|
||||
reg_t inter2 = vtype::max(
|
||||
inter1, vtype::template shuffle<SHUFFLE_MASK(1, 0, 3, 2)>(inter1));
|
||||
T arr[vtype::numlanes];
|
||||
vtype::storeu(arr, inter2);
|
||||
return std::max(arr[0], arr[7]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T avx2_emu_reduce_min32(typename avx2_vector<T>::reg_t x) {
|
||||
using vtype = avx2_vector<T>;
|
||||
using reg_t = typename vtype::reg_t;
|
||||
|
||||
reg_t inter1 =
|
||||
vtype::min(x, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(x));
|
||||
reg_t inter2 = vtype::min(
|
||||
inter1, vtype::template shuffle<SHUFFLE_MASK(1, 0, 3, 2)>(inter1));
|
||||
T arr[vtype::numlanes];
|
||||
vtype::storeu(arr, inter2);
|
||||
return std::min(arr[0], arr[7]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void avx2_emu_mask_compressstoreu32(void *base_addr,
|
||||
typename avx2_vector<T>::opmask_t k,
|
||||
typename avx2_vector<T>::reg_t reg) {
|
||||
using vtype = avx2_vector<T>;
|
||||
|
||||
T *leftStore = (T *)base_addr;
|
||||
|
||||
int32_t shortMask = convert_avx2_mask_to_int(k);
|
||||
const __m256i perm = _mm256_loadu_si256(
|
||||
(const __m256i *)avx2_compressstore_lut32_perm[shortMask].data());
|
||||
const __m256i left = _mm256_loadu_si256(
|
||||
(const __m256i *)avx2_compressstore_lut32_left[shortMask].data());
|
||||
|
||||
typename vtype::reg_t temp = vtype::permutevar(reg, perm);
|
||||
|
||||
vtype::mask_storeu(leftStore, left, temp);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
int avx2_double_compressstore32(void *left_addr, void *right_addr,
|
||||
typename avx2_vector<T>::opmask_t k,
|
||||
typename avx2_vector<T>::reg_t reg) {
|
||||
using vtype = avx2_vector<T>;
|
||||
|
||||
T *leftStore = (T *)left_addr;
|
||||
T *rightStore = (T *)right_addr;
|
||||
|
||||
int32_t shortMask = convert_avx2_mask_to_int(k);
|
||||
const __m256i perm = _mm256_loadu_si256(
|
||||
(const __m256i *)avx2_compressstore_lut32_perm[shortMask].data());
|
||||
|
||||
typename vtype::reg_t temp = vtype::permutevar(reg, perm);
|
||||
|
||||
vtype::storeu(leftStore, temp);
|
||||
vtype::storeu(rightStore, temp);
|
||||
|
||||
return _mm_popcnt_u32(shortMask);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
typename avx2_vector<T>::reg_t avx2_emu_max(typename avx2_vector<T>::reg_t x,
|
||||
typename avx2_vector<T>::reg_t y) {
|
||||
using vtype = avx2_vector<T>;
|
||||
typename vtype::opmask_t nlt = vtype::gt(x, y);
|
||||
return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(y),
|
||||
_mm256_castsi256_pd(x),
|
||||
_mm256_castsi256_pd(nlt)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename avx2_vector<T>::reg_t avx2_emu_min(typename avx2_vector<T>::reg_t x,
|
||||
typename avx2_vector<T>::reg_t y) {
|
||||
using vtype = avx2_vector<T>;
|
||||
typename vtype::opmask_t nlt = vtype::gt(x, y);
|
||||
return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(x),
|
||||
_mm256_castsi256_pd(y),
|
||||
_mm256_castsi256_pd(nlt)));
|
||||
}
|
||||
|
||||
#endif
|
||||
66
src/java.base/linux/native/libsimdsort/avx2-linux-qsort.cpp
Normal file
66
src/java.base/linux/native/libsimdsort/avx2-linux-qsort.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "simdsort-support.hpp"
|
||||
#ifdef __SIMDSORT_SUPPORTED_LINUX
|
||||
|
||||
#pragma GCC target("avx2")
|
||||
#include "avx2-32bit-qsort.hpp"
|
||||
#include "classfile_constants.h"
|
||||
|
||||
|
||||
#define DLL_PUBLIC __attribute__((visibility("default")))
|
||||
#define INSERTION_SORT_THRESHOLD_32BIT 16
|
||||
|
||||
extern "C" {
|
||||
|
||||
DLL_PUBLIC void avx2_sort(void *array, int elem_type, int32_t from_index, int32_t to_index) {
|
||||
switch(elem_type) {
|
||||
case JVM_T_INT:
|
||||
avx2_fast_sort((int32_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
|
||||
break;
|
||||
case JVM_T_FLOAT:
|
||||
avx2_fast_sort((float*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
|
||||
break;
|
||||
default:
|
||||
assert(false, "Unexpected type");
|
||||
}
|
||||
}
|
||||
|
||||
DLL_PUBLIC void avx2_partition(void *array, int elem_type, int32_t from_index, int32_t to_index, int32_t *pivot_indices, int32_t index_pivot1, int32_t index_pivot2) {
|
||||
switch(elem_type) {
|
||||
case JVM_T_INT:
|
||||
avx2_fast_partition((int32_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
|
||||
break;
|
||||
case JVM_T_FLOAT:
|
||||
avx2_fast_partition((float*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
|
||||
break;
|
||||
default:
|
||||
assert(false, "Unexpected type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
337
src/java.base/linux/native/libsimdsort/avx512-32bit-qsort.hpp
Normal file
337
src/java.base/linux/native/libsimdsort/avx512-32bit-qsort.hpp
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
#ifndef AVX512_QSORT_32BIT
|
||||
#define AVX512_QSORT_32BIT
|
||||
|
||||
#include "xss-common-qsort.h"
|
||||
|
||||
/*
|
||||
* Constants used in sorting 16 elements in a ZMM registers. Based on Bitonic
|
||||
* sorting network (see
|
||||
* https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg)
|
||||
*/
|
||||
#define NETWORK_32BIT_1 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1
|
||||
#define NETWORK_32BIT_2 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3
|
||||
#define NETWORK_32BIT_3 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7
|
||||
#define NETWORK_32BIT_4 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2
|
||||
#define NETWORK_32BIT_5 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
#define NETWORK_32BIT_6 11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4
|
||||
#define NETWORK_32BIT_7 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8
|
||||
|
||||
template <typename vtype, typename reg_t>
|
||||
X86_SIMD_SORT_INLINE reg_t sort_zmm_32bit(reg_t zmm);
|
||||
|
||||
struct avx512_32bit_swizzle_ops;
|
||||
|
||||
template <>
|
||||
struct zmm_vector<int32_t> {
|
||||
using type_t = int32_t;
|
||||
using reg_t = __m512i;
|
||||
using halfreg_t = __m256i;
|
||||
using opmask_t = __mmask16;
|
||||
static const uint8_t numlanes = 16;
|
||||
#ifdef XSS_MINIMAL_NETWORK_SORT
|
||||
static constexpr int network_sort_threshold = numlanes;
|
||||
#else
|
||||
static constexpr int network_sort_threshold = 512;
|
||||
#endif
|
||||
static constexpr int partition_unroll_factor = 8;
|
||||
|
||||
using swizzle_ops = avx512_32bit_swizzle_ops;
|
||||
|
||||
static type_t type_max() { return X86_SIMD_SORT_MAX_INT32; }
|
||||
static type_t type_min() { return X86_SIMD_SORT_MIN_INT32; }
|
||||
static reg_t zmm_max() { return _mm512_set1_epi32(type_max()); }
|
||||
|
||||
static opmask_t knot_opmask(opmask_t x) { return _mm512_knot(x); }
|
||||
|
||||
static opmask_t ge(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_epi32_mask(x, y, _MM_CMPINT_NLT);
|
||||
}
|
||||
|
||||
static opmask_t gt(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_epi32_mask(x, y, _MM_CMPINT_GT);
|
||||
}
|
||||
|
||||
static opmask_t get_partial_loadmask(uint64_t num_to_read) {
|
||||
return ((0x1ull << num_to_read) - 0x1ull);
|
||||
}
|
||||
template <int scale>
|
||||
static halfreg_t i64gather(__m512i index, void const *base) {
|
||||
return _mm512_i64gather_epi32(index, base, scale);
|
||||
}
|
||||
static reg_t merge(halfreg_t y1, halfreg_t y2) {
|
||||
reg_t z1 = _mm512_castsi256_si512(y1);
|
||||
return _mm512_inserti32x8(z1, y2, 1);
|
||||
}
|
||||
static reg_t loadu(void const *mem) { return _mm512_loadu_si512(mem); }
|
||||
static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_compressstoreu_epi32(mem, mask, x);
|
||||
}
|
||||
static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
|
||||
return _mm512_mask_loadu_epi32(x, mask, mem);
|
||||
}
|
||||
static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
|
||||
return _mm512_mask_mov_epi32(x, mask, y);
|
||||
}
|
||||
static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_storeu_epi32(mem, mask, x);
|
||||
}
|
||||
static reg_t min(reg_t x, reg_t y) { return _mm512_min_epi32(x, y); }
|
||||
static reg_t max(reg_t x, reg_t y) { return _mm512_max_epi32(x, y); }
|
||||
static reg_t permutexvar(__m512i idx, reg_t zmm) {
|
||||
return _mm512_permutexvar_epi32(idx, zmm);
|
||||
}
|
||||
static type_t reducemax(reg_t v) { return _mm512_reduce_max_epi32(v); }
|
||||
static type_t reducemin(reg_t v) { return _mm512_reduce_min_epi32(v); }
|
||||
static reg_t set1(type_t v) { return _mm512_set1_epi32(v); }
|
||||
template <uint8_t mask>
|
||||
static reg_t shuffle(reg_t zmm) {
|
||||
return _mm512_shuffle_epi32(zmm, (_MM_PERM_ENUM)mask);
|
||||
}
|
||||
static void storeu(void *mem, reg_t x) {
|
||||
return _mm512_storeu_si512(mem, x);
|
||||
}
|
||||
|
||||
static halfreg_t max(halfreg_t x, halfreg_t y) {
|
||||
return _mm256_max_epi32(x, y);
|
||||
}
|
||||
static halfreg_t min(halfreg_t x, halfreg_t y) {
|
||||
return _mm256_min_epi32(x, y);
|
||||
}
|
||||
static reg_t reverse(reg_t zmm) {
|
||||
const auto rev_index = _mm512_set_epi32(NETWORK_32BIT_5);
|
||||
return permutexvar(rev_index, zmm);
|
||||
}
|
||||
static reg_t sort_vec(reg_t x) {
|
||||
return sort_zmm_32bit<zmm_vector<type_t>>(x);
|
||||
}
|
||||
static reg_t cast_from(__m512i v) { return v; }
|
||||
static __m512i cast_to(reg_t v) { return v; }
|
||||
static int double_compressstore(type_t *left_addr, type_t *right_addr,
|
||||
opmask_t k, reg_t reg) {
|
||||
return avx512_double_compressstore<zmm_vector<type_t>>(
|
||||
left_addr, right_addr, k, reg);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct zmm_vector<float> {
|
||||
using type_t = float;
|
||||
using reg_t = __m512;
|
||||
using halfreg_t = __m256;
|
||||
using opmask_t = __mmask16;
|
||||
static const uint8_t numlanes = 16;
|
||||
#ifdef XSS_MINIMAL_NETWORK_SORT
|
||||
static constexpr int network_sort_threshold = numlanes;
|
||||
#else
|
||||
static constexpr int network_sort_threshold = 512;
|
||||
#endif
|
||||
static constexpr int partition_unroll_factor = 8;
|
||||
|
||||
using swizzle_ops = avx512_32bit_swizzle_ops;
|
||||
|
||||
static type_t type_max() { return X86_SIMD_SORT_INFINITYF; }
|
||||
static type_t type_min() { return -X86_SIMD_SORT_INFINITYF; }
|
||||
static reg_t zmm_max() { return _mm512_set1_ps(type_max()); }
|
||||
|
||||
static opmask_t knot_opmask(opmask_t x) { return _mm512_knot(x); }
|
||||
static opmask_t ge(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_ps_mask(x, y, _CMP_GE_OQ);
|
||||
}
|
||||
static opmask_t gt(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_ps_mask(x, y, _CMP_GT_OQ);
|
||||
}
|
||||
static opmask_t get_partial_loadmask(uint64_t num_to_read) {
|
||||
return ((0x1ull << num_to_read) - 0x1ull);
|
||||
}
|
||||
static int32_t convert_mask_to_int(opmask_t mask) { return mask; }
|
||||
template <int type>
|
||||
static opmask_t fpclass(reg_t x) {
|
||||
return _mm512_fpclass_ps_mask(x, type);
|
||||
}
|
||||
template <int scale>
|
||||
static halfreg_t i64gather(__m512i index, void const *base) {
|
||||
return _mm512_i64gather_ps(index, base, scale);
|
||||
}
|
||||
static reg_t merge(halfreg_t y1, halfreg_t y2) {
|
||||
reg_t z1 = _mm512_castsi512_ps(
|
||||
_mm512_castsi256_si512(_mm256_castps_si256(y1)));
|
||||
return _mm512_insertf32x8(z1, y2, 1);
|
||||
}
|
||||
static reg_t loadu(void const *mem) { return _mm512_loadu_ps(mem); }
|
||||
static reg_t max(reg_t x, reg_t y) { return _mm512_max_ps(x, y); }
|
||||
static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_compressstoreu_ps(mem, mask, x);
|
||||
}
|
||||
static reg_t maskz_loadu(opmask_t mask, void const *mem) {
|
||||
return _mm512_maskz_loadu_ps(mask, mem);
|
||||
}
|
||||
static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
|
||||
return _mm512_mask_loadu_ps(x, mask, mem);
|
||||
}
|
||||
static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
|
||||
return _mm512_mask_mov_ps(x, mask, y);
|
||||
}
|
||||
static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_storeu_ps(mem, mask, x);
|
||||
}
|
||||
static reg_t min(reg_t x, reg_t y) { return _mm512_min_ps(x, y); }
|
||||
static reg_t permutexvar(__m512i idx, reg_t zmm) {
|
||||
return _mm512_permutexvar_ps(idx, zmm);
|
||||
}
|
||||
static type_t reducemax(reg_t v) { return _mm512_reduce_max_ps(v); }
|
||||
static type_t reducemin(reg_t v) { return _mm512_reduce_min_ps(v); }
|
||||
static reg_t set1(type_t v) { return _mm512_set1_ps(v); }
|
||||
template <uint8_t mask>
|
||||
static reg_t shuffle(reg_t zmm) {
|
||||
return _mm512_shuffle_ps(zmm, zmm, (_MM_PERM_ENUM)mask);
|
||||
}
|
||||
static void storeu(void *mem, reg_t x) { return _mm512_storeu_ps(mem, x); }
|
||||
|
||||
static halfreg_t max(halfreg_t x, halfreg_t y) {
|
||||
return _mm256_max_ps(x, y);
|
||||
}
|
||||
static halfreg_t min(halfreg_t x, halfreg_t y) {
|
||||
return _mm256_min_ps(x, y);
|
||||
}
|
||||
static reg_t reverse(reg_t zmm) {
|
||||
const auto rev_index = _mm512_set_epi32(NETWORK_32BIT_5);
|
||||
return permutexvar(rev_index, zmm);
|
||||
}
|
||||
static reg_t sort_vec(reg_t x) {
|
||||
return sort_zmm_32bit<zmm_vector<type_t>>(x);
|
||||
}
|
||||
static reg_t cast_from(__m512i v) { return _mm512_castsi512_ps(v); }
|
||||
static __m512i cast_to(reg_t v) { return _mm512_castps_si512(v); }
|
||||
static int double_compressstore(type_t *left_addr, type_t *right_addr,
|
||||
opmask_t k, reg_t reg) {
|
||||
return avx512_double_compressstore<zmm_vector<type_t>>(
|
||||
left_addr, right_addr, k, reg);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Assumes zmm is random and performs a full sorting network defined in
|
||||
* https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg
|
||||
*/
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_INLINE reg_t sort_zmm_32bit(reg_t zmm) {
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(zmm), 0xAAAA);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(0, 1, 2, 3)>(zmm), 0xCCCC);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(zmm), 0xAAAA);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_3), zmm),
|
||||
0xF0F0);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(1, 0, 3, 2)>(zmm), 0xCCCC);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(zmm), 0xAAAA);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_5), zmm),
|
||||
0xFF00);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::permutexvar(_mm512_set_epi32(NETWORK_32BIT_6), zmm),
|
||||
0xF0F0);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(1, 0, 3, 2)>(zmm), 0xCCCC);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(2, 3, 0, 1)>(zmm), 0xAAAA);
|
||||
return zmm;
|
||||
}
|
||||
|
||||
struct avx512_32bit_swizzle_ops {
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t swap_n(
|
||||
typename vtype::reg_t reg) {
|
||||
__m512i v = vtype::cast_to(reg);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
v = _mm512_shuffle_epi32(v, (_MM_PERM_ENUM)0b10110001);
|
||||
} else if constexpr (scale == 4) {
|
||||
v = _mm512_shuffle_epi32(v, (_MM_PERM_ENUM)0b01001110);
|
||||
} else if constexpr (scale == 8) {
|
||||
v = _mm512_shuffle_i64x2(v, v, 0b10110001);
|
||||
} else if constexpr (scale == 16) {
|
||||
v = _mm512_shuffle_i64x2(v, v, 0b01001110);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v);
|
||||
}
|
||||
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t reverse_n(
|
||||
typename vtype::reg_t reg) {
|
||||
__m512i v = vtype::cast_to(reg);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
return swap_n<vtype, 2>(reg);
|
||||
} else if constexpr (scale == 4) {
|
||||
__m512i mask = _mm512_set_epi32(12, 13, 14, 15, 8, 9, 10, 11, 4, 5,
|
||||
6, 7, 0, 1, 2, 3);
|
||||
v = _mm512_permutexvar_epi32(mask, v);
|
||||
} else if constexpr (scale == 8) {
|
||||
__m512i mask = _mm512_set_epi32(8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
|
||||
2, 3, 4, 5, 6, 7);
|
||||
v = _mm512_permutexvar_epi32(mask, v);
|
||||
} else if constexpr (scale == 16) {
|
||||
return vtype::reverse(reg);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v);
|
||||
}
|
||||
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t merge_n(
|
||||
typename vtype::reg_t reg, typename vtype::reg_t other) {
|
||||
__m512i v1 = vtype::cast_to(reg);
|
||||
__m512i v2 = vtype::cast_to(other);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
v1 = _mm512_mask_blend_epi32(0b0101010101010101, v1, v2);
|
||||
} else if constexpr (scale == 4) {
|
||||
v1 = _mm512_mask_blend_epi32(0b0011001100110011, v1, v2);
|
||||
} else if constexpr (scale == 8) {
|
||||
v1 = _mm512_mask_blend_epi32(0b0000111100001111, v1, v2);
|
||||
} else if constexpr (scale == 16) {
|
||||
v1 = _mm512_mask_blend_epi32(0b0000000011111111, v1, v2);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v1);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // AVX512_QSORT_32BIT
|
||||
343
src/java.base/linux/native/libsimdsort/avx512-64bit-qsort.hpp
Normal file
343
src/java.base/linux/native/libsimdsort/avx512-64bit-qsort.hpp
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
#ifndef AVX512_QSORT_64BIT
|
||||
#define AVX512_QSORT_64BIT
|
||||
|
||||
#include "xss-common-includes.h"
|
||||
#include "xss-common-qsort.h"
|
||||
|
||||
/*
|
||||
* Constants used in sorting 8 elements in a ZMM registers. Based on Bitonic
|
||||
* sorting network (see
|
||||
* https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg)
|
||||
*/
|
||||
// ZMM 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define NETWORK_64BIT_1 4, 5, 6, 7, 0, 1, 2, 3
|
||||
#define NETWORK_64BIT_2 0, 1, 2, 3, 4, 5, 6, 7
|
||||
#define NETWORK_64BIT_3 5, 4, 7, 6, 1, 0, 3, 2
|
||||
#define NETWORK_64BIT_4 3, 2, 1, 0, 7, 6, 5, 4
|
||||
|
||||
template <typename vtype, typename reg_t>
|
||||
X86_SIMD_SORT_INLINE reg_t sort_zmm_64bit(reg_t zmm);
|
||||
|
||||
struct avx512_64bit_swizzle_ops;
|
||||
|
||||
template <>
|
||||
struct zmm_vector<int64_t> {
|
||||
using type_t = int64_t;
|
||||
using reg_t = __m512i;
|
||||
using regi_t = __m512i;
|
||||
using halfreg_t = __m512i;
|
||||
using opmask_t = __mmask8;
|
||||
static const uint8_t numlanes = 8;
|
||||
#ifdef XSS_MINIMAL_NETWORK_SORT
|
||||
static constexpr int network_sort_threshold = numlanes;
|
||||
#else
|
||||
static constexpr int network_sort_threshold = 256;
|
||||
#endif
|
||||
static constexpr int partition_unroll_factor = 8;
|
||||
|
||||
using swizzle_ops = avx512_64bit_swizzle_ops;
|
||||
|
||||
static type_t type_max() { return X86_SIMD_SORT_MAX_INT64; }
|
||||
static type_t type_min() { return X86_SIMD_SORT_MIN_INT64; }
|
||||
static reg_t zmm_max() {
|
||||
return _mm512_set1_epi64(type_max());
|
||||
} // TODO: this should broadcast bits as is?
|
||||
|
||||
static regi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
|
||||
int v8) {
|
||||
return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
|
||||
}
|
||||
static reg_t set(type_t v1, type_t v2, type_t v3, type_t v4, type_t v5,
|
||||
type_t v6, type_t v7, type_t v8) {
|
||||
return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
|
||||
}
|
||||
static opmask_t kxor_opmask(opmask_t x, opmask_t y) {
|
||||
return _kxor_mask8(x, y);
|
||||
}
|
||||
static opmask_t knot_opmask(opmask_t x) { return _knot_mask8(x); }
|
||||
static opmask_t le(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_LE);
|
||||
}
|
||||
static opmask_t ge(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_NLT);
|
||||
}
|
||||
static opmask_t gt(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_GT);
|
||||
}
|
||||
static opmask_t get_partial_loadmask(uint64_t num_to_read) {
|
||||
return ((0x1ull << num_to_read) - 0x1ull);
|
||||
}
|
||||
static opmask_t eq(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_epi64_mask(x, y, _MM_CMPINT_EQ);
|
||||
}
|
||||
template <int scale>
|
||||
static reg_t mask_i64gather(reg_t src, opmask_t mask, __m512i index,
|
||||
void const *base) {
|
||||
return _mm512_mask_i64gather_epi64(src, mask, index, base, scale);
|
||||
}
|
||||
template <int scale>
|
||||
static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
|
||||
void const *base) {
|
||||
return _mm512_mask_i32gather_epi64(src, mask, index, base, scale);
|
||||
}
|
||||
static reg_t i64gather(type_t *arr, arrsize_t *ind) {
|
||||
return set(arr[ind[7]], arr[ind[6]], arr[ind[5]], arr[ind[4]],
|
||||
arr[ind[3]], arr[ind[2]], arr[ind[1]], arr[ind[0]]);
|
||||
}
|
||||
static reg_t loadu(void const *mem) { return _mm512_loadu_si512(mem); }
|
||||
static reg_t max(reg_t x, reg_t y) { return _mm512_max_epi64(x, y); }
|
||||
static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_compressstoreu_epi64(mem, mask, x);
|
||||
}
|
||||
static reg_t maskz_loadu(opmask_t mask, void const *mem) {
|
||||
return _mm512_maskz_loadu_epi64(mask, mem);
|
||||
}
|
||||
static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
|
||||
return _mm512_mask_loadu_epi64(x, mask, mem);
|
||||
}
|
||||
static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
|
||||
return _mm512_mask_mov_epi64(x, mask, y);
|
||||
}
|
||||
static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_storeu_epi64(mem, mask, x);
|
||||
}
|
||||
static reg_t min(reg_t x, reg_t y) { return _mm512_min_epi64(x, y); }
|
||||
static reg_t permutexvar(__m512i idx, reg_t zmm) {
|
||||
return _mm512_permutexvar_epi64(idx, zmm);
|
||||
}
|
||||
static type_t reducemax(reg_t v) { return _mm512_reduce_max_epi64(v); }
|
||||
static type_t reducemin(reg_t v) { return _mm512_reduce_min_epi64(v); }
|
||||
static reg_t set1(type_t v) { return _mm512_set1_epi64(v); }
|
||||
template <uint8_t mask>
|
||||
static reg_t shuffle(reg_t zmm) {
|
||||
__m512d temp = _mm512_castsi512_pd(zmm);
|
||||
return _mm512_castpd_si512(
|
||||
_mm512_shuffle_pd(temp, temp, (_MM_PERM_ENUM)mask));
|
||||
}
|
||||
static void storeu(void *mem, reg_t x) { _mm512_storeu_si512(mem, x); }
|
||||
static reg_t reverse(reg_t zmm) {
|
||||
const regi_t rev_index = seti(NETWORK_64BIT_2);
|
||||
return permutexvar(rev_index, zmm);
|
||||
}
|
||||
static reg_t sort_vec(reg_t x) {
|
||||
return sort_zmm_64bit<zmm_vector<type_t>>(x);
|
||||
}
|
||||
static reg_t cast_from(__m512i v) { return v; }
|
||||
static __m512i cast_to(reg_t v) { return v; }
|
||||
static int double_compressstore(type_t *left_addr, type_t *right_addr,
|
||||
opmask_t k, reg_t reg) {
|
||||
return avx512_double_compressstore<zmm_vector<type_t>>(
|
||||
left_addr, right_addr, k, reg);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct zmm_vector<double> {
|
||||
using type_t = double;
|
||||
using reg_t = __m512d;
|
||||
using regi_t = __m512i;
|
||||
using halfreg_t = __m512d;
|
||||
using opmask_t = __mmask8;
|
||||
static const uint8_t numlanes = 8;
|
||||
#ifdef XSS_MINIMAL_NETWORK_SORT
|
||||
static constexpr int network_sort_threshold = numlanes;
|
||||
#else
|
||||
static constexpr int network_sort_threshold = 256;
|
||||
#endif
|
||||
static constexpr int partition_unroll_factor = 8;
|
||||
|
||||
using swizzle_ops = avx512_64bit_swizzle_ops;
|
||||
|
||||
static type_t type_max() { return X86_SIMD_SORT_INFINITY; }
|
||||
static type_t type_min() { return -X86_SIMD_SORT_INFINITY; }
|
||||
static reg_t zmm_max() { return _mm512_set1_pd(type_max()); }
|
||||
static regi_t seti(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
|
||||
int v8) {
|
||||
return _mm512_set_epi64(v1, v2, v3, v4, v5, v6, v7, v8);
|
||||
}
|
||||
static reg_t set(type_t v1, type_t v2, type_t v3, type_t v4, type_t v5,
|
||||
type_t v6, type_t v7, type_t v8) {
|
||||
return _mm512_set_pd(v1, v2, v3, v4, v5, v6, v7, v8);
|
||||
}
|
||||
static reg_t maskz_loadu(opmask_t mask, void const *mem) {
|
||||
return _mm512_maskz_loadu_pd(mask, mem);
|
||||
}
|
||||
static opmask_t knot_opmask(opmask_t x) { return _knot_mask8(x); }
|
||||
static opmask_t ge(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_pd_mask(x, y, _CMP_GE_OQ);
|
||||
}
|
||||
static opmask_t gt(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_pd_mask(x, y, _CMP_GT_OQ);
|
||||
}
|
||||
static opmask_t eq(reg_t x, reg_t y) {
|
||||
return _mm512_cmp_pd_mask(x, y, _CMP_EQ_OQ);
|
||||
}
|
||||
static opmask_t get_partial_loadmask(uint64_t num_to_read) {
|
||||
return ((0x1ull << num_to_read) - 0x1ull);
|
||||
}
|
||||
static int32_t convert_mask_to_int(opmask_t mask) { return mask; }
|
||||
template <int type>
|
||||
static opmask_t fpclass(reg_t x) {
|
||||
return _mm512_fpclass_pd_mask(x, type);
|
||||
}
|
||||
template <int scale>
|
||||
static reg_t mask_i64gather(reg_t src, opmask_t mask, __m512i index,
|
||||
void const *base) {
|
||||
return _mm512_mask_i64gather_pd(src, mask, index, base, scale);
|
||||
}
|
||||
template <int scale>
|
||||
static reg_t mask_i64gather(reg_t src, opmask_t mask, __m256i index,
|
||||
void const *base) {
|
||||
return _mm512_mask_i32gather_pd(src, mask, index, base, scale);
|
||||
}
|
||||
static reg_t i64gather(type_t *arr, arrsize_t *ind) {
|
||||
return set(arr[ind[7]], arr[ind[6]], arr[ind[5]], arr[ind[4]],
|
||||
arr[ind[3]], arr[ind[2]], arr[ind[1]], arr[ind[0]]);
|
||||
}
|
||||
static reg_t loadu(void const *mem) { return _mm512_loadu_pd(mem); }
|
||||
static reg_t max(reg_t x, reg_t y) { return _mm512_max_pd(x, y); }
|
||||
static void mask_compressstoreu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_compressstoreu_pd(mem, mask, x);
|
||||
}
|
||||
static reg_t mask_loadu(reg_t x, opmask_t mask, void const *mem) {
|
||||
return _mm512_mask_loadu_pd(x, mask, mem);
|
||||
}
|
||||
static reg_t mask_mov(reg_t x, opmask_t mask, reg_t y) {
|
||||
return _mm512_mask_mov_pd(x, mask, y);
|
||||
}
|
||||
static void mask_storeu(void *mem, opmask_t mask, reg_t x) {
|
||||
return _mm512_mask_storeu_pd(mem, mask, x);
|
||||
}
|
||||
static reg_t min(reg_t x, reg_t y) { return _mm512_min_pd(x, y); }
|
||||
static reg_t permutexvar(__m512i idx, reg_t zmm) {
|
||||
return _mm512_permutexvar_pd(idx, zmm);
|
||||
}
|
||||
static type_t reducemax(reg_t v) { return _mm512_reduce_max_pd(v); }
|
||||
static type_t reducemin(reg_t v) { return _mm512_reduce_min_pd(v); }
|
||||
static reg_t set1(type_t v) { return _mm512_set1_pd(v); }
|
||||
template <uint8_t mask>
|
||||
static reg_t shuffle(reg_t zmm) {
|
||||
return _mm512_shuffle_pd(zmm, zmm, (_MM_PERM_ENUM)mask);
|
||||
}
|
||||
static void storeu(void *mem, reg_t x) { _mm512_storeu_pd(mem, x); }
|
||||
static reg_t reverse(reg_t zmm) {
|
||||
const regi_t rev_index = seti(NETWORK_64BIT_2);
|
||||
return permutexvar(rev_index, zmm);
|
||||
}
|
||||
static reg_t sort_vec(reg_t x) {
|
||||
return sort_zmm_64bit<zmm_vector<type_t>>(x);
|
||||
}
|
||||
static reg_t cast_from(__m512i v) { return _mm512_castsi512_pd(v); }
|
||||
static __m512i cast_to(reg_t v) { return _mm512_castpd_si512(v); }
|
||||
static int double_compressstore(type_t *left_addr, type_t *right_addr,
|
||||
opmask_t k, reg_t reg) {
|
||||
return avx512_double_compressstore<zmm_vector<type_t>>(
|
||||
left_addr, right_addr, k, reg);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Assumes zmm is random and performs a full sorting network defined in
|
||||
* https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg
|
||||
*/
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_INLINE reg_t sort_zmm_64bit(reg_t zmm) {
|
||||
const typename vtype::regi_t rev_index = vtype::seti(NETWORK_64BIT_2);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(1, 1, 1, 1)>(zmm), 0xAA);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::permutexvar(vtype::seti(NETWORK_64BIT_1), zmm), 0xCC);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(1, 1, 1, 1)>(zmm), 0xAA);
|
||||
zmm = cmp_merge<vtype>(zmm, vtype::permutexvar(rev_index, zmm), 0xF0);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::permutexvar(vtype::seti(NETWORK_64BIT_3), zmm), 0xCC);
|
||||
zmm = cmp_merge<vtype>(
|
||||
zmm, vtype::template shuffle<SHUFFLE_MASK(1, 1, 1, 1)>(zmm), 0xAA);
|
||||
return zmm;
|
||||
}
|
||||
|
||||
struct avx512_64bit_swizzle_ops {
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t swap_n(
|
||||
typename vtype::reg_t reg) {
|
||||
__m512i v = vtype::cast_to(reg);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
v = _mm512_shuffle_epi32(v, (_MM_PERM_ENUM)0b01001110);
|
||||
} else if constexpr (scale == 4) {
|
||||
v = _mm512_shuffle_i64x2(v, v, 0b10110001);
|
||||
} else if constexpr (scale == 8) {
|
||||
v = _mm512_shuffle_i64x2(v, v, 0b01001110);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v);
|
||||
}
|
||||
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t reverse_n(
|
||||
typename vtype::reg_t reg) {
|
||||
__m512i v = vtype::cast_to(reg);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
return swap_n<vtype, 2>(reg);
|
||||
} else if constexpr (scale == 4) {
|
||||
constexpr uint64_t mask = 0b00011011;
|
||||
v = _mm512_permutex_epi64(v, mask);
|
||||
} else if constexpr (scale == 8) {
|
||||
return vtype::reverse(reg);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v);
|
||||
}
|
||||
|
||||
template <typename vtype, int scale>
|
||||
X86_SIMD_SORT_INLINE typename vtype::reg_t merge_n(
|
||||
typename vtype::reg_t reg, typename vtype::reg_t other) {
|
||||
__m512i v1 = vtype::cast_to(reg);
|
||||
__m512i v2 = vtype::cast_to(other);
|
||||
|
||||
if constexpr (scale == 2) {
|
||||
v1 = _mm512_mask_blend_epi64(0b01010101, v1, v2);
|
||||
} else if constexpr (scale == 4) {
|
||||
v1 = _mm512_mask_blend_epi64(0b00110011, v1, v2);
|
||||
} else if constexpr (scale == 8) {
|
||||
v1 = _mm512_mask_blend_epi64(0b00001111, v1, v2);
|
||||
} else {
|
||||
static_assert(scale == -1, "should not be reached");
|
||||
}
|
||||
|
||||
return vtype::cast_from(v1);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "simdsort-support.hpp"
|
||||
#ifdef __SIMDSORT_SUPPORTED_LINUX
|
||||
|
||||
#pragma GCC target("avx512dq", "avx512f")
|
||||
#include "avx512-32bit-qsort.hpp"
|
||||
#include "avx512-64bit-qsort.hpp"
|
||||
#include "classfile_constants.h"
|
||||
|
||||
|
||||
#define DLL_PUBLIC __attribute__((visibility("default")))
|
||||
#define INSERTION_SORT_THRESHOLD_32BIT 16
|
||||
#define INSERTION_SORT_THRESHOLD_64BIT 20
|
||||
|
||||
extern "C" {
|
||||
|
||||
DLL_PUBLIC void avx512_sort(void *array, int elem_type, int32_t from_index, int32_t to_index) {
|
||||
switch(elem_type) {
|
||||
case JVM_T_INT:
|
||||
avx512_fast_sort((int32_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
|
||||
break;
|
||||
case JVM_T_LONG:
|
||||
avx512_fast_sort((int64_t*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_64BIT);
|
||||
break;
|
||||
case JVM_T_FLOAT:
|
||||
avx512_fast_sort((float*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_32BIT);
|
||||
break;
|
||||
case JVM_T_DOUBLE:
|
||||
avx512_fast_sort((double*)array, from_index, to_index, INSERTION_SORT_THRESHOLD_64BIT);
|
||||
break;
|
||||
default:
|
||||
assert(false, "Unexpected type");
|
||||
}
|
||||
}
|
||||
|
||||
DLL_PUBLIC void avx512_partition(void *array, int elem_type, int32_t from_index, int32_t to_index, int32_t *pivot_indices, int32_t index_pivot1, int32_t index_pivot2) {
|
||||
switch(elem_type) {
|
||||
case JVM_T_INT:
|
||||
avx512_fast_partition((int32_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
|
||||
break;
|
||||
case JVM_T_LONG:
|
||||
avx512_fast_partition((int64_t*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
|
||||
break;
|
||||
case JVM_T_FLOAT:
|
||||
avx512_fast_partition((float*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
|
||||
break;
|
||||
case JVM_T_DOUBLE:
|
||||
avx512_fast_partition((double*)array, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
|
||||
break;
|
||||
default:
|
||||
assert(false, "Unexpected type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
39
src/java.base/linux/native/libsimdsort/simdsort-support.hpp
Normal file
39
src/java.base/linux/native/libsimdsort/simdsort-support.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SIMDSORT_SUPPORT_HPP
|
||||
#define SIMDSORT_SUPPORT_HPP
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#undef assert
|
||||
#define assert(cond, msg) { if (!(cond)) { fprintf(stderr, "assert fails %s %d: %s\n", __FILE__, __LINE__, msg); abort(); }}
|
||||
|
||||
|
||||
// GCC >= 9.1 is needed to build AVX2 portions of libsimdsort using C++17 features
|
||||
#if defined(_LP64) && (defined(__GNUC__) && ((__GNUC__ > 9) || ((__GNUC__ == 9) && (__GNUC_MINOR__ >= 1))))
|
||||
#define __SIMDSORT_SUPPORTED_LINUX
|
||||
#endif
|
||||
|
||||
#endif //SIMDSORT_SUPPORT_HPP
|
||||
101
src/java.base/linux/native/libsimdsort/xss-common-includes.h
Normal file
101
src/java.base/linux/native/libsimdsort/xss-common-includes.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
#ifndef XSS_COMMON_INCLUDES
|
||||
#define XSS_COMMON_INCLUDES
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
/*
|
||||
Workaround for the bug in GCC12 (that was fixed in GCC 12.3.1).
|
||||
More details are available at:
|
||||
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105593
|
||||
*/
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#pragma GCC diagnostic ignored "-Wuninitialized"
|
||||
#include <immintrin.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#define X86_SIMD_SORT_INFINITY std::numeric_limits<double>::infinity()
|
||||
#define X86_SIMD_SORT_INFINITYF std::numeric_limits<float>::infinity()
|
||||
#define X86_SIMD_SORT_INFINITYH 0x7c00
|
||||
#define X86_SIMD_SORT_NEGINFINITYH 0xfc00
|
||||
#define X86_SIMD_SORT_MAX_UINT16 std::numeric_limits<uint16_t>::max()
|
||||
#define X86_SIMD_SORT_MAX_INT16 std::numeric_limits<int16_t>::max()
|
||||
#define X86_SIMD_SORT_MIN_INT16 std::numeric_limits<int16_t>::min()
|
||||
#define X86_SIMD_SORT_MAX_UINT32 std::numeric_limits<uint32_t>::max()
|
||||
#define X86_SIMD_SORT_MAX_INT32 std::numeric_limits<int32_t>::max()
|
||||
#define X86_SIMD_SORT_MIN_INT32 std::numeric_limits<int32_t>::min()
|
||||
#define X86_SIMD_SORT_MAX_UINT64 std::numeric_limits<uint64_t>::max()
|
||||
#define X86_SIMD_SORT_MAX_INT64 std::numeric_limits<int64_t>::max()
|
||||
#define X86_SIMD_SORT_MIN_INT64 std::numeric_limits<int64_t>::min()
|
||||
#define ZMM_MAX_DOUBLE _mm512_set1_pd(X86_SIMD_SORT_INFINITY)
|
||||
#define ZMM_MAX_UINT64 _mm512_set1_epi64(X86_SIMD_SORT_MAX_UINT64)
|
||||
#define ZMM_MAX_INT64 _mm512_set1_epi64(X86_SIMD_SORT_MAX_INT64)
|
||||
#define ZMM_MAX_FLOAT _mm512_set1_ps(X86_SIMD_SORT_INFINITYF)
|
||||
#define ZMM_MAX_UINT _mm512_set1_epi32(X86_SIMD_SORT_MAX_UINT32)
|
||||
#define ZMM_MAX_INT _mm512_set1_epi32(X86_SIMD_SORT_MAX_INT32)
|
||||
#define ZMM_MAX_HALF _mm512_set1_epi16(X86_SIMD_SORT_INFINITYH)
|
||||
#define YMM_MAX_HALF _mm256_set1_epi16(X86_SIMD_SORT_INFINITYH)
|
||||
#define ZMM_MAX_UINT16 _mm512_set1_epi16(X86_SIMD_SORT_MAX_UINT16)
|
||||
#define ZMM_MAX_INT16 _mm512_set1_epi16(X86_SIMD_SORT_MAX_INT16)
|
||||
#define SHUFFLE_MASK(a, b, c, d) (a << 6) | (b << 4) | (c << 2) | d
|
||||
|
||||
#define PRAGMA(x) _Pragma(#x)
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
/* Compiler specific macros specific */
|
||||
#if defined(__GNUC__)
|
||||
#define X86_SIMD_SORT_INLINE static inline
|
||||
#define X86_SIMD_SORT_FINLINE static inline __attribute__((always_inline))
|
||||
#else
|
||||
#define X86_SIMD_SORT_INLINE static
|
||||
#define X86_SIMD_SORT_FINLINE static
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 8
|
||||
#define X86_SIMD_SORT_UNROLL_LOOP(num) PRAGMA(GCC unroll num)
|
||||
#else
|
||||
#define X86_SIMD_SORT_UNROLL_LOOP(num)
|
||||
#endif
|
||||
|
||||
typedef size_t arrsize_t;
|
||||
|
||||
template <typename type>
|
||||
struct zmm_vector;
|
||||
|
||||
template <typename type>
|
||||
struct ymm_vector;
|
||||
|
||||
template <typename type>
|
||||
struct avx2_vector;
|
||||
|
||||
#endif // XSS_COMMON_INCLUDES
|
||||
528
src/java.base/linux/native/libsimdsort/xss-common-qsort.h
Normal file
528
src/java.base/linux/native/libsimdsort/xss-common-qsort.h
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
#ifndef XSS_COMMON_QSORT
|
||||
#define XSS_COMMON_QSORT
|
||||
|
||||
/*
|
||||
* Quicksort using AVX-512. The ideas and code are based on these two research
|
||||
* papers [1] and [2]. On a high level, the idea is to vectorize quicksort
|
||||
* partitioning using AVX-512 compressstore instructions. If the array size is
|
||||
* < 128, then use Bitonic sorting network implemented on 512-bit registers.
|
||||
* The precise network definitions depend on the dtype and are defined in
|
||||
* separate files: avx512-16bit-qsort.hpp, avx512-32bit-qsort.hpp and
|
||||
* avx512-64bit-qsort.hpp. Article [4] is a good resource for bitonic sorting
|
||||
* network. The core implementations of the vectorized qsort functions
|
||||
* avx512_qsort<T>(T*, arrsize_t) are modified versions of avx2 quicksort
|
||||
* presented in the paper [2] and source code associated with that paper [3].
|
||||
*
|
||||
* [1] Fast and Robust Vectorized In-Place Sorting of Primitive Types
|
||||
* https://drops.dagstuhl.de/opus/volltexte/2021/13775/
|
||||
*
|
||||
* [2] A Novel Hybrid Quicksort Algorithm Vectorized using AVX-512 on Intel
|
||||
* Skylake https://arxiv.org/pdf/1704.08579.pdf
|
||||
*
|
||||
* [3] https://github.com/simd-sorting/fast-and-robust: SPDX-License-Identifier:
|
||||
* MIT
|
||||
*
|
||||
* [4] https://mitp-content-server.mit.edu/books/content/sectbyfn?collid=books_pres_0&fn=Chapter%2027.pdf&id=8030
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xss-common-includes.h"
|
||||
#include "xss-pivot-selection.hpp"
|
||||
#include "xss-network-qsort.hpp"
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool is_a_nan(T elem) {
|
||||
return std::isnan(elem);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
X86_SIMD_SORT_INLINE T get_pivot_scalar(T *arr, const int64_t left, const int64_t right) {
|
||||
// median of 8 equally spaced elements
|
||||
int64_t NUM_ELEMENTS = 8;
|
||||
int64_t MID = NUM_ELEMENTS / 2;
|
||||
int64_t size = (right - left) / NUM_ELEMENTS;
|
||||
T temp[NUM_ELEMENTS];
|
||||
for (int64_t i = 0; i < NUM_ELEMENTS; i++) temp[i] = arr[left + (i * size)];
|
||||
std::sort(temp, temp + NUM_ELEMENTS);
|
||||
return temp[MID];
|
||||
}
|
||||
|
||||
template <typename vtype, typename T = typename vtype::type_t>
|
||||
bool comparison_func_ge(const T &a, const T &b) {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
template <typename vtype, typename T = typename vtype::type_t>
|
||||
bool comparison_func_gt(const T &a, const T &b) {
|
||||
return a <= b;
|
||||
}
|
||||
|
||||
/*
|
||||
* COEX == Compare and Exchange two registers by swapping min and max values
|
||||
*/
|
||||
template <typename vtype, typename mm_t>
|
||||
X86_SIMD_SORT_INLINE void COEX(mm_t &a, mm_t &b) {
|
||||
mm_t temp = a;
|
||||
a = vtype::min(a, b);
|
||||
b = vtype::max(temp, b);
|
||||
}
|
||||
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t,
|
||||
typename opmask_t = typename vtype::opmask_t>
|
||||
X86_SIMD_SORT_INLINE reg_t cmp_merge(reg_t in1, reg_t in2, opmask_t mask) {
|
||||
reg_t min = vtype::min(in2, in1);
|
||||
reg_t max = vtype::max(in2, in1);
|
||||
return vtype::mask_mov(min, mask, max); // 0 -> min, 1 -> max
|
||||
}
|
||||
|
||||
template <typename vtype, typename type_t, typename reg_t>
|
||||
int avx512_double_compressstore(type_t *left_addr, type_t *right_addr,
|
||||
typename vtype::opmask_t k, reg_t reg) {
|
||||
int amount_ge_pivot = _mm_popcnt_u32((int)k);
|
||||
|
||||
vtype::mask_compressstoreu(left_addr, vtype::knot_opmask(k), reg);
|
||||
vtype::mask_compressstoreu(right_addr + vtype::numlanes - amount_ge_pivot,
|
||||
k, reg);
|
||||
|
||||
return amount_ge_pivot;
|
||||
}
|
||||
|
||||
// Generic function dispatches to AVX2 or AVX512 code
|
||||
template <typename vtype, typename type_t,
|
||||
typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_INLINE arrsize_t partition_vec(type_t *l_store, type_t *r_store,
|
||||
const reg_t curr_vec,
|
||||
const reg_t pivot_vec,
|
||||
reg_t &smallest_vec,
|
||||
reg_t &biggest_vec, bool use_gt) {
|
||||
//typename vtype::opmask_t ge_mask = vtype::ge(curr_vec, pivot_vec);
|
||||
typename vtype::opmask_t mask;
|
||||
if (use_gt) mask = vtype::gt(curr_vec, pivot_vec);
|
||||
else mask = vtype::ge(curr_vec, pivot_vec);
|
||||
|
||||
int amount_ge_pivot =
|
||||
vtype::double_compressstore(l_store, r_store, mask, curr_vec);
|
||||
|
||||
smallest_vec = vtype::min(curr_vec, smallest_vec);
|
||||
biggest_vec = vtype::max(curr_vec, biggest_vec);
|
||||
|
||||
return amount_ge_pivot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parition an array based on the pivot and returns the index of the
|
||||
* first element that is greater than or equal to the pivot.
|
||||
*/
|
||||
template <typename vtype, typename type_t>
|
||||
X86_SIMD_SORT_INLINE arrsize_t partition_avx512(type_t *arr, arrsize_t left,
|
||||
arrsize_t right, type_t pivot,
|
||||
type_t *smallest,
|
||||
type_t *biggest,
|
||||
bool use_gt) {
|
||||
auto comparison_func = use_gt ? comparison_func_gt<vtype> : comparison_func_ge<vtype>;
|
||||
/* make array length divisible by vtype::numlanes , shortening the array */
|
||||
for (int32_t i = (right - left) % vtype::numlanes; i > 0; --i) {
|
||||
*smallest = std::min(*smallest, arr[left], comparison_func);
|
||||
*biggest = std::max(*biggest, arr[left], comparison_func);
|
||||
if (!comparison_func(arr[left], pivot)) {
|
||||
std::swap(arr[left], arr[--right]);
|
||||
} else {
|
||||
++left;
|
||||
}
|
||||
}
|
||||
|
||||
if (left == right)
|
||||
return left; /* less than vtype::numlanes elements in the array */
|
||||
|
||||
using reg_t = typename vtype::reg_t;
|
||||
reg_t pivot_vec = vtype::set1(pivot);
|
||||
reg_t min_vec = vtype::set1(*smallest);
|
||||
reg_t max_vec = vtype::set1(*biggest);
|
||||
|
||||
if (right - left == vtype::numlanes) {
|
||||
reg_t vec = vtype::loadu(arr + left);
|
||||
arrsize_t unpartitioned = right - left - vtype::numlanes;
|
||||
arrsize_t l_store = left;
|
||||
|
||||
arrsize_t amount_ge_pivot =
|
||||
partition_vec<vtype>(arr + l_store, arr + l_store + unpartitioned,
|
||||
vec, pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
*smallest = vtype::reducemin(min_vec);
|
||||
*biggest = vtype::reducemax(max_vec);
|
||||
return l_store;
|
||||
}
|
||||
|
||||
// first and last vtype::numlanes values are partitioned at the end
|
||||
reg_t vec_left = vtype::loadu(arr + left);
|
||||
reg_t vec_right = vtype::loadu(arr + (right - vtype::numlanes));
|
||||
// store points of the vectors
|
||||
arrsize_t unpartitioned = right - left - vtype::numlanes;
|
||||
arrsize_t l_store = left;
|
||||
// indices for loading the elements
|
||||
left += vtype::numlanes;
|
||||
right -= vtype::numlanes;
|
||||
while (right - left != 0) {
|
||||
reg_t curr_vec;
|
||||
/*
|
||||
* if fewer elements are stored on the right side of the array,
|
||||
* then next elements are loaded from the right side,
|
||||
* otherwise from the left side
|
||||
*/
|
||||
if ((l_store + unpartitioned + vtype::numlanes) - right <
|
||||
left - l_store) {
|
||||
right -= vtype::numlanes;
|
||||
curr_vec = vtype::loadu(arr + right);
|
||||
} else {
|
||||
curr_vec = vtype::loadu(arr + left);
|
||||
left += vtype::numlanes;
|
||||
}
|
||||
// partition the current vector and save it on both sides of the array
|
||||
arrsize_t amount_ge_pivot =
|
||||
partition_vec<vtype>(arr + l_store, arr + l_store + unpartitioned,
|
||||
curr_vec, pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
unpartitioned -= vtype::numlanes;
|
||||
}
|
||||
|
||||
/* partition and save vec_left and vec_right */
|
||||
arrsize_t amount_ge_pivot =
|
||||
partition_vec<vtype>(arr + l_store, arr + l_store + unpartitioned,
|
||||
vec_left, pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
unpartitioned -= vtype::numlanes;
|
||||
|
||||
amount_ge_pivot =
|
||||
partition_vec<vtype>(arr + l_store, arr + l_store + unpartitioned,
|
||||
vec_right, pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
unpartitioned -= vtype::numlanes;
|
||||
|
||||
*smallest = vtype::reducemin(min_vec);
|
||||
*biggest = vtype::reducemax(max_vec);
|
||||
return l_store;
|
||||
}
|
||||
|
||||
template <typename vtype, int num_unroll,
|
||||
typename type_t = typename vtype::type_t>
|
||||
X86_SIMD_SORT_INLINE arrsize_t
|
||||
partition_avx512_unrolled(type_t *arr, arrsize_t left, arrsize_t right,
|
||||
type_t pivot, type_t *smallest, type_t *biggest, bool use_gt) {
|
||||
if constexpr (num_unroll == 0) {
|
||||
return partition_avx512<vtype>(arr, left, right, pivot, smallest,
|
||||
biggest, use_gt);
|
||||
}
|
||||
|
||||
/* Use regular partition_avx512 for smaller arrays */
|
||||
if (right - left < 3 * num_unroll * vtype::numlanes) {
|
||||
return partition_avx512<vtype>(arr, left, right, pivot, smallest,
|
||||
biggest, use_gt);
|
||||
}
|
||||
|
||||
auto comparison_func = use_gt ? comparison_func_gt<vtype> : comparison_func_ge<vtype>;
|
||||
/* make array length divisible by vtype::numlanes, shortening the array */
|
||||
for (int32_t i = ((right - left) % (vtype::numlanes)); i > 0; --i) {
|
||||
*smallest = std::min(*smallest, arr[left], comparison_func);
|
||||
*biggest = std::max(*biggest, arr[left], comparison_func);
|
||||
if (!comparison_func(arr[left], pivot)) {
|
||||
std::swap(arr[left], arr[--right]);
|
||||
} else {
|
||||
++left;
|
||||
}
|
||||
}
|
||||
|
||||
arrsize_t unpartitioned = right - left - vtype::numlanes;
|
||||
arrsize_t l_store = left;
|
||||
|
||||
using reg_t = typename vtype::reg_t;
|
||||
reg_t pivot_vec = vtype::set1(pivot);
|
||||
reg_t min_vec = vtype::set1(*smallest);
|
||||
reg_t max_vec = vtype::set1(*biggest);
|
||||
|
||||
/* Calculate and load more registers to make the rest of the array a
|
||||
* multiple of num_unroll. These registers will be partitioned at the very
|
||||
* end. */
|
||||
int vecsToPartition = ((right - left) / vtype::numlanes) % num_unroll;
|
||||
reg_t vec_align[num_unroll];
|
||||
for (int i = 0; i < vecsToPartition; i++) {
|
||||
vec_align[i] = vtype::loadu(arr + left + i * vtype::numlanes);
|
||||
}
|
||||
left += vecsToPartition * vtype::numlanes;
|
||||
|
||||
/* We will now have atleast 3*num_unroll registers worth of data to
|
||||
* process. Load left and right vtype::numlanes*num_unroll values into
|
||||
* registers to make space for in-place parition. The vec_left and
|
||||
* vec_right registers are partitioned at the end */
|
||||
reg_t vec_left[num_unroll], vec_right[num_unroll];
|
||||
X86_SIMD_SORT_UNROLL_LOOP(8)
|
||||
for (int ii = 0; ii < num_unroll; ++ii) {
|
||||
vec_left[ii] = vtype::loadu(arr + left + vtype::numlanes * ii);
|
||||
vec_right[ii] =
|
||||
vtype::loadu(arr + (right - vtype::numlanes * (num_unroll - ii)));
|
||||
}
|
||||
/* indices for loading the elements */
|
||||
left += num_unroll * vtype::numlanes;
|
||||
right -= num_unroll * vtype::numlanes;
|
||||
while (right - left != 0) {
|
||||
reg_t curr_vec[num_unroll];
|
||||
/*
|
||||
* if fewer elements are stored on the right side of the array,
|
||||
* then next elements are loaded from the right side,
|
||||
* otherwise from the left side
|
||||
*/
|
||||
if ((l_store + unpartitioned + vtype::numlanes) - right <
|
||||
left - l_store) {
|
||||
right -= num_unroll * vtype::numlanes;
|
||||
X86_SIMD_SORT_UNROLL_LOOP(8)
|
||||
for (int ii = 0; ii < num_unroll; ++ii) {
|
||||
curr_vec[ii] = vtype::loadu(arr + right + ii * vtype::numlanes);
|
||||
/*
|
||||
* error: '_mm_prefetch' needs target feature mmx on clang-cl
|
||||
*/
|
||||
#if !(defined(_MSC_VER) && defined(__clang__))
|
||||
_mm_prefetch((char *)(arr + right + ii * vtype::numlanes -
|
||||
num_unroll * vtype::numlanes),
|
||||
_MM_HINT_T0);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
X86_SIMD_SORT_UNROLL_LOOP(8)
|
||||
for (int ii = 0; ii < num_unroll; ++ii) {
|
||||
curr_vec[ii] = vtype::loadu(arr + left + ii * vtype::numlanes);
|
||||
/*
|
||||
* error: '_mm_prefetch' needs target feature mmx on clang-cl
|
||||
*/
|
||||
#if !(defined(_MSC_VER) && defined(__clang__))
|
||||
_mm_prefetch((char *)(arr + left + ii * vtype::numlanes +
|
||||
num_unroll * vtype::numlanes),
|
||||
_MM_HINT_T0);
|
||||
#endif
|
||||
}
|
||||
left += num_unroll * vtype::numlanes;
|
||||
}
|
||||
/* partition the current vector and save it on both sides of the array
|
||||
* */
|
||||
X86_SIMD_SORT_UNROLL_LOOP(8)
|
||||
for (int ii = 0; ii < num_unroll; ++ii) {
|
||||
arrsize_t amount_ge_pivot = partition_vec<vtype>(
|
||||
arr + l_store, arr + l_store + unpartitioned, curr_vec[ii],
|
||||
pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
unpartitioned -= vtype::numlanes;
|
||||
}
|
||||
}
|
||||
|
||||
/* partition and save vec_left[num_unroll] and vec_right[num_unroll] */
|
||||
X86_SIMD_SORT_UNROLL_LOOP(8)
|
||||
for (int ii = 0; ii < num_unroll; ++ii) {
|
||||
arrsize_t amount_ge_pivot =
|
||||
partition_vec<vtype>(arr + l_store, arr + l_store + unpartitioned,
|
||||
vec_left[ii], pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
unpartitioned -= vtype::numlanes;
|
||||
}
|
||||
X86_SIMD_SORT_UNROLL_LOOP(8)
|
||||
for (int ii = 0; ii < num_unroll; ++ii) {
|
||||
arrsize_t amount_ge_pivot =
|
||||
partition_vec<vtype>(arr + l_store, arr + l_store + unpartitioned,
|
||||
vec_right[ii], pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
unpartitioned -= vtype::numlanes;
|
||||
}
|
||||
|
||||
/* partition and save vec_align[vecsToPartition] */
|
||||
X86_SIMD_SORT_UNROLL_LOOP(8)
|
||||
for (int ii = 0; ii < vecsToPartition; ++ii) {
|
||||
arrsize_t amount_ge_pivot =
|
||||
partition_vec<vtype>(arr + l_store, arr + l_store + unpartitioned,
|
||||
vec_align[ii], pivot_vec, min_vec, max_vec, use_gt);
|
||||
l_store += (vtype::numlanes - amount_ge_pivot);
|
||||
unpartitioned -= vtype::numlanes;
|
||||
}
|
||||
|
||||
*smallest = vtype::reducemin(min_vec);
|
||||
*biggest = vtype::reducemax(max_vec);
|
||||
return l_store;
|
||||
}
|
||||
|
||||
template <typename vtype, int maxN>
|
||||
void sort_n(typename vtype::type_t *arr, int N);
|
||||
|
||||
template <typename vtype, typename type_t>
|
||||
static void qsort_(type_t *arr, arrsize_t left, arrsize_t right,
|
||||
arrsize_t max_iters) {
|
||||
/*
|
||||
* Resort to std::sort if quicksort isnt making any progress
|
||||
*/
|
||||
if (max_iters <= 0) {
|
||||
std::sort(arr + left, arr + right + 1, comparison_func_ge<vtype>);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Base case: use bitonic networks to sort arrays <=
|
||||
* vtype::network_sort_threshold
|
||||
*/
|
||||
if (right + 1 - left <= vtype::network_sort_threshold) {
|
||||
sort_n<vtype, vtype::network_sort_threshold>(
|
||||
arr + left, (int32_t)(right + 1 - left));
|
||||
return;
|
||||
}
|
||||
|
||||
type_t pivot = get_pivot_blocks<vtype, type_t>(arr, left, right);
|
||||
type_t smallest = vtype::type_max();
|
||||
type_t biggest = vtype::type_min();
|
||||
|
||||
arrsize_t pivot_index =
|
||||
partition_avx512_unrolled<vtype, vtype::partition_unroll_factor>(
|
||||
arr, left, right + 1, pivot, &smallest, &biggest, false);
|
||||
|
||||
if (pivot != smallest)
|
||||
qsort_<vtype>(arr, left, pivot_index - 1, max_iters - 1);
|
||||
if (pivot != biggest) qsort_<vtype>(arr, pivot_index, right, max_iters - 1);
|
||||
}
|
||||
|
||||
// Hooks for OpenJDK sort
|
||||
// to_index (exclusive)
|
||||
template <typename vtype, typename type_t>
|
||||
static int64_t vectorized_partition(type_t *arr, int64_t from_index, int64_t to_index, type_t pivot, bool use_gt) {
|
||||
type_t smallest = vtype::type_max();
|
||||
type_t biggest = vtype::type_min();
|
||||
int64_t pivot_index = partition_avx512_unrolled<vtype, 2>(
|
||||
arr, from_index, to_index, pivot, &smallest, &biggest, use_gt);
|
||||
return pivot_index;
|
||||
}
|
||||
|
||||
// partitioning functions
|
||||
template <typename vtype, typename T>
|
||||
X86_SIMD_SORT_INLINE void simd_dual_pivot_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2){
|
||||
const T pivot1 = arr[index_pivot1];
|
||||
const T pivot2 = arr[index_pivot2];
|
||||
|
||||
const int64_t low = from_index;
|
||||
const int64_t high = to_index;
|
||||
const int64_t start = low + 1;
|
||||
const int64_t end = high - 1;
|
||||
|
||||
|
||||
std::swap(arr[index_pivot1], arr[low]);
|
||||
std::swap(arr[index_pivot2], arr[end]);
|
||||
|
||||
|
||||
const int64_t pivot_index2 = vectorized_partition<vtype, T>(arr, start, end, pivot2, true); // use_gt = true
|
||||
std::swap(arr[end], arr[pivot_index2]);
|
||||
int64_t upper = pivot_index2;
|
||||
|
||||
// if all other elements are greater than pivot2 (and pivot1), no need to do further partitioning
|
||||
if (upper == start) {
|
||||
pivot_indices[0] = low;
|
||||
pivot_indices[1] = upper;
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t pivot_index1 = vectorized_partition<vtype, T>(arr, start, upper, pivot1, false); // use_ge (use_gt = false)
|
||||
int64_t lower = pivot_index1 - 1;
|
||||
std::swap(arr[low], arr[lower]);
|
||||
|
||||
pivot_indices[0] = lower;
|
||||
pivot_indices[1] = upper;
|
||||
}
|
||||
|
||||
template <typename vtype, typename T>
|
||||
X86_SIMD_SORT_INLINE void simd_single_pivot_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot) {
|
||||
const T pivot = arr[index_pivot];
|
||||
|
||||
const int64_t low = from_index;
|
||||
const int64_t high = to_index;
|
||||
const int64_t end = high - 1;
|
||||
|
||||
|
||||
const int64_t pivot_index1 = vectorized_partition<vtype, T>(arr, low, high, pivot, false); // use_gt = false (use_ge)
|
||||
int64_t lower = pivot_index1;
|
||||
|
||||
const int64_t pivot_index2 = vectorized_partition<vtype, T>(arr, pivot_index1, high, pivot, true); // use_gt = true
|
||||
int64_t upper = pivot_index2;
|
||||
|
||||
pivot_indices[0] = lower;
|
||||
pivot_indices[1] = upper;
|
||||
}
|
||||
|
||||
template <typename vtype, typename T>
|
||||
X86_SIMD_SORT_INLINE void simd_fast_partition(T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2) {
|
||||
if (index_pivot1 != index_pivot2) {
|
||||
simd_dual_pivot_partition<vtype, T>(arr, from_index, to_index, pivot_indices, index_pivot1, index_pivot2);
|
||||
}
|
||||
else {
|
||||
simd_single_pivot_partition<vtype, T>(arr, from_index, to_index, pivot_indices, index_pivot1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
X86_SIMD_SORT_INLINE void insertion_sort(T *arr, int32_t from_index, int32_t to_index) {
|
||||
for (int i, k = from_index; ++k < to_index; ) {
|
||||
T ai = arr[i = k];
|
||||
if (ai < arr[i - 1]) {
|
||||
while (--i >= from_index && ai < arr[i]) {
|
||||
arr[i + 1] = arr[i];
|
||||
}
|
||||
arr[i + 1] = ai;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename vtype, typename T>
|
||||
X86_SIMD_SORT_INLINE void simd_fast_sort(T *arr, arrsize_t from_index, arrsize_t to_index, const arrsize_t INS_SORT_THRESHOLD)
|
||||
{
|
||||
arrsize_t arrsize = to_index - from_index;
|
||||
if (arrsize <= INS_SORT_THRESHOLD) {
|
||||
insertion_sort<T>(arr, from_index, to_index);
|
||||
} else {
|
||||
qsort_<vtype, T>(arr, from_index, to_index - 1, 2 * (arrsize_t)log2(arrsize));
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFINE_METHODS(ISA, VTYPE) \
|
||||
template <typename T> \
|
||||
X86_SIMD_SORT_INLINE void ISA##_fast_sort( \
|
||||
T *arr, arrsize_t from_index, arrsize_t to_index, const arrsize_t INS_SORT_THRESHOLD) \
|
||||
{ \
|
||||
simd_fast_sort<VTYPE, T>(arr, from_index, to_index, INS_SORT_THRESHOLD); \
|
||||
} \
|
||||
template <typename T> \
|
||||
X86_SIMD_SORT_INLINE void ISA##_fast_partition( \
|
||||
T *arr, int64_t from_index, int64_t to_index, int32_t *pivot_indices, int64_t index_pivot1, int64_t index_pivot2) \
|
||||
{ \
|
||||
simd_fast_partition<VTYPE, T>(arr, from_index, to_index, pivot_indices, index_pivot1, index_pivot2); \
|
||||
}
|
||||
|
||||
DEFINE_METHODS(avx2, avx2_vector<T>)
|
||||
DEFINE_METHODS(avx512, zmm_vector<T>)
|
||||
|
||||
#endif // XSS_COMMON_QSORT
|
||||
209
src/java.base/linux/native/libsimdsort/xss-network-qsort.hpp
Normal file
209
src/java.base/linux/native/libsimdsort/xss-network-qsort.hpp
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
#ifndef XSS_NETWORK_QSORT
|
||||
#define XSS_NETWORK_QSORT
|
||||
|
||||
#include "xss-common-qsort.h"
|
||||
#include "xss-optimal-networks.hpp"
|
||||
|
||||
template <typename vtype, int numVecs, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void bitonic_sort_n_vec(reg_t *regs) {
|
||||
if constexpr (numVecs == 1) {
|
||||
UNUSED(regs);
|
||||
return;
|
||||
} else if constexpr (numVecs == 2) {
|
||||
COEX<vtype>(regs[0], regs[1]);
|
||||
} else if constexpr (numVecs == 4) {
|
||||
optimal_sort_4<vtype>(regs);
|
||||
} else if constexpr (numVecs == 8) {
|
||||
optimal_sort_8<vtype>(regs);
|
||||
} else if constexpr (numVecs == 16) {
|
||||
optimal_sort_16<vtype>(regs);
|
||||
} else if constexpr (numVecs == 32) {
|
||||
optimal_sort_32<vtype>(regs);
|
||||
} else {
|
||||
static_assert(numVecs == -1, "should not reach here");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Swizzle ops explained:
|
||||
* swap_n<scale>: swap neighbouring blocks of size <scale/2> within block of
|
||||
* size <scale> reg i = [7,6,5,4,3,2,1,0] swap_n<2>: =
|
||||
* [[6,7],[4,5],[2,3],[0,1]] swap_n<4>: = [[5,4,7,6],[1,0,3,2]] swap_n<8>: =
|
||||
* [[3,2,1,0,7,6,5,4]] reverse_n<scale>: reverse elements within block of size
|
||||
* <scale> reg i = [7,6,5,4,3,2,1,0] rev_n<2>: =
|
||||
* [[6,7],[4,5],[2,3],[0,1]] rev_n<4>: = [[4,5,6,7],[0,1,2,3]] rev_n<8>: =
|
||||
* [[0,1,2,3,4,5,6,7]] merge_n<scale>: merge blocks of <scale/2> elements from
|
||||
* two regs reg b,a = [a,a,a,a,a,a,a,a], [b,b,b,b,b,b,b,b] merge_n<2> =
|
||||
* [a,b,a,b,a,b,a,b] merge_n<4> = [a,a,b,b,a,a,b,b] merge_n<8> =
|
||||
* [a,a,a,a,b,b,b,b]
|
||||
*/
|
||||
|
||||
template <typename vtype, int numVecs, int scale, bool first = true>
|
||||
X86_SIMD_SORT_FINLINE void internal_merge_n_vec(typename vtype::reg_t *reg) {
|
||||
using reg_t = typename vtype::reg_t;
|
||||
using swizzle = typename vtype::swizzle_ops;
|
||||
if constexpr (scale <= 1) {
|
||||
UNUSED(reg);
|
||||
return;
|
||||
} else {
|
||||
if constexpr (first) {
|
||||
// Use reverse then merge
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = 0; i < numVecs; i++) {
|
||||
reg_t &v = reg[i];
|
||||
reg_t rev = swizzle::template reverse_n<vtype, scale>(v);
|
||||
COEX<vtype>(rev, v);
|
||||
v = swizzle::template merge_n<vtype, scale>(v, rev);
|
||||
}
|
||||
} else {
|
||||
// Use swap then merge
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = 0; i < numVecs; i++) {
|
||||
reg_t &v = reg[i];
|
||||
reg_t swap = swizzle::template swap_n<vtype, scale>(v);
|
||||
COEX<vtype>(swap, v);
|
||||
v = swizzle::template merge_n<vtype, scale>(v, swap);
|
||||
}
|
||||
}
|
||||
internal_merge_n_vec<vtype, numVecs, scale / 2, false>(reg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename vtype, int numVecs, int scale,
|
||||
typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void merge_substep_n_vec(reg_t *regs) {
|
||||
using swizzle = typename vtype::swizzle_ops;
|
||||
if constexpr (numVecs <= 1) {
|
||||
UNUSED(regs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reverse upper half of vectors
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = numVecs / 2; i < numVecs; i++) {
|
||||
regs[i] = swizzle::template reverse_n<vtype, scale>(regs[i]);
|
||||
}
|
||||
// Do compare exchanges
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = 0; i < numVecs / 2; i++) {
|
||||
COEX<vtype>(regs[i], regs[numVecs - 1 - i]);
|
||||
}
|
||||
|
||||
merge_substep_n_vec<vtype, numVecs / 2, scale>(regs);
|
||||
merge_substep_n_vec<vtype, numVecs / 2, scale>(regs + numVecs / 2);
|
||||
}
|
||||
|
||||
template <typename vtype, int numVecs, int scale,
|
||||
typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void merge_step_n_vec(reg_t *regs) {
|
||||
// Do cross vector merges
|
||||
merge_substep_n_vec<vtype, numVecs, scale>(regs);
|
||||
|
||||
// Do internal vector merges
|
||||
internal_merge_n_vec<vtype, numVecs, scale>(regs);
|
||||
}
|
||||
|
||||
template <typename vtype, int numVecs, int numPer = 2,
|
||||
typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void merge_n_vec(reg_t *regs) {
|
||||
if constexpr (numPer > vtype::numlanes) {
|
||||
UNUSED(regs);
|
||||
return;
|
||||
} else {
|
||||
merge_step_n_vec<vtype, numVecs, numPer>(regs);
|
||||
merge_n_vec<vtype, numVecs, numPer * 2>(regs);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename vtype, int numVecs, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_INLINE void sort_n_vec(typename vtype::type_t *arr, int N) {
|
||||
static_assert(numVecs > 0, "numVecs should be > 0");
|
||||
if constexpr (numVecs > 1) {
|
||||
if (N * 2 <= numVecs * vtype::numlanes) {
|
||||
sort_n_vec<vtype, numVecs / 2>(arr, N);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reg_t vecs[numVecs];
|
||||
|
||||
// Generate masks for loading and storing
|
||||
typename vtype::opmask_t ioMasks[numVecs - numVecs / 2];
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = numVecs / 2, j = 0; i < numVecs; i++, j++) {
|
||||
uint64_t num_to_read =
|
||||
std::min((uint64_t)std::max(0, N - i * vtype::numlanes),
|
||||
(uint64_t)vtype::numlanes);
|
||||
ioMasks[j] = vtype::get_partial_loadmask(num_to_read);
|
||||
}
|
||||
|
||||
// Unmasked part of the load
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = 0; i < numVecs / 2; i++) {
|
||||
vecs[i] = vtype::loadu(arr + i * vtype::numlanes);
|
||||
}
|
||||
// Masked part of the load
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = numVecs / 2, j = 0; i < numVecs; i++, j++) {
|
||||
vecs[i] = vtype::mask_loadu(vtype::zmm_max(), ioMasks[j],
|
||||
arr + i * vtype::numlanes);
|
||||
}
|
||||
|
||||
/* Run the initial sorting network to sort the columns of the [numVecs x
|
||||
* num_lanes] matrix
|
||||
*/
|
||||
bitonic_sort_n_vec<vtype, numVecs>(vecs);
|
||||
|
||||
// Merge the vectors using bitonic merging networks
|
||||
merge_n_vec<vtype, numVecs>(vecs);
|
||||
|
||||
// Unmasked part of the store
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = 0; i < numVecs / 2; i++) {
|
||||
vtype::storeu(arr + i * vtype::numlanes, vecs[i]);
|
||||
}
|
||||
// Masked part of the store
|
||||
X86_SIMD_SORT_UNROLL_LOOP(64)
|
||||
for (int i = numVecs / 2, j = 0; i < numVecs; i++, j++) {
|
||||
vtype::mask_storeu(arr + i * vtype::numlanes, ioMasks[j], vecs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename vtype, int maxN>
|
||||
X86_SIMD_SORT_INLINE void sort_n(typename vtype::type_t *arr, int N) {
|
||||
constexpr int numVecs = maxN / vtype::numlanes;
|
||||
constexpr bool isMultiple = (maxN == (vtype::numlanes * numVecs));
|
||||
constexpr bool powerOfTwo = (numVecs != 0 && !(numVecs & (numVecs - 1)));
|
||||
static_assert(powerOfTwo == true && isMultiple == true,
|
||||
"maxN must be vtype::numlanes times a power of 2");
|
||||
|
||||
sort_n_vec<vtype, numVecs>(arr, N);
|
||||
}
|
||||
#endif
|
||||
342
src/java.base/linux/native/libsimdsort/xss-optimal-networks.hpp
Normal file
342
src/java.base/linux/native/libsimdsort/xss-optimal-networks.hpp
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort) All of these sources
|
||||
// files are generated from the optimal networks described in
|
||||
// https://bertdobbelaere.github.io/sorting_networks.html
|
||||
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void optimal_sort_4(reg_t *vecs) {
|
||||
COEX<vtype>(vecs[0], vecs[2]);
|
||||
COEX<vtype>(vecs[1], vecs[3]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[1]);
|
||||
COEX<vtype>(vecs[2], vecs[3]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[2]);
|
||||
}
|
||||
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void optimal_sort_8(reg_t *vecs) {
|
||||
COEX<vtype>(vecs[0], vecs[2]);
|
||||
COEX<vtype>(vecs[1], vecs[3]);
|
||||
COEX<vtype>(vecs[4], vecs[6]);
|
||||
COEX<vtype>(vecs[5], vecs[7]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[4]);
|
||||
COEX<vtype>(vecs[1], vecs[5]);
|
||||
COEX<vtype>(vecs[2], vecs[6]);
|
||||
COEX<vtype>(vecs[3], vecs[7]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[1]);
|
||||
COEX<vtype>(vecs[2], vecs[3]);
|
||||
COEX<vtype>(vecs[4], vecs[5]);
|
||||
COEX<vtype>(vecs[6], vecs[7]);
|
||||
|
||||
COEX<vtype>(vecs[2], vecs[4]);
|
||||
COEX<vtype>(vecs[3], vecs[5]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[4]);
|
||||
COEX<vtype>(vecs[3], vecs[6]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[2]);
|
||||
COEX<vtype>(vecs[3], vecs[4]);
|
||||
COEX<vtype>(vecs[5], vecs[6]);
|
||||
}
|
||||
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void optimal_sort_16(reg_t *vecs) {
|
||||
COEX<vtype>(vecs[0], vecs[13]);
|
||||
COEX<vtype>(vecs[1], vecs[12]);
|
||||
COEX<vtype>(vecs[2], vecs[15]);
|
||||
COEX<vtype>(vecs[3], vecs[14]);
|
||||
COEX<vtype>(vecs[4], vecs[8]);
|
||||
COEX<vtype>(vecs[5], vecs[6]);
|
||||
COEX<vtype>(vecs[7], vecs[11]);
|
||||
COEX<vtype>(vecs[9], vecs[10]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[5]);
|
||||
COEX<vtype>(vecs[1], vecs[7]);
|
||||
COEX<vtype>(vecs[2], vecs[9]);
|
||||
COEX<vtype>(vecs[3], vecs[4]);
|
||||
COEX<vtype>(vecs[6], vecs[13]);
|
||||
COEX<vtype>(vecs[8], vecs[14]);
|
||||
COEX<vtype>(vecs[10], vecs[15]);
|
||||
COEX<vtype>(vecs[11], vecs[12]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[1]);
|
||||
COEX<vtype>(vecs[2], vecs[3]);
|
||||
COEX<vtype>(vecs[4], vecs[5]);
|
||||
COEX<vtype>(vecs[6], vecs[8]);
|
||||
COEX<vtype>(vecs[7], vecs[9]);
|
||||
COEX<vtype>(vecs[10], vecs[11]);
|
||||
COEX<vtype>(vecs[12], vecs[13]);
|
||||
COEX<vtype>(vecs[14], vecs[15]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[2]);
|
||||
COEX<vtype>(vecs[1], vecs[3]);
|
||||
COEX<vtype>(vecs[4], vecs[10]);
|
||||
COEX<vtype>(vecs[5], vecs[11]);
|
||||
COEX<vtype>(vecs[6], vecs[7]);
|
||||
COEX<vtype>(vecs[8], vecs[9]);
|
||||
COEX<vtype>(vecs[12], vecs[14]);
|
||||
COEX<vtype>(vecs[13], vecs[15]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[2]);
|
||||
COEX<vtype>(vecs[3], vecs[12]);
|
||||
COEX<vtype>(vecs[4], vecs[6]);
|
||||
COEX<vtype>(vecs[5], vecs[7]);
|
||||
COEX<vtype>(vecs[8], vecs[10]);
|
||||
COEX<vtype>(vecs[9], vecs[11]);
|
||||
COEX<vtype>(vecs[13], vecs[14]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[4]);
|
||||
COEX<vtype>(vecs[2], vecs[6]);
|
||||
COEX<vtype>(vecs[5], vecs[8]);
|
||||
COEX<vtype>(vecs[7], vecs[10]);
|
||||
COEX<vtype>(vecs[9], vecs[13]);
|
||||
COEX<vtype>(vecs[11], vecs[14]);
|
||||
|
||||
COEX<vtype>(vecs[2], vecs[4]);
|
||||
COEX<vtype>(vecs[3], vecs[6]);
|
||||
COEX<vtype>(vecs[9], vecs[12]);
|
||||
COEX<vtype>(vecs[11], vecs[13]);
|
||||
|
||||
COEX<vtype>(vecs[3], vecs[5]);
|
||||
COEX<vtype>(vecs[6], vecs[8]);
|
||||
COEX<vtype>(vecs[7], vecs[9]);
|
||||
COEX<vtype>(vecs[10], vecs[12]);
|
||||
|
||||
COEX<vtype>(vecs[3], vecs[4]);
|
||||
COEX<vtype>(vecs[5], vecs[6]);
|
||||
COEX<vtype>(vecs[7], vecs[8]);
|
||||
COEX<vtype>(vecs[9], vecs[10]);
|
||||
COEX<vtype>(vecs[11], vecs[12]);
|
||||
|
||||
COEX<vtype>(vecs[6], vecs[7]);
|
||||
COEX<vtype>(vecs[8], vecs[9]);
|
||||
}
|
||||
|
||||
template <typename vtype, typename reg_t = typename vtype::reg_t>
|
||||
X86_SIMD_SORT_FINLINE void optimal_sort_32(reg_t *vecs) {
|
||||
COEX<vtype>(vecs[0], vecs[1]);
|
||||
COEX<vtype>(vecs[2], vecs[3]);
|
||||
COEX<vtype>(vecs[4], vecs[5]);
|
||||
COEX<vtype>(vecs[6], vecs[7]);
|
||||
COEX<vtype>(vecs[8], vecs[9]);
|
||||
COEX<vtype>(vecs[10], vecs[11]);
|
||||
COEX<vtype>(vecs[12], vecs[13]);
|
||||
COEX<vtype>(vecs[14], vecs[15]);
|
||||
COEX<vtype>(vecs[16], vecs[17]);
|
||||
COEX<vtype>(vecs[18], vecs[19]);
|
||||
COEX<vtype>(vecs[20], vecs[21]);
|
||||
COEX<vtype>(vecs[22], vecs[23]);
|
||||
COEX<vtype>(vecs[24], vecs[25]);
|
||||
COEX<vtype>(vecs[26], vecs[27]);
|
||||
COEX<vtype>(vecs[28], vecs[29]);
|
||||
COEX<vtype>(vecs[30], vecs[31]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[2]);
|
||||
COEX<vtype>(vecs[1], vecs[3]);
|
||||
COEX<vtype>(vecs[4], vecs[6]);
|
||||
COEX<vtype>(vecs[5], vecs[7]);
|
||||
COEX<vtype>(vecs[8], vecs[10]);
|
||||
COEX<vtype>(vecs[9], vecs[11]);
|
||||
COEX<vtype>(vecs[12], vecs[14]);
|
||||
COEX<vtype>(vecs[13], vecs[15]);
|
||||
COEX<vtype>(vecs[16], vecs[18]);
|
||||
COEX<vtype>(vecs[17], vecs[19]);
|
||||
COEX<vtype>(vecs[20], vecs[22]);
|
||||
COEX<vtype>(vecs[21], vecs[23]);
|
||||
COEX<vtype>(vecs[24], vecs[26]);
|
||||
COEX<vtype>(vecs[25], vecs[27]);
|
||||
COEX<vtype>(vecs[28], vecs[30]);
|
||||
COEX<vtype>(vecs[29], vecs[31]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[4]);
|
||||
COEX<vtype>(vecs[1], vecs[5]);
|
||||
COEX<vtype>(vecs[2], vecs[6]);
|
||||
COEX<vtype>(vecs[3], vecs[7]);
|
||||
COEX<vtype>(vecs[8], vecs[12]);
|
||||
COEX<vtype>(vecs[9], vecs[13]);
|
||||
COEX<vtype>(vecs[10], vecs[14]);
|
||||
COEX<vtype>(vecs[11], vecs[15]);
|
||||
COEX<vtype>(vecs[16], vecs[20]);
|
||||
COEX<vtype>(vecs[17], vecs[21]);
|
||||
COEX<vtype>(vecs[18], vecs[22]);
|
||||
COEX<vtype>(vecs[19], vecs[23]);
|
||||
COEX<vtype>(vecs[24], vecs[28]);
|
||||
COEX<vtype>(vecs[25], vecs[29]);
|
||||
COEX<vtype>(vecs[26], vecs[30]);
|
||||
COEX<vtype>(vecs[27], vecs[31]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[8]);
|
||||
COEX<vtype>(vecs[1], vecs[9]);
|
||||
COEX<vtype>(vecs[2], vecs[10]);
|
||||
COEX<vtype>(vecs[3], vecs[11]);
|
||||
COEX<vtype>(vecs[4], vecs[12]);
|
||||
COEX<vtype>(vecs[5], vecs[13]);
|
||||
COEX<vtype>(vecs[6], vecs[14]);
|
||||
COEX<vtype>(vecs[7], vecs[15]);
|
||||
COEX<vtype>(vecs[16], vecs[24]);
|
||||
COEX<vtype>(vecs[17], vecs[25]);
|
||||
COEX<vtype>(vecs[18], vecs[26]);
|
||||
COEX<vtype>(vecs[19], vecs[27]);
|
||||
COEX<vtype>(vecs[20], vecs[28]);
|
||||
COEX<vtype>(vecs[21], vecs[29]);
|
||||
COEX<vtype>(vecs[22], vecs[30]);
|
||||
COEX<vtype>(vecs[23], vecs[31]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[16]);
|
||||
COEX<vtype>(vecs[1], vecs[8]);
|
||||
COEX<vtype>(vecs[2], vecs[4]);
|
||||
COEX<vtype>(vecs[3], vecs[12]);
|
||||
COEX<vtype>(vecs[5], vecs[10]);
|
||||
COEX<vtype>(vecs[6], vecs[9]);
|
||||
COEX<vtype>(vecs[7], vecs[14]);
|
||||
COEX<vtype>(vecs[11], vecs[13]);
|
||||
COEX<vtype>(vecs[15], vecs[31]);
|
||||
COEX<vtype>(vecs[17], vecs[24]);
|
||||
COEX<vtype>(vecs[18], vecs[20]);
|
||||
COEX<vtype>(vecs[19], vecs[28]);
|
||||
COEX<vtype>(vecs[21], vecs[26]);
|
||||
COEX<vtype>(vecs[22], vecs[25]);
|
||||
COEX<vtype>(vecs[23], vecs[30]);
|
||||
COEX<vtype>(vecs[27], vecs[29]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[2]);
|
||||
COEX<vtype>(vecs[3], vecs[5]);
|
||||
COEX<vtype>(vecs[4], vecs[8]);
|
||||
COEX<vtype>(vecs[6], vecs[22]);
|
||||
COEX<vtype>(vecs[7], vecs[11]);
|
||||
COEX<vtype>(vecs[9], vecs[25]);
|
||||
COEX<vtype>(vecs[10], vecs[12]);
|
||||
COEX<vtype>(vecs[13], vecs[14]);
|
||||
COEX<vtype>(vecs[17], vecs[18]);
|
||||
COEX<vtype>(vecs[19], vecs[21]);
|
||||
COEX<vtype>(vecs[20], vecs[24]);
|
||||
COEX<vtype>(vecs[23], vecs[27]);
|
||||
COEX<vtype>(vecs[26], vecs[28]);
|
||||
COEX<vtype>(vecs[29], vecs[30]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[17]);
|
||||
COEX<vtype>(vecs[2], vecs[18]);
|
||||
COEX<vtype>(vecs[3], vecs[19]);
|
||||
COEX<vtype>(vecs[4], vecs[20]);
|
||||
COEX<vtype>(vecs[5], vecs[10]);
|
||||
COEX<vtype>(vecs[7], vecs[23]);
|
||||
COEX<vtype>(vecs[8], vecs[24]);
|
||||
COEX<vtype>(vecs[11], vecs[27]);
|
||||
COEX<vtype>(vecs[12], vecs[28]);
|
||||
COEX<vtype>(vecs[13], vecs[29]);
|
||||
COEX<vtype>(vecs[14], vecs[30]);
|
||||
COEX<vtype>(vecs[21], vecs[26]);
|
||||
|
||||
COEX<vtype>(vecs[3], vecs[17]);
|
||||
COEX<vtype>(vecs[4], vecs[16]);
|
||||
COEX<vtype>(vecs[5], vecs[21]);
|
||||
COEX<vtype>(vecs[6], vecs[18]);
|
||||
COEX<vtype>(vecs[7], vecs[9]);
|
||||
COEX<vtype>(vecs[8], vecs[20]);
|
||||
COEX<vtype>(vecs[10], vecs[26]);
|
||||
COEX<vtype>(vecs[11], vecs[23]);
|
||||
COEX<vtype>(vecs[13], vecs[25]);
|
||||
COEX<vtype>(vecs[14], vecs[28]);
|
||||
COEX<vtype>(vecs[15], vecs[27]);
|
||||
COEX<vtype>(vecs[22], vecs[24]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[4]);
|
||||
COEX<vtype>(vecs[3], vecs[8]);
|
||||
COEX<vtype>(vecs[5], vecs[16]);
|
||||
COEX<vtype>(vecs[7], vecs[17]);
|
||||
COEX<vtype>(vecs[9], vecs[21]);
|
||||
COEX<vtype>(vecs[10], vecs[22]);
|
||||
COEX<vtype>(vecs[11], vecs[19]);
|
||||
COEX<vtype>(vecs[12], vecs[20]);
|
||||
COEX<vtype>(vecs[14], vecs[24]);
|
||||
COEX<vtype>(vecs[15], vecs[26]);
|
||||
COEX<vtype>(vecs[23], vecs[28]);
|
||||
COEX<vtype>(vecs[27], vecs[30]);
|
||||
|
||||
COEX<vtype>(vecs[2], vecs[5]);
|
||||
COEX<vtype>(vecs[7], vecs[8]);
|
||||
COEX<vtype>(vecs[9], vecs[18]);
|
||||
COEX<vtype>(vecs[11], vecs[17]);
|
||||
COEX<vtype>(vecs[12], vecs[16]);
|
||||
COEX<vtype>(vecs[13], vecs[22]);
|
||||
COEX<vtype>(vecs[14], vecs[20]);
|
||||
COEX<vtype>(vecs[15], vecs[19]);
|
||||
COEX<vtype>(vecs[23], vecs[24]);
|
||||
COEX<vtype>(vecs[26], vecs[29]);
|
||||
|
||||
COEX<vtype>(vecs[2], vecs[4]);
|
||||
COEX<vtype>(vecs[6], vecs[12]);
|
||||
COEX<vtype>(vecs[9], vecs[16]);
|
||||
COEX<vtype>(vecs[10], vecs[11]);
|
||||
COEX<vtype>(vecs[13], vecs[17]);
|
||||
COEX<vtype>(vecs[14], vecs[18]);
|
||||
COEX<vtype>(vecs[15], vecs[22]);
|
||||
COEX<vtype>(vecs[19], vecs[25]);
|
||||
COEX<vtype>(vecs[20], vecs[21]);
|
||||
COEX<vtype>(vecs[27], vecs[29]);
|
||||
|
||||
COEX<vtype>(vecs[5], vecs[6]);
|
||||
COEX<vtype>(vecs[8], vecs[12]);
|
||||
COEX<vtype>(vecs[9], vecs[10]);
|
||||
COEX<vtype>(vecs[11], vecs[13]);
|
||||
COEX<vtype>(vecs[14], vecs[16]);
|
||||
COEX<vtype>(vecs[15], vecs[17]);
|
||||
COEX<vtype>(vecs[18], vecs[20]);
|
||||
COEX<vtype>(vecs[19], vecs[23]);
|
||||
COEX<vtype>(vecs[21], vecs[22]);
|
||||
COEX<vtype>(vecs[25], vecs[26]);
|
||||
|
||||
COEX<vtype>(vecs[3], vecs[5]);
|
||||
COEX<vtype>(vecs[6], vecs[7]);
|
||||
COEX<vtype>(vecs[8], vecs[9]);
|
||||
COEX<vtype>(vecs[10], vecs[12]);
|
||||
COEX<vtype>(vecs[11], vecs[14]);
|
||||
COEX<vtype>(vecs[13], vecs[16]);
|
||||
COEX<vtype>(vecs[15], vecs[18]);
|
||||
COEX<vtype>(vecs[17], vecs[20]);
|
||||
COEX<vtype>(vecs[19], vecs[21]);
|
||||
COEX<vtype>(vecs[22], vecs[23]);
|
||||
COEX<vtype>(vecs[24], vecs[25]);
|
||||
COEX<vtype>(vecs[26], vecs[28]);
|
||||
|
||||
COEX<vtype>(vecs[3], vecs[4]);
|
||||
COEX<vtype>(vecs[5], vecs[6]);
|
||||
COEX<vtype>(vecs[7], vecs[8]);
|
||||
COEX<vtype>(vecs[9], vecs[10]);
|
||||
COEX<vtype>(vecs[11], vecs[12]);
|
||||
COEX<vtype>(vecs[13], vecs[14]);
|
||||
COEX<vtype>(vecs[15], vecs[16]);
|
||||
COEX<vtype>(vecs[17], vecs[18]);
|
||||
COEX<vtype>(vecs[19], vecs[20]);
|
||||
COEX<vtype>(vecs[21], vecs[22]);
|
||||
COEX<vtype>(vecs[23], vecs[24]);
|
||||
COEX<vtype>(vecs[25], vecs[26]);
|
||||
COEX<vtype>(vecs[27], vecs[28]);
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2023, Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2021 Serge Sans Paille. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This implementation is based on x86-simd-sort(https://github.com/intel/x86-simd-sort)
|
||||
|
||||
template <typename vtype, typename mm_t>
|
||||
X86_SIMD_SORT_INLINE void COEX(mm_t &a, mm_t &b);
|
||||
|
||||
template <typename vtype, typename type_t>
|
||||
X86_SIMD_SORT_INLINE type_t get_pivot(type_t *arr, const arrsize_t left,
|
||||
const arrsize_t right) {
|
||||
using reg_t = typename vtype::reg_t;
|
||||
type_t samples[vtype::numlanes];
|
||||
arrsize_t delta = (right - left) / vtype::numlanes;
|
||||
for (int i = 0; i < vtype::numlanes; i++) {
|
||||
samples[i] = arr[left + i * delta];
|
||||
}
|
||||
reg_t rand_vec = vtype::loadu(samples);
|
||||
reg_t sort = vtype::sort_vec(rand_vec);
|
||||
|
||||
return ((type_t *)&sort)[vtype::numlanes / 2];
|
||||
}
|
||||
|
||||
template <typename vtype, typename type_t>
|
||||
X86_SIMD_SORT_INLINE type_t get_pivot_blocks(type_t *arr, const arrsize_t left,
|
||||
const arrsize_t right) {
|
||||
if (right - left <= 1024) {
|
||||
return get_pivot<vtype>(arr, left, right);
|
||||
}
|
||||
|
||||
using reg_t = typename vtype::reg_t;
|
||||
constexpr int numVecs = 5;
|
||||
|
||||
arrsize_t width = (right - vtype::numlanes) - left;
|
||||
arrsize_t delta = width / numVecs;
|
||||
|
||||
reg_t vecs[numVecs];
|
||||
// Load data
|
||||
for (int i = 0; i < numVecs; i++) {
|
||||
vecs[i] = vtype::loadu(arr + left + delta * i);
|
||||
}
|
||||
|
||||
// Implement sorting network (from
|
||||
// https://bertdobbelaere.github.io/sorting_networks.html)
|
||||
COEX<vtype>(vecs[0], vecs[3]);
|
||||
COEX<vtype>(vecs[1], vecs[4]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[2]);
|
||||
COEX<vtype>(vecs[1], vecs[3]);
|
||||
|
||||
COEX<vtype>(vecs[0], vecs[1]);
|
||||
COEX<vtype>(vecs[2], vecs[4]);
|
||||
|
||||
COEX<vtype>(vecs[1], vecs[2]);
|
||||
COEX<vtype>(vecs[3], vecs[4]);
|
||||
|
||||
COEX<vtype>(vecs[2], vecs[3]);
|
||||
|
||||
// Calculate median of the middle vector
|
||||
reg_t &vec = vecs[numVecs / 2];
|
||||
vec = vtype::sort_vec(vec);
|
||||
|
||||
type_t data[vtype::numlanes];
|
||||
vtype::storeu(data, vec);
|
||||
return data[vtype::numlanes / 2];
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2024, 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 apple.security;
|
||||
|
||||
import java.security.*;
|
||||
import static sun.security.util.SecurityConstants.PROVIDER_VER;
|
||||
|
||||
/*
|
||||
* The Apple Security Provider.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the Apple provider.
|
||||
*
|
||||
* This provider only exists to provide access to the Apple keychain-based KeyStore implementation
|
||||
*/
|
||||
@SuppressWarnings("serial") // JDK implementation class
|
||||
public final class AppleProvider extends Provider {
|
||||
|
||||
private static final String info = "Apple Provider";
|
||||
|
||||
private static final class ProviderService extends Provider.Service {
|
||||
ProviderService(Provider p, String type, String algo, String cn) {
|
||||
super(p, type, algo, cn, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object newInstance(Object ctrParamObj)
|
||||
throws NoSuchAlgorithmException {
|
||||
String type = getType();
|
||||
if (ctrParamObj != null) {
|
||||
throw new InvalidParameterException
|
||||
("constructorParameter not used with " + type + " engines");
|
||||
}
|
||||
|
||||
String algo = getAlgorithm();
|
||||
try {
|
||||
if (type.equals("KeyStore")) {
|
||||
if (algo.equals("KeychainStore")) {
|
||||
return new KeychainStore.USER();
|
||||
} else if (algo.equals("KeychainStore-ROOT")) {
|
||||
return new KeychainStore.ROOT();
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NoSuchAlgorithmException("Error constructing " +
|
||||
type + " for " + algo + " using Apple", ex);
|
||||
}
|
||||
throw new ProviderException("No impl for " + algo +
|
||||
" " + type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AppleProvider() {
|
||||
/* We are the Apple provider */
|
||||
super("Apple", PROVIDER_VER, info);
|
||||
|
||||
final Provider p = this;
|
||||
putService(new ProviderService(p, "KeyStore",
|
||||
"KeychainStore", "apple.security.KeychainStore$USER"));
|
||||
putService(new ProviderService(p, "KeyStore",
|
||||
"KeychainStore-ROOT", "apple.security.KeychainStore$ROOT"));
|
||||
}
|
||||
}
|
||||
1291
src/java.base/macosx/classes/apple/security/KeychainStore.java
Normal file
1291
src/java.base/macosx/classes/apple/security/KeychainStore.java
Normal file
File diff suppressed because it is too large
Load diff
155
src/java.base/macosx/classes/java/net/DefaultInterface.java
Normal file
155
src/java.base/macosx/classes/java/net/DefaultInterface.java
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2024, 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 java.net;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Choose a network interface to be the default for
|
||||
* outgoing IPv6 traffic that does not specify a scope_id (and which needs one).
|
||||
* We choose the first interface that is up and is (in order of preference):
|
||||
* 1. neither loopback nor point to point
|
||||
* 2. point to point
|
||||
* 3. loopback
|
||||
* 4. none.
|
||||
* Platforms that do not require a default interface implement a dummy
|
||||
* that returns null.
|
||||
*/
|
||||
|
||||
class DefaultInterface {
|
||||
|
||||
private static final NetworkInterface defaultInterface =
|
||||
chooseDefaultInterface();
|
||||
|
||||
static NetworkInterface getDefault() {
|
||||
return defaultInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose a default interface. This method returns the first interface that
|
||||
* is both "up" and supports multicast. This method chooses an interface in
|
||||
* order of preference, using the following algorithm:
|
||||
*
|
||||
* <pre>
|
||||
* Interfaces that are down, or don't support multicasting, are skipped.
|
||||
* In steps 1-4 below, PPP and loopback interfaces are skipped.
|
||||
*
|
||||
* 1. The first interface that has at least an IPv4 address, and an IPv6 address,
|
||||
* and a non link-local IP address, is picked.
|
||||
*
|
||||
* 2. If none is found, then the first interface that has at least an
|
||||
* IPv4 address, and an IPv6 address is picked.
|
||||
*
|
||||
* 3. If none is found, then the first interface that has at least a
|
||||
* non link local IP address is picked.
|
||||
*
|
||||
* 4. If none is found, then the first non loopback and non PPP interface
|
||||
* is picked.
|
||||
*
|
||||
* 5. If none is found then first PPP interface is picked.
|
||||
*
|
||||
* 6. If none is found, then the first loopback interface is picked.
|
||||
*
|
||||
* 7. If none is found, then null is returned.
|
||||
* </pre>
|
||||
*
|
||||
* @return the chosen interface or {@code null} if there isn't a suitable
|
||||
* default
|
||||
*/
|
||||
private static NetworkInterface chooseDefaultInterface() {
|
||||
Enumeration<NetworkInterface> nifs;
|
||||
|
||||
try {
|
||||
nifs = NetworkInterface.getNetworkInterfaces();
|
||||
} catch (IOException ignore) {
|
||||
// unable to enumerate network interfaces
|
||||
return null;
|
||||
}
|
||||
|
||||
NetworkInterface preferred = null;
|
||||
NetworkInterface dual = null;
|
||||
NetworkInterface nonLinkLocal = null;
|
||||
NetworkInterface ppp = null;
|
||||
NetworkInterface loopback = null;
|
||||
|
||||
while (nifs.hasMoreElements()) {
|
||||
NetworkInterface ni = nifs.nextElement();
|
||||
try {
|
||||
if (!ni.isUp() || !ni.supportsMulticast())
|
||||
continue;
|
||||
|
||||
boolean ip4 = false, ip6 = false, isNonLinkLocal = false;
|
||||
Enumeration<InetAddress> addrs = ni.getInetAddresses();
|
||||
while (addrs.hasMoreElements()) {
|
||||
InetAddress addr = addrs.nextElement();
|
||||
if (!addr.isAnyLocalAddress()) {
|
||||
if (addr instanceof Inet4Address) {
|
||||
ip4 = true;
|
||||
} else if (addr instanceof Inet6Address) {
|
||||
ip6 = true;
|
||||
}
|
||||
if (!addr.isLinkLocalAddress()) {
|
||||
isNonLinkLocal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isLoopback = ni.isLoopback();
|
||||
boolean isPPP = ni.isPointToPoint();
|
||||
if (!isLoopback && !isPPP) {
|
||||
// found an interface that is not the loopback or a
|
||||
// point-to-point interface
|
||||
if (preferred == null) {
|
||||
preferred = ni;
|
||||
}
|
||||
if (ip4 && ip6) {
|
||||
if (isNonLinkLocal) return ni;
|
||||
if (dual == null) dual = ni;
|
||||
}
|
||||
if (nonLinkLocal == null) {
|
||||
if (isNonLinkLocal) nonLinkLocal = ni;
|
||||
}
|
||||
}
|
||||
if (ppp == null && isPPP)
|
||||
ppp = ni;
|
||||
if (loopback == null && isLoopback)
|
||||
loopback = ni;
|
||||
|
||||
} catch (IOException skip) { }
|
||||
}
|
||||
|
||||
if (dual != null) {
|
||||
return dual;
|
||||
} else if (nonLinkLocal != null) {
|
||||
return nonLinkLocal;
|
||||
} else if (preferred != null) {
|
||||
return preferred;
|
||||
} else {
|
||||
return (ppp != null) ? ppp : loopback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.errno;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.lang.invoke.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
import static java.lang.foreign.ValueLayout.*;
|
||||
|
||||
@SuppressWarnings("restricted")
|
||||
public class errno_h$shared {
|
||||
|
||||
errno_h$shared() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
public static final OfBoolean C_BOOL = (OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool");
|
||||
public static final OfByte C_CHAR =(OfByte)Linker.nativeLinker().canonicalLayouts().get("char");
|
||||
public static final OfShort C_SHORT = (OfShort) Linker.nativeLinker().canonicalLayouts().get("short");
|
||||
public static final OfInt C_INT = (OfInt) Linker.nativeLinker().canonicalLayouts().get("int");
|
||||
public static final OfLong C_LONG_LONG = (OfLong) Linker.nativeLinker().canonicalLayouts().get("long long");
|
||||
public static final OfFloat C_FLOAT = (OfFloat) Linker.nativeLinker().canonicalLayouts().get("float");
|
||||
public static final OfDouble C_DOUBLE = (OfDouble) Linker.nativeLinker().canonicalLayouts().get("double");
|
||||
public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*"))
|
||||
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, C_CHAR));
|
||||
public static final OfLong C_LONG = (OfLong) Linker.nativeLinker().canonicalLayouts().get("long");
|
||||
|
||||
static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls");
|
||||
|
||||
static void traceDowncall(String name, Object... args) {
|
||||
String traceArgs = Arrays.stream(args)
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining(", "));
|
||||
System.out.printf("%s(%s)\n", name, traceArgs);
|
||||
}
|
||||
|
||||
static MethodHandle upcallHandle(Class<?> fi, String name, FunctionDescriptor fdesc) {
|
||||
try {
|
||||
return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType());
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static MemoryLayout align(MemoryLayout layout, long align) {
|
||||
return switch (layout) {
|
||||
case PaddingLayout p -> p;
|
||||
case ValueLayout v -> v.withByteAlignment(align);
|
||||
case GroupLayout g -> {
|
||||
MemoryLayout[] alignedMembers = g.memberLayouts().stream()
|
||||
.map(m -> align(m, align)).toArray(MemoryLayout[]::new);
|
||||
yield g instanceof StructLayout ?
|
||||
MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers);
|
||||
}
|
||||
case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.errno;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.lang.invoke.*;
|
||||
|
||||
@SuppressWarnings("restricted")
|
||||
public class errno_h extends errno_h$shared {
|
||||
|
||||
errno_h() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
static final Arena LIBRARY_ARENA = Arena.ofAuto();
|
||||
|
||||
static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup()
|
||||
.or(Linker.nativeLinker().defaultLookup());
|
||||
|
||||
private static final int EINTR = (int)4L;
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* #define EINTR 4
|
||||
* }
|
||||
*/
|
||||
public static int EINTR() {
|
||||
return EINTR;
|
||||
}
|
||||
|
||||
private static class strerror_r {
|
||||
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
|
||||
C_INT,
|
||||
C_INT,
|
||||
C_POINTER,
|
||||
C_LONG
|
||||
);
|
||||
|
||||
public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("strerror_r");
|
||||
|
||||
public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function descriptor for:
|
||||
* {@snippet lang=c :
|
||||
* int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen)
|
||||
* }
|
||||
*/
|
||||
public static FunctionDescriptor strerror_r$descriptor() {
|
||||
return strerror_r.DESC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downcall method handle for:
|
||||
* {@snippet lang=c :
|
||||
* int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen)
|
||||
* }
|
||||
*/
|
||||
public static MethodHandle strerror_r$handle() {
|
||||
return strerror_r.HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address for:
|
||||
* {@snippet lang=c :
|
||||
* int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen)
|
||||
* }
|
||||
*/
|
||||
public static MemorySegment strerror_r$address() {
|
||||
return strerror_r.ADDR;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen)
|
||||
* }
|
||||
*/
|
||||
public static int strerror_r(int __errnum, MemorySegment __strerrbuf, long __buflen) {
|
||||
var mh$ = strerror_r.HANDLE;
|
||||
try {
|
||||
if (TRACE_DOWNCALLS) {
|
||||
traceDowncall("strerror_r", __errnum, __strerrbuf, __buflen);
|
||||
}
|
||||
return (int)mh$.invokeExact(__errnum, __strerrbuf, __buflen);
|
||||
} catch (Error | RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex$) {
|
||||
throw new AssertionError("should not reach here", ex$);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines native structures for errno APIs.
|
||||
* Generated with the following jextract command:
|
||||
* {@snippet lang = "Shell Script":
|
||||
*
|
||||
* HEADER_NAME=errno.h
|
||||
* echo "#include <errno.h>" > $HEADER_NAME
|
||||
* echo "#include <string.h>" >> $HEADER_NAME
|
||||
*
|
||||
* jextract --target-package jdk.internal.ffi.generated.errno \
|
||||
* --include-constant EINTR \
|
||||
* --include-function strerror_r \
|
||||
* $HEADER_NAME
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
package jdk.internal.ffi.generated.errno;
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.kqueue;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.util.function.*;
|
||||
|
||||
import static java.lang.foreign.MemoryLayout.PathElement.*;
|
||||
import static java.lang.foreign.ValueLayout.*;
|
||||
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* struct kevent {
|
||||
* uintptr_t ident;
|
||||
* int16_t filter;
|
||||
* uint16_t flags;
|
||||
* uint32_t fflags;
|
||||
* intptr_t data;
|
||||
* void *udata;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@SuppressWarnings("restricted")
|
||||
public class kevent {
|
||||
|
||||
kevent() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
private static final GroupLayout $LAYOUT = MemoryLayout.structLayout(
|
||||
kqueue_h.align(kqueue_h.C_LONG, 4).withName("ident"),
|
||||
kqueue_h.C_SHORT.withName("filter"),
|
||||
kqueue_h.C_SHORT.withName("flags"),
|
||||
kqueue_h.C_INT.withName("fflags"),
|
||||
kqueue_h.align(kqueue_h.C_LONG, 4).withName("data"),
|
||||
kqueue_h.align(kqueue_h.C_POINTER, 4).withName("udata")
|
||||
).withName("kevent");
|
||||
|
||||
/**
|
||||
* The layout of this struct
|
||||
*/
|
||||
public static final GroupLayout layout() {
|
||||
return $LAYOUT;
|
||||
}
|
||||
|
||||
private static final OfLong ident$LAYOUT = (OfLong)$LAYOUT.select(groupElement("ident"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* uintptr_t ident
|
||||
* }
|
||||
*/
|
||||
public static final OfLong ident$layout() {
|
||||
return ident$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long ident$OFFSET = $LAYOUT.byteOffset(groupElement("ident"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* uintptr_t ident
|
||||
* }
|
||||
*/
|
||||
public static final long ident$offset() {
|
||||
return ident$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* uintptr_t ident
|
||||
* }
|
||||
*/
|
||||
public static long ident(MemorySegment struct) {
|
||||
return struct.get(ident$LAYOUT, ident$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* uintptr_t ident
|
||||
* }
|
||||
*/
|
||||
public static void ident(MemorySegment struct, long fieldValue) {
|
||||
struct.set(ident$LAYOUT, ident$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
private static final OfShort filter$LAYOUT = (OfShort)$LAYOUT.select(groupElement("filter"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* int16_t filter
|
||||
* }
|
||||
*/
|
||||
public static final OfShort filter$layout() {
|
||||
return filter$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long filter$OFFSET = $LAYOUT.byteOffset(groupElement("filter"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* int16_t filter
|
||||
* }
|
||||
*/
|
||||
public static final long filter$offset() {
|
||||
return filter$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* int16_t filter
|
||||
* }
|
||||
*/
|
||||
public static short filter(MemorySegment struct) {
|
||||
return struct.get(filter$LAYOUT, filter$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* int16_t filter
|
||||
* }
|
||||
*/
|
||||
public static void filter(MemorySegment struct, short fieldValue) {
|
||||
struct.set(filter$LAYOUT, filter$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
private static final OfShort flags$LAYOUT = (OfShort)$LAYOUT.select(groupElement("flags"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* uint16_t flags
|
||||
* }
|
||||
*/
|
||||
public static final OfShort flags$layout() {
|
||||
return flags$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long flags$OFFSET = $LAYOUT.byteOffset(groupElement("flags"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* uint16_t flags
|
||||
* }
|
||||
*/
|
||||
public static final long flags$offset() {
|
||||
return flags$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* uint16_t flags
|
||||
* }
|
||||
*/
|
||||
public static short flags(MemorySegment struct) {
|
||||
return struct.get(flags$LAYOUT, flags$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* uint16_t flags
|
||||
* }
|
||||
*/
|
||||
public static void flags(MemorySegment struct, short fieldValue) {
|
||||
struct.set(flags$LAYOUT, flags$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
private static final OfInt fflags$LAYOUT = (OfInt)$LAYOUT.select(groupElement("fflags"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* uint32_t fflags
|
||||
* }
|
||||
*/
|
||||
public static final OfInt fflags$layout() {
|
||||
return fflags$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long fflags$OFFSET = $LAYOUT.byteOffset(groupElement("fflags"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* uint32_t fflags
|
||||
* }
|
||||
*/
|
||||
public static final long fflags$offset() {
|
||||
return fflags$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* uint32_t fflags
|
||||
* }
|
||||
*/
|
||||
public static int fflags(MemorySegment struct) {
|
||||
return struct.get(fflags$LAYOUT, fflags$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* uint32_t fflags
|
||||
* }
|
||||
*/
|
||||
public static void fflags(MemorySegment struct, int fieldValue) {
|
||||
struct.set(fflags$LAYOUT, fflags$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
private static final OfLong data$LAYOUT = (OfLong)$LAYOUT.select(groupElement("data"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* intptr_t data
|
||||
* }
|
||||
*/
|
||||
public static final OfLong data$layout() {
|
||||
return data$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long data$OFFSET = $LAYOUT.byteOffset(groupElement("data"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* intptr_t data
|
||||
* }
|
||||
*/
|
||||
public static final long data$offset() {
|
||||
return data$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* intptr_t data
|
||||
* }
|
||||
*/
|
||||
public static long data(MemorySegment struct) {
|
||||
return struct.get(data$LAYOUT, data$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* intptr_t data
|
||||
* }
|
||||
*/
|
||||
public static void data(MemorySegment struct, long fieldValue) {
|
||||
struct.set(data$LAYOUT, data$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
private static final AddressLayout udata$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("udata"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* void *udata
|
||||
* }
|
||||
*/
|
||||
public static final AddressLayout udata$layout() {
|
||||
return udata$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long udata$OFFSET = $LAYOUT.byteOffset(groupElement("udata"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* void *udata
|
||||
* }
|
||||
*/
|
||||
public static final long udata$offset() {
|
||||
return udata$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* void *udata
|
||||
* }
|
||||
*/
|
||||
public static MemorySegment udata(MemorySegment struct) {
|
||||
return struct.get(udata$LAYOUT, udata$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* void *udata
|
||||
* }
|
||||
*/
|
||||
public static void udata(MemorySegment struct, MemorySegment fieldValue) {
|
||||
struct.set(udata$LAYOUT, udata$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a slice of {@code arrayParam} which selects the array element at {@code index}.
|
||||
* The returned segment has address {@code arrayParam.address() + index * layout().byteSize()}
|
||||
*/
|
||||
public static MemorySegment asSlice(MemorySegment array, long index) {
|
||||
return array.asSlice(layout().byteSize() * index);
|
||||
}
|
||||
|
||||
/**
|
||||
* The size (in bytes) of this struct
|
||||
*/
|
||||
public static long sizeof() { return layout().byteSize(); }
|
||||
|
||||
/**
|
||||
* Allocate a segment of size {@code layout().byteSize()} using {@code allocator}
|
||||
*/
|
||||
public static MemorySegment allocate(SegmentAllocator allocator) {
|
||||
return allocator.allocate(layout());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an array of size {@code elementCount} using {@code allocator}.
|
||||
* The returned segment has size {@code elementCount * layout().byteSize()}.
|
||||
*/
|
||||
public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) {
|
||||
return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any).
|
||||
* The returned segment has size {@code layout().byteSize()}
|
||||
*/
|
||||
public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer<MemorySegment> cleanup) {
|
||||
return reinterpret(addr, 1, arena, cleanup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any).
|
||||
* The returned segment has size {@code elementCount * layout().byteSize()}
|
||||
*/
|
||||
public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer<MemorySegment> cleanup) {
|
||||
return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.kqueue;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.lang.invoke.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
import static java.lang.foreign.ValueLayout.*;
|
||||
|
||||
@SuppressWarnings("restricted")
|
||||
public class kqueue_h$shared {
|
||||
|
||||
kqueue_h$shared() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
public static final OfBoolean C_BOOL = (OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool");
|
||||
public static final OfByte C_CHAR =(OfByte)Linker.nativeLinker().canonicalLayouts().get("char");
|
||||
public static final OfShort C_SHORT = (OfShort) Linker.nativeLinker().canonicalLayouts().get("short");
|
||||
public static final OfInt C_INT = (OfInt) Linker.nativeLinker().canonicalLayouts().get("int");
|
||||
public static final OfLong C_LONG_LONG = (OfLong) Linker.nativeLinker().canonicalLayouts().get("long long");
|
||||
public static final OfFloat C_FLOAT = (OfFloat) Linker.nativeLinker().canonicalLayouts().get("float");
|
||||
public static final OfDouble C_DOUBLE = (OfDouble) Linker.nativeLinker().canonicalLayouts().get("double");
|
||||
public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*"))
|
||||
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, C_CHAR));
|
||||
public static final OfLong C_LONG = (OfLong) Linker.nativeLinker().canonicalLayouts().get("long");
|
||||
|
||||
static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls");
|
||||
|
||||
static void traceDowncall(String name, Object... args) {
|
||||
String traceArgs = Arrays.stream(args)
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining(", "));
|
||||
System.out.printf("%s(%s)\n", name, traceArgs);
|
||||
}
|
||||
|
||||
static MethodHandle upcallHandle(Class<?> fi, String name, FunctionDescriptor fdesc) {
|
||||
try {
|
||||
return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType());
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static MemoryLayout align(MemoryLayout layout, long align) {
|
||||
return switch (layout) {
|
||||
case PaddingLayout p -> p;
|
||||
case ValueLayout v -> v.withByteAlignment(align);
|
||||
case GroupLayout g -> {
|
||||
MemoryLayout[] alignedMembers = g.memberLayouts().stream()
|
||||
.map(m -> align(m, align)).toArray(MemoryLayout[]::new);
|
||||
yield g instanceof StructLayout ?
|
||||
MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers);
|
||||
}
|
||||
case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.kqueue;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.lang.invoke.*;
|
||||
|
||||
@SuppressWarnings("restricted")
|
||||
public class kqueue_h extends kqueue_h$shared {
|
||||
|
||||
kqueue_h() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
static final Arena LIBRARY_ARENA = Arena.ofAuto();
|
||||
|
||||
static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup()
|
||||
.or(Linker.nativeLinker().defaultLookup());
|
||||
|
||||
private static final int EV_ADD = (int)1L;
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* #define EV_ADD 1
|
||||
* }
|
||||
*/
|
||||
public static int EV_ADD() {
|
||||
return EV_ADD;
|
||||
}
|
||||
private static final int EV_DELETE = (int)2L;
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* #define EV_DELETE 2
|
||||
* }
|
||||
*/
|
||||
public static int EV_DELETE() {
|
||||
return EV_DELETE;
|
||||
}
|
||||
private static final int EV_ONESHOT = (int)16L;
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* #define EV_ONESHOT 16
|
||||
* }
|
||||
*/
|
||||
public static int EV_ONESHOT() {
|
||||
return EV_ONESHOT;
|
||||
}
|
||||
private static final int EV_CLEAR = (int)32L;
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* #define EV_CLEAR 32
|
||||
* }
|
||||
*/
|
||||
public static int EV_CLEAR() {
|
||||
return EV_CLEAR;
|
||||
}
|
||||
|
||||
private static class kqueue {
|
||||
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
|
||||
kqueue_h.C_INT );
|
||||
|
||||
public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("kqueue");
|
||||
|
||||
public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function descriptor for:
|
||||
* {@snippet lang=c :
|
||||
* int kqueue()
|
||||
* }
|
||||
*/
|
||||
public static FunctionDescriptor kqueue$descriptor() {
|
||||
return kqueue.DESC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downcall method handle for:
|
||||
* {@snippet lang=c :
|
||||
* int kqueue()
|
||||
* }
|
||||
*/
|
||||
public static MethodHandle kqueue$handle() {
|
||||
return kqueue.HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address for:
|
||||
* {@snippet lang=c :
|
||||
* int kqueue()
|
||||
* }
|
||||
*/
|
||||
public static MemorySegment kqueue$address() {
|
||||
return kqueue.ADDR;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* int kqueue()
|
||||
* }
|
||||
*/
|
||||
public static int kqueue() {
|
||||
var mh$ = kqueue.HANDLE;
|
||||
try {
|
||||
if (TRACE_DOWNCALLS) {
|
||||
traceDowncall("kqueue");
|
||||
}
|
||||
return (int)mh$.invokeExact();
|
||||
} catch (Error | RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex$) {
|
||||
throw new AssertionError("should not reach here", ex$);
|
||||
}
|
||||
}
|
||||
|
||||
private static class kevent {
|
||||
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
|
||||
kqueue_h.C_INT,
|
||||
kqueue_h.C_INT,
|
||||
kqueue_h.C_POINTER,
|
||||
kqueue_h.C_INT,
|
||||
kqueue_h.C_POINTER,
|
||||
kqueue_h.C_INT,
|
||||
kqueue_h.C_POINTER
|
||||
);
|
||||
|
||||
public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("kevent");
|
||||
|
||||
public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function descriptor for:
|
||||
* {@snippet lang=c :
|
||||
* int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout)
|
||||
* }
|
||||
*/
|
||||
public static FunctionDescriptor kevent$descriptor() {
|
||||
return kevent.DESC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downcall method handle for:
|
||||
* {@snippet lang=c :
|
||||
* int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout)
|
||||
* }
|
||||
*/
|
||||
public static MethodHandle kevent$handle() {
|
||||
return kevent.HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address for:
|
||||
* {@snippet lang=c :
|
||||
* int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout)
|
||||
* }
|
||||
*/
|
||||
public static MemorySegment kevent$address() {
|
||||
return kevent.ADDR;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout)
|
||||
* }
|
||||
*/
|
||||
public static int kevent(int kq, MemorySegment changelist, int nchanges, MemorySegment eventlist, int nevents, MemorySegment timeout) {
|
||||
var mh$ = kevent.HANDLE;
|
||||
try {
|
||||
if (TRACE_DOWNCALLS) {
|
||||
traceDowncall("kevent", kq, changelist, nchanges, eventlist, nevents, timeout);
|
||||
}
|
||||
return (int)mh$.invokeExact(kq, changelist, nchanges, eventlist, nevents, timeout);
|
||||
} catch (Error | RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex$) {
|
||||
throw new AssertionError("should not reach here", ex$);
|
||||
}
|
||||
}
|
||||
private static final int EVFILT_READ = (int)-1L;
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* #define EVFILT_READ -1
|
||||
* }
|
||||
*/
|
||||
public static int EVFILT_READ() {
|
||||
return EVFILT_READ;
|
||||
}
|
||||
private static final int EVFILT_WRITE = (int)-2L;
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* #define EVFILT_WRITE -2
|
||||
* }
|
||||
*/
|
||||
public static int EVFILT_WRITE() {
|
||||
return EVFILT_WRITE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines native structures for Kqueue socket APIs.
|
||||
* Generated with the following jextract command:
|
||||
* {@snippet lang = "Shell Script":
|
||||
*
|
||||
* HEADER_NAME=kqueue.h
|
||||
* echo "#include <sys/types.h> " > $HEADER_NAME
|
||||
* echo "#include <sys/event.h>" >> $HEADER_NAME
|
||||
*
|
||||
*
|
||||
* jextract --target-package jdk.internal.ffi.generated.kqueue \
|
||||
* --include-constant EV_CLEAR \
|
||||
* --include-constant EV_ONESHOT \
|
||||
* --include-constant EV_DELETE \
|
||||
* --include-constant EV_ADD \
|
||||
* --include-constant EVFILT_WRITE \
|
||||
* --include-constant EVFILT_READ \
|
||||
* --include-function kevent \
|
||||
* --include-function kqueue \
|
||||
* --include-struct kevent \
|
||||
* $HEADER_NAME
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
package jdk.internal.ffi.generated.kqueue;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines native structures for timespec APIs.
|
||||
* Generated with the following jextract command:
|
||||
* {@snippet lang = "Shell Script":
|
||||
*
|
||||
* HEADER_NAME=timespec.h
|
||||
* echo "#include <time.h>" > $HEADER_NAME
|
||||
*
|
||||
* jextract --target-package jdk.internal.ffi.generated.timespec \
|
||||
* --include-struct timespec \
|
||||
* $HEADER_NAME
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
package jdk.internal.ffi.generated.timespec;
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.timespec;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.util.function.*;
|
||||
|
||||
import static java.lang.foreign.MemoryLayout.PathElement.*;
|
||||
import static java.lang.foreign.ValueLayout.*;
|
||||
|
||||
/**
|
||||
* {@snippet lang=c :
|
||||
* struct timespec {
|
||||
* __darwin_time_t tv_sec;
|
||||
* long tv_nsec;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@SuppressWarnings("restricted")
|
||||
public class timespec {
|
||||
|
||||
timespec() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
private static final GroupLayout $LAYOUT = MemoryLayout.structLayout(
|
||||
timespec_h.C_LONG.withName("tv_sec"),
|
||||
timespec_h.C_LONG.withName("tv_nsec")
|
||||
).withName("timespec");
|
||||
|
||||
/**
|
||||
* The layout of this struct
|
||||
*/
|
||||
public static final GroupLayout layout() {
|
||||
return $LAYOUT;
|
||||
}
|
||||
|
||||
private static final OfLong tv_sec$LAYOUT = (OfLong)$LAYOUT.select(groupElement("tv_sec"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* __darwin_time_t tv_sec
|
||||
* }
|
||||
*/
|
||||
public static final OfLong tv_sec$layout() {
|
||||
return tv_sec$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long tv_sec$OFFSET = $LAYOUT.byteOffset(groupElement("tv_sec"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* __darwin_time_t tv_sec
|
||||
* }
|
||||
*/
|
||||
public static final long tv_sec$offset() {
|
||||
return tv_sec$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* __darwin_time_t tv_sec
|
||||
* }
|
||||
*/
|
||||
public static long tv_sec(MemorySegment struct) {
|
||||
return struct.get(tv_sec$LAYOUT, tv_sec$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* __darwin_time_t tv_sec
|
||||
* }
|
||||
*/
|
||||
public static void tv_sec(MemorySegment struct, long fieldValue) {
|
||||
struct.set(tv_sec$LAYOUT, tv_sec$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
private static final OfLong tv_nsec$LAYOUT = (OfLong)$LAYOUT.select(groupElement("tv_nsec"));
|
||||
|
||||
/**
|
||||
* Layout for field:
|
||||
* {@snippet lang=c :
|
||||
* long tv_nsec
|
||||
* }
|
||||
*/
|
||||
public static final OfLong tv_nsec$layout() {
|
||||
return tv_nsec$LAYOUT;
|
||||
}
|
||||
|
||||
private static final long tv_nsec$OFFSET = $LAYOUT.byteOffset(groupElement("tv_nsec"));
|
||||
|
||||
/**
|
||||
* Offset for field:
|
||||
* {@snippet lang=c :
|
||||
* long tv_nsec
|
||||
* }
|
||||
*/
|
||||
public static final long tv_nsec$offset() {
|
||||
return tv_nsec$OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for field:
|
||||
* {@snippet lang=c :
|
||||
* long tv_nsec
|
||||
* }
|
||||
*/
|
||||
public static long tv_nsec(MemorySegment struct) {
|
||||
return struct.get(tv_nsec$LAYOUT, tv_nsec$OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for field:
|
||||
* {@snippet lang=c :
|
||||
* long tv_nsec
|
||||
* }
|
||||
*/
|
||||
public static void tv_nsec(MemorySegment struct, long fieldValue) {
|
||||
struct.set(tv_nsec$LAYOUT, tv_nsec$OFFSET, fieldValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a slice of {@code arrayParam} which selects the array element at {@code index}.
|
||||
* The returned segment has address {@code arrayParam.address() + index * layout().byteSize()}
|
||||
*/
|
||||
public static MemorySegment asSlice(MemorySegment array, long index) {
|
||||
return array.asSlice(layout().byteSize() * index);
|
||||
}
|
||||
|
||||
/**
|
||||
* The size (in bytes) of this struct
|
||||
*/
|
||||
public static long sizeof() { return layout().byteSize(); }
|
||||
|
||||
/**
|
||||
* Allocate a segment of size {@code layout().byteSize()} using {@code allocator}
|
||||
*/
|
||||
public static MemorySegment allocate(SegmentAllocator allocator) {
|
||||
return allocator.allocate(layout());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an array of size {@code elementCount} using {@code allocator}.
|
||||
* The returned segment has size {@code elementCount * layout().byteSize()}.
|
||||
*/
|
||||
public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) {
|
||||
return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any).
|
||||
* The returned segment has size {@code layout().byteSize()}
|
||||
*/
|
||||
public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer<MemorySegment> cleanup) {
|
||||
return reinterpret(addr, 1, arena, cleanup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any).
|
||||
* The returned segment has size {@code elementCount * layout().byteSize()}
|
||||
*/
|
||||
public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer<MemorySegment> cleanup) {
|
||||
return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.timespec;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.lang.invoke.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
import static java.lang.foreign.ValueLayout.*;
|
||||
|
||||
@SuppressWarnings("restricted")
|
||||
public class timespec_h$shared {
|
||||
|
||||
timespec_h$shared() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
public static final OfBoolean C_BOOL = (OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool");
|
||||
public static final OfByte C_CHAR =(OfByte)Linker.nativeLinker().canonicalLayouts().get("char");
|
||||
public static final OfShort C_SHORT = (OfShort) Linker.nativeLinker().canonicalLayouts().get("short");
|
||||
public static final OfInt C_INT = (OfInt) Linker.nativeLinker().canonicalLayouts().get("int");
|
||||
public static final OfLong C_LONG_LONG = (OfLong) Linker.nativeLinker().canonicalLayouts().get("long long");
|
||||
public static final OfFloat C_FLOAT = (OfFloat) Linker.nativeLinker().canonicalLayouts().get("float");
|
||||
public static final OfDouble C_DOUBLE = (OfDouble) Linker.nativeLinker().canonicalLayouts().get("double");
|
||||
public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*"))
|
||||
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, C_CHAR));
|
||||
public static final OfLong C_LONG = (OfLong) Linker.nativeLinker().canonicalLayouts().get("long");
|
||||
|
||||
static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls");
|
||||
|
||||
static void traceDowncall(String name, Object... args) {
|
||||
String traceArgs = Arrays.stream(args)
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining(", "));
|
||||
System.out.printf("%s(%s)\n", name, traceArgs);
|
||||
}
|
||||
|
||||
static MethodHandle upcallHandle(Class<?> fi, String name, FunctionDescriptor fdesc) {
|
||||
try {
|
||||
return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType());
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static MemoryLayout align(MemoryLayout layout, long align) {
|
||||
return switch (layout) {
|
||||
case PaddingLayout p -> p;
|
||||
case ValueLayout v -> v.withByteAlignment(align);
|
||||
case GroupLayout g -> {
|
||||
MemoryLayout[] alignedMembers = g.memberLayouts().stream()
|
||||
.map(m -> align(m, align)).toArray(MemoryLayout[]::new);
|
||||
yield g instanceof StructLayout ?
|
||||
MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers);
|
||||
}
|
||||
case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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.
|
||||
*/
|
||||
|
||||
// Generated by jextract
|
||||
|
||||
package jdk.internal.ffi.generated.timespec;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
|
||||
public class timespec_h extends timespec_h$shared {
|
||||
|
||||
timespec_h() {
|
||||
// Should not be called directly
|
||||
}
|
||||
|
||||
static final Arena LIBRARY_ARENA = Arena.ofAuto();
|
||||
|
||||
static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup()
|
||||
.or(Linker.nativeLinker().defaultLookup());
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2023, 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 jdk.internal.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jdk.internal.util.OSVersion;
|
||||
|
||||
class ClassLoaderHelper {
|
||||
|
||||
// SDK 10.15 and earlier always reports 10.16 instead of 11.x.x
|
||||
private static final boolean hasDynamicLoaderCache = OSVersion.current()
|
||||
.compareTo(new OSVersion(10, 16)) >= 0;
|
||||
|
||||
private ClassLoaderHelper() {}
|
||||
|
||||
/**
|
||||
* Returns true if loading a native library only if
|
||||
* it's present on the file system.
|
||||
*
|
||||
* @implNote
|
||||
* On macOS 11.x or later which supports dynamic linker cache,
|
||||
* the dynamic library is not present on the filesystem. The
|
||||
* library cannot determine if a dynamic library exists on a
|
||||
* given path or not and so this method returns false.
|
||||
*/
|
||||
static boolean loadLibraryOnlyIfPresent() {
|
||||
return !hasDynamicLoaderCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an alternate path name for the given file
|
||||
* such that if the original pathname did not exist, then the
|
||||
* file may be located at the alternate location.
|
||||
* For mac, this replaces the final .dylib suffix with .jnilib
|
||||
*/
|
||||
static File mapAlternativeName(File lib) {
|
||||
String name = lib.toString();
|
||||
int index = name.lastIndexOf('.');
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
return new File(name.substring(0, index) + ".jnilib");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a PATH env variable.
|
||||
*
|
||||
* Empty elements will be replaced by dot.
|
||||
*/
|
||||
static String[] parsePath(String ldPath) {
|
||||
char ps = File.pathSeparatorChar;
|
||||
ArrayList<String> paths = new ArrayList<>();
|
||||
int pathStart = 0;
|
||||
int pathEnd;
|
||||
while ((pathEnd = ldPath.indexOf(ps, pathStart)) >= 0) {
|
||||
paths.add((pathStart < pathEnd) ?
|
||||
ldPath.substring(pathStart, pathEnd) : ".");
|
||||
pathStart = pathEnd + 1;
|
||||
}
|
||||
int ldLen = ldPath.length();
|
||||
paths.add((pathStart < ldLen) ?
|
||||
ldPath.substring(pathStart, ldLen) : ".");
|
||||
return paths.toArray(new String[paths.size()]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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.nio.channels.*;
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BsdAsynchronousChannelProvider
|
||||
extends AsynchronousChannelProvider
|
||||
{
|
||||
private static volatile KQueuePort defaultPort;
|
||||
|
||||
private KQueuePort defaultEventPort() throws IOException {
|
||||
if (defaultPort == null) {
|
||||
synchronized (BsdAsynchronousChannelProvider.class) {
|
||||
if (defaultPort == null) {
|
||||
defaultPort = new KQueuePort(this, ThreadPool.getDefault()).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
public BsdAsynchronousChannelProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
|
||||
throws IOException
|
||||
{
|
||||
return new KQueuePort(this, ThreadPool.create(nThreads, factory)).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
|
||||
throws IOException
|
||||
{
|
||||
return new KQueuePort(this, ThreadPool.wrap(executor, initialSize)).start();
|
||||
}
|
||||
|
||||
private Port toPort(AsynchronousChannelGroup group) throws IOException {
|
||||
if (group == null) {
|
||||
return defaultEventPort();
|
||||
} else {
|
||||
if (!(group instanceof KQueuePort))
|
||||
throw new IllegalChannelGroupException();
|
||||
return (Port)group;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousServerSocketChannelImpl(toPort(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new UnixAsynchronousSocketChannelImpl(toPort(group));
|
||||
}
|
||||
}
|
||||
|
|
@ -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 BsdAsynchronousChannelProvider();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2025, 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;
|
||||
|
||||
/**
|
||||
* Default PollerProvider for macOS.
|
||||
*/
|
||||
class DefaultPollerProvider extends PollerProvider {
|
||||
DefaultPollerProvider(Poller.Mode mode) {
|
||||
super(mode);
|
||||
}
|
||||
|
||||
DefaultPollerProvider() {
|
||||
this(Poller.Mode.SYSTEM_THREADS);
|
||||
}
|
||||
|
||||
@Override
|
||||
Poller readPoller(boolean subPoller) throws IOException {
|
||||
return new KQueuePoller(pollerMode(), subPoller, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
Poller writePoller(boolean subPoller) throws IOException {
|
||||
return new KQueuePoller(pollerMode(), subPoller, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2024, 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;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE = new KQueueSelectorProvider();
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2022, 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.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
class FileDispatcherImpl extends UnixFileDispatcherImpl {
|
||||
FileDispatcherImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
int force(FileDescriptor fd, boolean metaData) throws IOException {
|
||||
return force0(fd, metaData);
|
||||
}
|
||||
|
||||
boolean canTransferToFromOverlappedMap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
long transferTo(FileDescriptor src, long position, long count,
|
||||
FileDescriptor dst, boolean append) {
|
||||
return transferTo0(src, position, count, dst, append);
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
static native int force0(FileDescriptor fd, boolean metaData)
|
||||
throws IOException;
|
||||
|
||||
static native long transferTo0(FileDescriptor src, long position,
|
||||
long count, FileDescriptor dst,
|
||||
boolean append);
|
||||
}
|
||||
120
src/java.base/macosx/classes/sun/nio/ch/KQueue.java
Normal file
120
src/java.base/macosx/classes/sun/nio/ch/KQueue.java
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2022, 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 jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Provides access to the BSD kqueue facility.
|
||||
*/
|
||||
|
||||
class KQueue {
|
||||
private KQueue() { }
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
/**
|
||||
* struct kevent {
|
||||
* uintptr_t ident; // identifier for this event, usually the fd
|
||||
* int16_t filter; // filter for event
|
||||
* uint16_t flags; // general flags
|
||||
* uint32_t fflags; // filter-specific flags
|
||||
* intptr_t data; // filter-specific data
|
||||
* void *udata; // opaque user data identifier
|
||||
* };
|
||||
*/
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
private static final int SIZEOF_KQUEUEEVENT = keventSize();
|
||||
private static final int OFFSET_IDENT = identOffset();
|
||||
private static final int OFFSET_FILTER = filterOffset();
|
||||
private static final int OFFSET_FLAGS = flagsOffset();
|
||||
|
||||
// filters
|
||||
static final int EVFILT_READ = -1;
|
||||
static final int EVFILT_WRITE = -2;
|
||||
|
||||
// flags
|
||||
static final int EV_ADD = 0x0001;
|
||||
static final int EV_DELETE = 0x0002;
|
||||
static final int EV_ONESHOT = 0x0010;
|
||||
static final int EV_CLEAR = 0x0020;
|
||||
|
||||
/**
|
||||
* Allocates a poll array to handle up to {@code count} events.
|
||||
*/
|
||||
static long allocatePollArray(int count) {
|
||||
return unsafe.allocateMemory(count * SIZEOF_KQUEUEEVENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a poll array
|
||||
*/
|
||||
static void freePollArray(long address) {
|
||||
unsafe.freeMemory(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns kevent[i].
|
||||
*/
|
||||
static long getEvent(long address, int i) {
|
||||
return address + (SIZEOF_KQUEUEEVENT*i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file descriptor from a kevent (assuming it is in the ident field)
|
||||
*/
|
||||
static int getDescriptor(long address) {
|
||||
return unsafe.getInt(address + OFFSET_IDENT);
|
||||
}
|
||||
|
||||
static short getFilter(long address) {
|
||||
return unsafe.getShort(address + OFFSET_FILTER);
|
||||
}
|
||||
|
||||
static short getFlags(long address) {
|
||||
return unsafe.getShort(address + OFFSET_FLAGS);
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native int keventSize();
|
||||
|
||||
private static native int identOffset();
|
||||
|
||||
private static native int filterOffset();
|
||||
|
||||
private static native int flagsOffset();
|
||||
|
||||
static native int create() throws IOException;
|
||||
|
||||
static native int register(int kqfd, int fd, int filter, int flags);
|
||||
|
||||
static native int poll(int kqfd, long pollAddress, int nevents, long timeout)
|
||||
throws IOException;
|
||||
}
|
||||
158
src/java.base/macosx/classes/sun/nio/ch/KQueuePoller.java
Normal file
158
src/java.base/macosx/classes/sun/nio/ch/KQueuePoller.java
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2025, 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.lang.ref.Cleaner.Cleanable;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
import static sun.nio.ch.KQueue.*;
|
||||
|
||||
/**
|
||||
* Poller implementation based on the kqueue facility.
|
||||
*/
|
||||
class KQueuePoller extends Poller {
|
||||
private final int kqfd;
|
||||
private final int filter;
|
||||
private final int maxEvents;
|
||||
private final long address;
|
||||
|
||||
// file descriptors used for wakeup during shutdown
|
||||
private final int fd0;
|
||||
private final int fd1;
|
||||
|
||||
// close action, and cleaner if this is subpoller
|
||||
private final Runnable closer;
|
||||
private final Cleanable cleaner;
|
||||
|
||||
KQueuePoller(Poller.Mode mode, boolean subPoller, boolean read) throws IOException {
|
||||
boolean wakeable = (mode == Mode.POLLER_PER_CARRIER) && subPoller;
|
||||
int maxEvents = (subPoller) ? 16 : 64;
|
||||
|
||||
int kqfd = KQueue.create();
|
||||
long address = 0L;
|
||||
int fd0 = -1;
|
||||
int fd1 = -1;
|
||||
try {
|
||||
address = KQueue.allocatePollArray(maxEvents);
|
||||
|
||||
// register one end of the pipe with kqueue to allow for wakeup
|
||||
if (wakeable) {
|
||||
long fds = IOUtil.makePipe(false);
|
||||
fd0 = (int) (fds >>> 32);
|
||||
fd1 = (int) fds;
|
||||
KQueue.register(kqfd, fd0, EVFILT_READ, EV_ADD);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
if (address != 0L) KQueue.freePollArray(address);
|
||||
if (fd0 >= 0) FileDispatcherImpl.closeIntFD(fd0);
|
||||
if (fd1 >= 0) FileDispatcherImpl.closeIntFD(fd1);
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.kqfd = kqfd;
|
||||
this.filter = (read) ? EVFILT_READ : EVFILT_WRITE;
|
||||
this.maxEvents = maxEvents;
|
||||
this.address = address;
|
||||
this.fd0 = fd0;
|
||||
this.fd1 = fd1;
|
||||
|
||||
// create action to close kqueue, register cleaner when wakeable
|
||||
this.closer = closer(kqfd, address, fd0, fd1);
|
||||
if (wakeable) {
|
||||
this.cleaner = CleanerFactory.cleaner().register(this, closer);
|
||||
} else {
|
||||
this.cleaner = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an action to close the kqueue and release other resources.
|
||||
*/
|
||||
private static Runnable closer(int kqfd, long address, int fd0, int fd1) {
|
||||
return () -> {
|
||||
try {
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
KQueue.freePollArray(address);
|
||||
if (fd0 >= 0) FileDispatcherImpl.closeIntFD(fd0);
|
||||
if (fd1 >= 0) FileDispatcherImpl.closeIntFD(fd1);
|
||||
} catch (IOException _) { }
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
void close() {
|
||||
if (cleaner != null) {
|
||||
cleaner.clean();
|
||||
} else {
|
||||
closer.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int fdVal() {
|
||||
return kqfd;
|
||||
}
|
||||
|
||||
@Override
|
||||
void implStartPoll(int fdVal) throws IOException {
|
||||
int err = KQueue.register(kqfd, fdVal, filter, (EV_ADD|EV_ONESHOT));
|
||||
if (err != 0)
|
||||
throw new IOException("kevent failed: " + err);
|
||||
}
|
||||
|
||||
@Override
|
||||
void implStopPoll(int fdVal, boolean polled) {
|
||||
// event was deleted if already polled
|
||||
if (!polled) {
|
||||
KQueue.register(kqfd, fdVal, filter, EV_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void wakeupPoller() throws IOException {
|
||||
if (fd1 < 0) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
IOUtil.write1(fd1, (byte)0);
|
||||
}
|
||||
|
||||
@Override
|
||||
int poll(int timeout) throws IOException {
|
||||
int n = KQueue.poll(kqfd, address, maxEvents, timeout);
|
||||
int polled = 0;
|
||||
int i = 0;
|
||||
while (i < n) {
|
||||
long keventAddress = KQueue.getEvent(address, i);
|
||||
int fdVal = KQueue.getDescriptor(keventAddress);
|
||||
if (fdVal != fd0) {
|
||||
polled(fdVal);
|
||||
polled++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return polled;
|
||||
}
|
||||
}
|
||||
327
src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java
Normal file
327
src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2022, 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.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static sun.nio.ch.KQueue.EVFILT_READ;
|
||||
import static sun.nio.ch.KQueue.EVFILT_WRITE;
|
||||
import static sun.nio.ch.KQueue.EV_ADD;
|
||||
import static sun.nio.ch.KQueue.EV_ONESHOT;
|
||||
|
||||
/**
|
||||
* AsynchronousChannelGroup implementation based on the BSD kqueue facility.
|
||||
*/
|
||||
|
||||
final class KQueuePort
|
||||
extends Port
|
||||
{
|
||||
// maximum number of events to poll at a time
|
||||
private static final int MAX_KEVENTS_TO_POLL = 512;
|
||||
|
||||
// kqueue file descriptor
|
||||
private final int kqfd;
|
||||
|
||||
// address of the poll array passed to kqueue_wait
|
||||
private final long address;
|
||||
|
||||
// true if kqueue closed
|
||||
private boolean closed;
|
||||
|
||||
// socket pair used for wakeup
|
||||
private final int sp[];
|
||||
|
||||
// number of wakeups pending
|
||||
private final AtomicInteger wakeupCount = new AtomicInteger();
|
||||
|
||||
// encapsulates an event for a channel
|
||||
static class Event {
|
||||
final PollableChannel channel;
|
||||
final int events;
|
||||
|
||||
Event(PollableChannel channel, int events) {
|
||||
this.channel = channel;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
PollableChannel channel() { return channel; }
|
||||
int events() { return events; }
|
||||
}
|
||||
|
||||
// queue of events for cases that a polling thread dequeues more than one
|
||||
// event
|
||||
private final ArrayBlockingQueue<Event> queue;
|
||||
private final Event NEED_TO_POLL = new Event(null, 0);
|
||||
private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
|
||||
|
||||
KQueuePort(AsynchronousChannelProvider provider, ThreadPool pool)
|
||||
throws IOException
|
||||
{
|
||||
super(provider, pool);
|
||||
|
||||
this.kqfd = KQueue.create();
|
||||
this.address = KQueue.allocatePollArray(MAX_KEVENTS_TO_POLL);
|
||||
|
||||
// create socket pair for wakeup mechanism
|
||||
try {
|
||||
long fds = IOUtil.makePipe(true);
|
||||
this.sp = new int[]{(int) (fds >>> 32), (int) fds};
|
||||
} catch (IOException ioe) {
|
||||
KQueue.freePollArray(address);
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
// register one end with kqueue
|
||||
KQueue.register(kqfd, sp[0], EVFILT_READ, EV_ADD);
|
||||
|
||||
// create the queue and offer the special event to ensure that the first
|
||||
// threads polls
|
||||
this.queue = new ArrayBlockingQueue<>(MAX_KEVENTS_TO_POLL);
|
||||
this.queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
|
||||
KQueuePort start() {
|
||||
startThreads(new EventHandlerTask());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources
|
||||
*/
|
||||
private void implClose() {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
try { FileDispatcherImpl.closeIntFD(kqfd); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { }
|
||||
try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { }
|
||||
KQueue.freePollArray(address);
|
||||
}
|
||||
|
||||
private void wakeup() {
|
||||
if (wakeupCount.incrementAndGet() == 1) {
|
||||
// write byte to socketpair to force wakeup
|
||||
try {
|
||||
IOUtil.write1(sp[1], (byte)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 wakeup to each thread
|
||||
while (nThreads-- > 0) {
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invoked by clients to register a file descriptor
|
||||
@Override
|
||||
void startPoll(int fd, int events) {
|
||||
// We use a separate filter for read and write events.
|
||||
// TBD: Measure cost of EV_ONESHOT vs. EV_CLEAR, either will do here.
|
||||
int err = 0;
|
||||
int flags = (EV_ADD|EV_ONESHOT);
|
||||
if ((events & Net.POLLIN) > 0)
|
||||
err = KQueue.register(kqfd, fd, EVFILT_READ, flags);
|
||||
if (err == 0 && (events & Net.POLLOUT) > 0)
|
||||
err = KQueue.register(kqfd, fd, EVFILT_WRITE, flags);
|
||||
if (err != 0)
|
||||
throw new InternalError("kevent failed: " + err); // should not happen
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to process events from kqueue and dispatch to the channel's
|
||||
* onEvent handler.
|
||||
*
|
||||
* Events are retrieved from kqueue in batch and offered to a BlockingQueue
|
||||
* where they are consumed by handler threads. A special "NEED_TO_POLL"
|
||||
* event is used to signal one consumer to re-poll when all events have
|
||||
* been consumed.
|
||||
*/
|
||||
private class EventHandlerTask implements Runnable {
|
||||
private Event poll() throws IOException {
|
||||
try {
|
||||
for (;;) {
|
||||
int n;
|
||||
do {
|
||||
n = KQueue.poll(kqfd, address, MAX_KEVENTS_TO_POLL, -1L);
|
||||
} while (n == IOStatus.INTERRUPTED);
|
||||
|
||||
/**
|
||||
* 'n' events have been read. Here we map them to their
|
||||
* corresponding channel in batch and queue n-1 so that
|
||||
* they can be handled by other handler threads. The last
|
||||
* event is handled by this thread (and so is not queued).
|
||||
*/
|
||||
fdToChannelLock.readLock().lock();
|
||||
try {
|
||||
while (n-- > 0) {
|
||||
long keventAddress = KQueue.getEvent(address, n);
|
||||
int fd = KQueue.getDescriptor(keventAddress);
|
||||
|
||||
// wakeup
|
||||
if (fd == sp[0]) {
|
||||
if (wakeupCount.decrementAndGet() == 0) {
|
||||
// consume one wakeup byte, never more as this
|
||||
// would interfere with shutdown when there is
|
||||
// a wakeup byte queued to wake each thread
|
||||
int nread;
|
||||
do {
|
||||
nread = IOUtil.drain1(sp[0]);
|
||||
} while (nread == IOStatus.INTERRUPTED);
|
||||
}
|
||||
|
||||
// queue special event if there are more events
|
||||
// to handle.
|
||||
if (n > 0) {
|
||||
queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
|
||||
continue;
|
||||
}
|
||||
return EXECUTE_TASK_OR_SHUTDOWN;
|
||||
}
|
||||
|
||||
PollableChannel channel = fdToChannel.get(fd);
|
||||
if (channel != null) {
|
||||
int filter = KQueue.getFilter(keventAddress);
|
||||
int events = 0;
|
||||
if (filter == EVFILT_READ)
|
||||
events = Net.POLLIN;
|
||||
else if (filter == EVFILT_WRITE)
|
||||
events = Net.POLLOUT;
|
||||
|
||||
Event ev = new Event(channel, events);
|
||||
|
||||
// n-1 events are queued; This thread handles
|
||||
// the last one except for the wakeup
|
||||
if (n > 0) {
|
||||
queue.offer(ev);
|
||||
} else {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fdToChannelLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// to ensure that some thread will poll when all events have
|
||||
// been consumed
|
||||
queue.offer(NEED_TO_POLL);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
|
||||
Invoker.getGroupAndInvokeCount();
|
||||
final boolean isPooledThread = (myGroupAndInvokeCount != null);
|
||||
boolean replaceMe = false;
|
||||
Event ev;
|
||||
try {
|
||||
for (;;) {
|
||||
// reset invoke count
|
||||
if (isPooledThread)
|
||||
myGroupAndInvokeCount.resetInvokeCount();
|
||||
|
||||
try {
|
||||
replaceMe = false;
|
||||
ev = queue.take();
|
||||
|
||||
// no events and this thread has been "selected" to
|
||||
// poll for more.
|
||||
if (ev == NEED_TO_POLL) {
|
||||
try {
|
||||
ev = poll();
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle wakeup to execute task or shutdown
|
||||
if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
|
||||
Runnable task = pollTask();
|
||||
if (task == null) {
|
||||
// shutdown request
|
||||
return;
|
||||
}
|
||||
// run task (may throw error/exception)
|
||||
replaceMe = true;
|
||||
task.run();
|
||||
continue;
|
||||
}
|
||||
|
||||
// process event
|
||||
try {
|
||||
ev.channel().onEvent(ev.events(), isPooledThread);
|
||||
} catch (Error | RuntimeException x) {
|
||||
replaceMe = true;
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// last handler to exit when shutdown releases resources
|
||||
int remaining = threadExit(this, replaceMe);
|
||||
if (remaining == 0 && isShutdown()) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
342
src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
Normal file
342
src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2024, 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.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static sun.nio.ch.KQueue.EVFILT_READ;
|
||||
import static sun.nio.ch.KQueue.EVFILT_WRITE;
|
||||
import static sun.nio.ch.KQueue.EV_ADD;
|
||||
import static sun.nio.ch.KQueue.EV_DELETE;
|
||||
|
||||
/**
|
||||
* KQueue based Selector implementation for macOS
|
||||
*/
|
||||
|
||||
class KQueueSelectorImpl extends SelectorImpl {
|
||||
|
||||
// maximum number of events to poll in one call to kqueue
|
||||
private static final int MAX_KEVENTS = 256;
|
||||
|
||||
// kqueue file descriptor
|
||||
private final int kqfd;
|
||||
|
||||
// address of poll array (event list) when polling for pending events
|
||||
private final long pollArrayAddress;
|
||||
|
||||
// file descriptors used for interrupt
|
||||
private final int fd0;
|
||||
private final int fd1;
|
||||
|
||||
// maps file descriptor to selection key, synchronize on selector
|
||||
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
|
||||
|
||||
// pending new registrations/updates, queued by setEventOps
|
||||
private final Object updateLock = new Object();
|
||||
private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
|
||||
|
||||
// interrupt triggering and clearing
|
||||
private final Object interruptLock = new Object();
|
||||
private boolean interruptTriggered;
|
||||
|
||||
// used by updateSelectedKeys to handle cases where the same file
|
||||
// descriptor is polled by more than one filter
|
||||
private int pollCount;
|
||||
|
||||
KQueueSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
|
||||
this.kqfd = KQueue.create();
|
||||
this.pollArrayAddress = KQueue.allocatePollArray(MAX_KEVENTS);
|
||||
|
||||
try {
|
||||
long fds = IOUtil.makePipe(false);
|
||||
this.fd0 = (int) (fds >>> 32);
|
||||
this.fd1 = (int) fds;
|
||||
} catch (IOException ioe) {
|
||||
KQueue.freePollArray(pollArrayAddress);
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
// register one end of the socket pair for wakeups
|
||||
KQueue.register(kqfd, fd0, EVFILT_READ, EV_ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doSelect(Consumer<SelectionKey> action, long timeout)
|
||||
throws IOException
|
||||
{
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
long to = Math.min(timeout, Integer.MAX_VALUE); // max kqueue timeout
|
||||
boolean blocking = (to != 0);
|
||||
boolean timedPoll = (to > 0);
|
||||
|
||||
int numEntries;
|
||||
processUpdateQueue();
|
||||
processDeregisterQueue();
|
||||
|
||||
if (Thread.currentThread().isVirtual()) {
|
||||
numEntries = (timedPoll)
|
||||
? timedPoll(TimeUnit.MILLISECONDS.toNanos(to))
|
||||
: untimedPoll(blocking);
|
||||
} else {
|
||||
try {
|
||||
begin(blocking);
|
||||
do {
|
||||
long startTime = timedPoll ? System.nanoTime() : 0;
|
||||
numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, to);
|
||||
if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
|
||||
// timed poll interrupted so need to adjust timeout
|
||||
long adjust = System.nanoTime() - startTime;
|
||||
to -= TimeUnit.NANOSECONDS.toMillis(adjust);
|
||||
if (to <= 0) {
|
||||
// timeout expired so no retry
|
||||
numEntries = 0;
|
||||
}
|
||||
}
|
||||
} while (numEntries == IOStatus.INTERRUPTED);
|
||||
} finally {
|
||||
end(blocking);
|
||||
}
|
||||
}
|
||||
assert IOStatus.check(numEntries);
|
||||
|
||||
processDeregisterQueue();
|
||||
return processEvents(numEntries, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* If blocking, parks the current virtual thread until a file descriptor is polled
|
||||
* or the thread is interrupted.
|
||||
*/
|
||||
private int untimedPoll(boolean block) throws IOException {
|
||||
int numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, 0);
|
||||
if (block) {
|
||||
while (numEntries == 0 && !Thread.currentThread().isInterrupted()) {
|
||||
Poller.pollSelector(kqfd, 0);
|
||||
numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, 0);
|
||||
}
|
||||
}
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parks the current virtual thread until a file descriptor is polled, or the thread
|
||||
* is interrupted, for up to the specified waiting time.
|
||||
*/
|
||||
private int timedPoll(long nanos) throws IOException {
|
||||
long startNanos = System.nanoTime();
|
||||
int numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, 0);
|
||||
while (numEntries == 0 && !Thread.currentThread().isInterrupted()) {
|
||||
long remainingNanos = nanos - (System.nanoTime() - startNanos);
|
||||
if (remainingNanos <= 0) {
|
||||
// timeout
|
||||
break;
|
||||
}
|
||||
Poller.pollSelector(kqfd, remainingNanos);
|
||||
numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, 0);
|
||||
}
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process changes to the interest ops.
|
||||
*/
|
||||
private void processUpdateQueue() {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
synchronized (updateLock) {
|
||||
SelectionKeyImpl ski;
|
||||
while ((ski = updateKeys.pollFirst()) != null) {
|
||||
if (ski.isValid()) {
|
||||
int fd = ski.getFDVal();
|
||||
// add to fdToKey if needed
|
||||
SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
|
||||
assert (previous == null) || (previous == ski);
|
||||
|
||||
int newEvents = ski.translateInterestOps();
|
||||
int registeredEvents = ski.registeredEvents();
|
||||
|
||||
// DatagramChannelImpl::disconnect has reset socket
|
||||
if (ski.getAndClearReset() && registeredEvents != 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
|
||||
registeredEvents = 0;
|
||||
}
|
||||
|
||||
if (newEvents != registeredEvents) {
|
||||
|
||||
// add or delete interest in read events
|
||||
if ((registeredEvents & Net.POLLIN) != 0) {
|
||||
if ((newEvents & Net.POLLIN) == 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
|
||||
}
|
||||
} else if ((newEvents & Net.POLLIN) != 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_READ, EV_ADD);
|
||||
}
|
||||
|
||||
// add or delete interest in write events
|
||||
if ((registeredEvents & Net.POLLOUT) != 0) {
|
||||
if ((newEvents & Net.POLLOUT) == 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
|
||||
}
|
||||
} else if ((newEvents & Net.POLLOUT) != 0) {
|
||||
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_ADD);
|
||||
}
|
||||
|
||||
ski.registeredEvents(newEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the polled events.
|
||||
* If the interrupt fd has been selected, drain it and clear the interrupt.
|
||||
*/
|
||||
private int processEvents(int numEntries, Consumer<SelectionKey> action)
|
||||
throws IOException
|
||||
{
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
int numKeysUpdated = 0;
|
||||
boolean interrupted = false;
|
||||
|
||||
// A file descriptor may be registered with kqueue with more than one
|
||||
// filter and so there may be more than one event for a fd. The poll
|
||||
// count is incremented here and compared against the SelectionKey's
|
||||
// "lastPolled" field. This ensures that the ready ops is updated rather
|
||||
// than replaced when a file descriptor is polled by both the read and
|
||||
// write filter.
|
||||
pollCount++;
|
||||
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
long kevent = KQueue.getEvent(pollArrayAddress, i);
|
||||
int fd = KQueue.getDescriptor(kevent);
|
||||
if (fd == fd0) {
|
||||
interrupted = true;
|
||||
} else {
|
||||
SelectionKeyImpl ski = fdToKey.get(fd);
|
||||
if (ski != null) {
|
||||
int rOps = 0;
|
||||
short filter = KQueue.getFilter(kevent);
|
||||
if (filter == EVFILT_READ) {
|
||||
rOps |= Net.POLLIN;
|
||||
} else if (filter == EVFILT_WRITE) {
|
||||
rOps |= Net.POLLOUT;
|
||||
}
|
||||
int updated = processReadyEvents(rOps, ski, action);
|
||||
if (updated > 0 && ski.lastPolled != pollCount) {
|
||||
numKeysUpdated++;
|
||||
ski.lastPolled = pollCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interrupted) {
|
||||
clearInterrupt();
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implClose() throws IOException {
|
||||
assert !isOpen();
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcherImpl.closeIntFD(kqfd);
|
||||
KQueue.freePollArray(pollArrayAddress);
|
||||
|
||||
FileDispatcherImpl.closeIntFD(fd0);
|
||||
FileDispatcherImpl.closeIntFD(fd1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
assert !ski.isValid();
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
int fd = ski.getFDVal();
|
||||
int registeredEvents = ski.registeredEvents();
|
||||
if (fdToKey.remove(fd) != null) {
|
||||
if (registeredEvents != 0) {
|
||||
if ((registeredEvents & Net.POLLIN) != 0)
|
||||
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
|
||||
if ((registeredEvents & Net.POLLOUT) != 0)
|
||||
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
|
||||
ski.registeredEvents(0);
|
||||
}
|
||||
} else {
|
||||
assert registeredEvents == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventOps(SelectionKeyImpl ski) {
|
||||
synchronized (updateLock) {
|
||||
updateKeys.addLast(ski);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
try {
|
||||
IOUtil.write1(fd1, (byte)0);
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void clearInterrupt() throws IOException {
|
||||
synchronized (interruptLock) {
|
||||
IOUtil.drain(fd0);
|
||||
interruptTriggered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue