# HG changeset patch # User simonis # Date 1385480431 -3600 # Node ID 541585921c82c1dd7c5fb93b81dafa3b10d5e142 # Parent 488eade6d51064d7bbe55b055c412e54258e208a 8024854: PPC64: Basic changes and files to build the class library on AIX Reviewed-by: alanb, prr, sla, chegar, michaelm, mullan, art Contributed-by: luchsh@linux.vnet.ibm.com, spoole@linux.vnet.ibm.com, thomas.stuefe@sap.com diff --git a/makefiles/CompileDemos.gmk b/makefiles/CompileDemos.gmk --- a/makefiles/CompileDemos.gmk +++ b/makefiles/CompileDemos.gmk @@ -210,9 +210,12 @@ # Param 5 = libs for posix # Param 6 = libs for windows # Param 7 = libs for solaris + # Param 8 = libs for linux + # Param 9 = extra directories with required sources BUILD_DEMO_JVMTI_$1_EXTRA_SRC := \ $$(wildcard $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/demo/jvmti/$1) \ - $$(wildcard $$(addprefix $(JDK_TOPDIR)/src/share/demo/jvmti/, $2)) + $$(wildcard $$(addprefix $(JDK_TOPDIR)/src/share/demo/jvmti/, $2)) \ + $9 BUILD_DEMO_JVMTI_$1_EXTRA_SRC_EXCLUDE := \ $$(wildcard $$(addprefix $(JDK_TOPDIR)/src/share/demo/jvmti/, $2)/README.txt) \ $$(wildcard $$(addprefix $(JDK_TOPDIR)/src/share/demo/jvmti/, $2)/sample.makefile.txt) @@ -304,9 +307,19 @@ $(eval $(call SetupJVMTIDemo,gctest, agent_util)) $(eval $(call SetupJVMTIDemo,heapTracker, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,heapViewer, agent_util)) + +# On AIX, hprof requires 'dladdr' from src/aix/porting/porting_aix.cpp +BUILD_LIBHPROF_AIX_EXTRA_SRC := +BUILD_LIBHPROF_AIX_EXTRA_CFLAGS := +ifeq ($(OPENJDK_TARGET_OS), aix) + BUILD_LIBHPROF_AIX_EXTRA_SRC += $(JDK_TOPDIR)/src/aix/porting + BUILD_LIBHPROF_AIX_EXTRA_CFLAGS += -I$(JDK_TOPDIR)/src/aix/porting +endif + $(eval $(call SetupJVMTIDemo,hprof, java_crw_demo, \ - -I$(JDK_TOPDIR)/src/share/npt -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/npt, C, \ - -ldl, ws2_32.lib winmm.lib, -lsocket -lnsl, -lpthread)) + -I$(JDK_TOPDIR)/src/share/npt -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/npt \ + $(BUILD_LIBHPROF_AIX_EXTRA_CFLAGS), C, \ + -ldl, ws2_32.lib winmm.lib, -lsocket -lnsl, -lpthread, $(BUILD_LIBHPROF_AIX_EXTRA_SRC))) $(eval $(call SetupJVMTIDemo,minst, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,mtrace, agent_util java_crw_demo)) diff --git a/makefiles/lib/Awt2dLibraries.gmk b/makefiles/lib/Awt2dLibraries.gmk --- a/makefiles/lib/Awt2dLibraries.gmk +++ b/makefiles/lib/Awt2dLibraries.gmk @@ -231,6 +231,10 @@ $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/x11 endif +ifeq ($(OPENJDK_TARGET_OS), aix) + LIBAWT_DIRS += $(JDK_TOPDIR)/src/aix/porting +endif + LIBAWT_CFLAGS += -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES \ $(X_CFLAGS) \ $(foreach dir, $(LIBAWT_DIRS), -I$(dir)) @@ -309,6 +313,10 @@ LIBAWT_FILES += awt_LoadLibrary.c initIDs.c img_colors.c endif +ifeq ($(OPENJDK_TARGET_OS), aix) + LIBAWT_FILES += porting_aix.c +endif + ifeq ($(OPENJDK_TARGET_OS), macosx) LIBAWT_FILES += awt_LoadLibrary.c img_colors.c LIBAWT_CFLAGS += -F/System/Library/Frameworks/JavaVM.framework/Frameworks diff --git a/makefiles/lib/NetworkingLibraries.gmk b/makefiles/lib/NetworkingLibraries.gmk --- a/makefiles/lib/NetworkingLibraries.gmk +++ b/makefiles/lib/NetworkingLibraries.gmk @@ -37,7 +37,7 @@ LIBNET_CFLAGS := $(foreach dir, $(LIBNET_SRC_DIRS), -I$(dir)) LIBNET_EXCLUDE_FILES := -ifeq (, $(filter $(OPENJDK_TARGET_OS), linux aix)) +ifneq ($(OPENJDK_TARGET_OS), linux) LIBNET_EXCLUDE_FILES += linux_close.c endif @@ -45,6 +45,10 @@ LIBNET_EXCLUDE_FILES += bsd_close.c endif +ifeq ($(OPENJDK_TARGET_OS), aix) + LIBNET_SRC_DIRS += $(JDK_TOPDIR)/src/aix/native/java/net/ +endif + ifeq ($(OPENJDK_TARGET_OS), windows) LIBNET_EXCLUDE_FILES += PlainSocketImpl.c PlainDatagramSocketImpl.c SdpSupport.c else diff --git a/makefiles/lib/NioLibraries.gmk b/makefiles/lib/NioLibraries.gmk --- a/makefiles/lib/NioLibraries.gmk +++ b/makefiles/lib/NioLibraries.gmk @@ -114,7 +114,9 @@ ifeq ($(OPENJDK_TARGET_OS), aix) BUILD_LIBNIO_MAPFILE:=$(JDK_TOPDIR)/makefiles/mapfiles/libnio/mapfile-$(OPENJDK_TARGET_OS) - BUILD_LIBNIO_SRC += $(JDK_TOPDIR)/src/aix/native/sun/nio/ch + BUILD_LIBNIO_SRC += \ + $(JDK_TOPDIR)/src/aix/native/sun/nio/ch \ + $(JDK_TOPDIR)/src/aix/native/sun/nio/fs BUILD_LIBNIO_FILES += \ AixPollPort.c \ InheritedChannel.c \ diff --git a/makefiles/lib/ServiceabilityLibraries.gmk b/makefiles/lib/ServiceabilityLibraries.gmk --- a/makefiles/lib/ServiceabilityLibraries.gmk +++ b/makefiles/lib/ServiceabilityLibraries.gmk @@ -344,6 +344,11 @@ -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/npt \ -I$(JDK_TOPDIR)/src/share/demo/jvmti/java_crw_demo +ifeq ($(OPENJDK_TARGET_OS), aix) + BUILD_LIBHPROF_SRC += $(JDK_TOPDIR)/src/aix/porting + BUILD_LIBHPROF_CFLAGS += -I$(JDK_TOPDIR)/src/aix/porting +endif + BUILD_LIBHPROF_LDFLAGS := LIBHPROF_OPTIMIZATION := HIGHEST diff --git a/src/aix/classes/sun/awt/fontconfigs/aix.fontconfig.properties b/src/aix/classes/sun/awt/fontconfigs/aix.fontconfig.properties new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/awt/fontconfigs/aix.fontconfig.properties @@ -0,0 +1,77 @@ +# +# +# Copyright 2013 SAP AG. 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. +# + +# Minimal version for AIX using the standard Latin Type1 Fonts from the +# package X11.fnt.iso_T1. These fonts are installed by default into +# "/usr/lpp/X11/lib/X11/fonts/Type1" and sym-linked to "/usr/lib/X11/fonts/Type1" + +# Version + +version=1 + +# Component Font Mappings + +dialog.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1 +dialog.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1 +dialog.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1 +dialog.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1 + +dialoginput.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1 +dialoginput.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1 +dialoginput.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1 +dialoginput.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1 + +sansserif.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1 +sansserif.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1 +sansserif.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1 +sansserif.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1 + +serif.plain.latin-1=-*-times new roman-medium-r-normal--*-%d-100-100-p-*-iso10646-1 +serif.bold.latin-1=-*-times new roman-bold-r-normal--*-%d-100-100-p-*-iso10646-1 +serif.italic.latin-1=-*-times new roman-medium-i-normal--*-%d-100-100-p-*-iso10646-1 +serif.bolditalic.latin-1=-*-times new roman-bold-i-normal--*-%d-100-100-p-*-iso10646-1 + +monospaced.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1 +monospaced.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1 +monospaced.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1 +monospaced.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1 + +# Search Sequences + +sequence.allfonts=latin-1 + +filename.-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/cour.pfa +filename.-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/courb.pfa +filename.-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/couri.pfa +filename.-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/courbi.pfa +filename.-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helv.pfa +filename.-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvb.pfa +filename.-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvi.pfa +filename.-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvbi.pfa +filename.-*-times_new_roman-medium-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnr.pfa +filename.-*-times_new_roman-bold-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrb.pfa +filename.-*-times_new_roman-medium-i-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnri.pfa +filename.-*-times_new_roman-bold-i-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrbi.pfa diff --git a/src/aix/classes/sun/nio/ch/AixAsynchronousChannelProvider.java b/src/aix/classes/sun/nio/ch/AixAsynchronousChannelProvider.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/nio/ch/AixAsynchronousChannelProvider.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 SAP AG. 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)); + } +} diff --git a/src/aix/classes/sun/nio/ch/AixPollPort.java b/src/aix/classes/sun/nio/ch/AixPollPort.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/nio/ch/AixPollPort.java @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 SAP AG. 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.HashSet; +import java.util.Iterator; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; +import sun.misc.Unsafe; + +/** + * AsynchronousChannelGroup implementation based on the AIX pollset framework. + */ +final class AixPollPort + extends Port +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + static { + IOUtil.load(); + init(); + } + + /** + * struct pollfd { + * int fd; + * short events; + * short revents; + * } + */ + private static final int SIZEOF_POLLFD = eventSize(); + private static final int OFFSETOF_EVENTS = eventsOffset(); + private static final int OFFSETOF_REVENTS = reventsOffset(); + private static final int OFFSETOF_FD = fdOffset(); + + // opcodes + private static final int PS_ADD = 0x0; + private static final int PS_MOD = 0x1; + private static final int PS_DELETE = 0x2; + + // maximum number of events to poll at a time + private static final int MAX_POLL_EVENTS = 512; + + // 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; + + // 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 queue; + private final Event NEED_TO_POLL = new Event(null, 0); + private final Event EXECUTE_TASK_OR_SHUTDOWN = 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 controlQueue = new HashSet(); + + // 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 = pollsetCreate(); + + // create socket pair for wakeup mechanism + int[] sv = new int[2]; + try { + socketpair(sv); + // register one end with pollset + pollsetCtl(pollset, PS_ADD, sv[0], POLLIN); + } catch (IOException x) { + pollsetDestroy(pollset); + throw x; + } + this.sp = sv; + + // create socket pair for pollset control mechanism + sv = new int[2]; + try { + socketpair(sv); + // register one end with pollset + pollsetCtl(pollset, PS_ADD, sv[0], POLLIN); + } catch (IOException x) { + pollsetDestroy(pollset); + throw x; + } + this.ctlSp = sv; + + // allocate the poll array + this.address = allocatePollArray(MAX_POLL_EVENTS); + + // create the queue and offer the special event to ensure that the first + // threads polls + this.queue = new ArrayBlockingQueue(MAX_POLL_EVENTS); + 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; + } + freePollArray(address); + close0(sp[0]); + close0(sp[1]); + close0(ctlSp[0]); + close0(ctlSp[1]); + pollsetDestroy(pollset); + } + + private void wakeup() { + if (wakeupCount.incrementAndGet() == 1) { + // write byte to socketpair to force wakeup + try { + 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 { + 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() { + synchronized (controlQueue) { + // 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 iter = controlQueue.iterator(); + while (iter.hasNext()) { + ControlEvent ev = iter.next(); + pollsetCtl(pollset, PS_DELETE, ev.fd(), 0); + if (!ev.removeOnly()) { + ev.setError(pollsetCtl(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 retreived 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 { + n = pollsetPoll(pollset, address, MAX_POLL_EVENTS); + } 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 = getEvent(address, n); + int fd = getDescriptor(eventAddress); + + // To emulate one shot semantic we need to remove + // the file descriptor here. + pollsetCtl(pollset, PS_DELETE, fd, 0); + + // wakeup + if (fd == sp[0]) { + if (wakeupCount.decrementAndGet() == 0) { + // no more wakeups so drain pipe + drain1(sp[0]); + } + + // This is the only file descriptor without + // one shot semantic => register it again. + pollsetCtl(pollset, PS_ADD, sp[0], POLLIN); + + // 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) { + drain1(ctlSp[0]); + // This file descriptor does not have + // one shot semantic => register it again. + pollsetCtl(pollset, PS_ADD, ctlSp[0], POLLIN); + processControlQueue(); + } + continue; + } + + PollableChannel channel = fdToChannel.get(fd); + if (channel != null) { + int events = 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; + } + + // 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 x) { + replaceMe = true; throw x; + } catch (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(); + } + } + } + } + + /** + * Allocates a poll array to handle up to {@code count} events. + */ + private static long allocatePollArray(int count) { + return unsafe.allocateMemory(count * SIZEOF_POLLFD); + } + + /** + * Free a poll array + */ + private static void freePollArray(long address) { + unsafe.freeMemory(address); + } + + /** + * Returns event[i]; + */ + private static long getEvent(long address, int i) { + return address + (SIZEOF_POLLFD*i); + } + + /** + * Returns event->fd + */ + private static int getDescriptor(long eventAddress) { + return unsafe.getInt(eventAddress + OFFSETOF_FD); + } + + /** + * Returns event->events + */ + private static int getEvents(long eventAddress) { + return unsafe.getChar(eventAddress + OFFSETOF_EVENTS); + } + + /** + * Returns event->revents + */ + private static int getRevents(long eventAddress) { + return unsafe.getChar(eventAddress + OFFSETOF_REVENTS); + } + + // -- Native methods -- + + private static native void init(); + + private static native int eventSize(); + + private static native int eventsOffset(); + + private static native int reventsOffset(); + + private static native int fdOffset(); + + private static native int pollsetCreate() throws IOException; + + private static native int pollsetCtl(int pollset, int opcode, int fd, int events); + + private static native int pollsetPoll(int pollset, long pollAddress, int numfds) + throws IOException; + + private static native void pollsetDestroy(int pollset); + + private static native void socketpair(int[] sv) throws IOException; + + private static native void interrupt(int fd) throws IOException; + + private static native void drain1(int fd) throws IOException; + + private static native void close0(int fd); +} diff --git a/src/aix/classes/sun/nio/fs/AixFileStore.java b/src/aix/classes/sun/nio/fs/AixFileStore.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/nio/fs/AixFileStore.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. 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"); + } + + // returns true if extended attributes enabled on file system where given + // file resides, returns false if disabled or unable to determine. + private boolean isExtendedAttributesEnabled(UnixPath path) { + return false; + } + + @Override + public boolean supportsFileAttributeView(Class type) { + return super.supportsFileAttributeView(type); + } + + @Override + public boolean supportsFileAttributeView(String name) { + return super.supportsFileAttributeView(name); + } +} diff --git a/src/aix/classes/sun/nio/fs/AixFileSystem.java b/src/aix/classes/sun/nio/fs/AixFileSystem.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/nio/fs/AixFileSystem.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. 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 supportedFileAttributeViews = + supportedFileAttributeViews(); + private static Set supportedFileAttributeViews() { + Set result = new HashSet(); + result.addAll(UnixFileSystem.standardFileAttributeViews()); + return Collections.unmodifiableSet(result); + } + } + + @Override + public Set 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 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); + } +} diff --git a/src/aix/classes/sun/nio/fs/AixFileSystemProvider.java b/src/aix/classes/sun/nio/fs/AixFileSystemProvider.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/nio/fs/AixFileSystemProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. 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; + +/** + * AIX implementation of FileSystemProvider + */ + +public 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); + } +} diff --git a/src/aix/classes/sun/nio/fs/AixNativeDispatcher.java b/src/aix/classes/sun/nio/fs/AixNativeDispatcher.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/nio/fs/AixNativeDispatcher.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.fs; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * 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 int init(); + + static { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff --git a/src/aix/classes/sun/tools/attach/AixAttachProvider.java b/src/aix/classes/sun/tools/attach/AixAttachProvider.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/tools/attach/AixAttachProvider.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. 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.tools.attach; + +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; +import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.spi.AttachProvider; + +import java.io.IOException; + +// Based on 'LinuxAttachProvider.java'. All occurrences of the string +// "Linux" have been textually replaced by "Aix" to avoid confusion. + +/* + * An AttachProvider implementation for Aix that uses a UNIX domain + * socket. + */ +public class AixAttachProvider extends HotSpotAttachProvider { + + // perf counter for the JVM version + private static final String JVM_VERSION = "java.property.java.vm.version"; + + public AixAttachProvider() { + } + + public String name() { + return "sun"; + } + + public String type() { + return "socket"; + } + + public VirtualMachine attachVirtualMachine(String vmid) + throws AttachNotSupportedException, IOException + { + checkAttachPermission(); + + // AttachNotSupportedException will be thrown if the target VM can be determined + // to be not attachable. + testAttachable(vmid); + + return new AixVirtualMachine(this, vmid); + } + + public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd) + throws AttachNotSupportedException, IOException + { + if (vmd.provider() != this) { + throw new AttachNotSupportedException("provider mismatch"); + } + // To avoid re-checking if the VM if attachable, we check if the descriptor + // is for a hotspot VM - these descriptors are created by the listVirtualMachines + // implementation which only returns a list of attachable VMs. + if (vmd instanceof HotSpotVirtualMachineDescriptor) { + assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable(); + checkAttachPermission(); + return new AixVirtualMachine(this, vmd.id()); + } else { + return attachVirtualMachine(vmd.id()); + } + } + +} diff --git a/src/aix/classes/sun/tools/attach/AixVirtualMachine.java b/src/aix/classes/sun/tools/attach/AixVirtualMachine.java new file mode 100644 --- /dev/null +++ b/src/aix/classes/sun/tools/attach/AixVirtualMachine.java @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. 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.tools.attach; + +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.AgentLoadException; +import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.spi.AttachProvider; +import java.io.InputStream; +import java.io.IOException; +import java.io.File; +import java.util.Properties; + +// Based on 'LinuxVirtualMachine.java'. All occurrences of the string +// "Linux" have been textually replaced by "Aix" to avoid confusion. + +/* + * Aix implementation of HotSpotVirtualMachine + */ +public class AixVirtualMachine extends HotSpotVirtualMachine { + // "/tmp" is used as a global well-known location for the files + // .java_pid. and .attach_pid. It is important that this + // location is the same for all processes, otherwise the tools + // will not be able to find all Hotspot processes. + // Any changes to this needs to be synchronized with HotSpot. + private static final String tmpdir = "/tmp"; + + // The patch to the socket file created by the target VM + String path; + + /** + * Attaches to the target VM + */ + AixVirtualMachine(AttachProvider provider, String vmid) + throws AttachNotSupportedException, IOException + { + super(provider, vmid); + + // This provider only understands pids + int pid; + try { + pid = Integer.parseInt(vmid); + } catch (NumberFormatException x) { + throw new AttachNotSupportedException("Invalid process identifier"); + } + + // Find the socket file. If not found then we attempt to start the + // attach mechanism in the target VM by sending it a QUIT signal. + // Then we attempt to find the socket file again. + path = findSocketFile(pid); + if (path == null) { + File f = createAttachFile(pid); + try { + sendQuitTo(pid); + + // give the target VM time to start the attach mechanism + int i = 0; + long delay = 200; + int retries = (int)(attachTimeout() / delay); + do { + try { + Thread.sleep(delay); + } catch (InterruptedException x) { } + path = findSocketFile(pid); + i++; + } while (i <= retries && path == null); + if (path == null) { + throw new AttachNotSupportedException( + "Unable to open socket file: target process not responding " + + "or HotSpot VM not loaded"); + } + } finally { + f.delete(); + } + } + + // Check that the file owner/permission to avoid attaching to + // bogus process + checkPermissions(path); + + // Check that we can connect to the process + // - this ensures we throw the permission denied error now rather than + // later when we attempt to enqueue a command. + int s = socket(); + try { + connect(s, path); + } finally { + close(s); + } + } + + /** + * Detach from the target VM + */ + public void detach() throws IOException { + synchronized (this) { + if (this.path != null) { + this.path = null; + } + } + } + + // protocol version + private final static String PROTOCOL_VERSION = "1"; + + // known errors + private final static int ATTACH_ERROR_BADVERSION = 101; + + /** + * Execute the given command in the target VM. + */ + InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException { + assert args.length <= 3; // includes null + + // did we detach? + String p; + synchronized (this) { + if (this.path == null) { + throw new IOException("Detached from target VM"); + } + p = this.path; + } + + // create UNIX socket + int s = socket(); + + // connect to target VM + try { + connect(s, p); + } catch (IOException x) { + close(s); + throw x; + } + + IOException ioe = null; + + // connected - write request + // + try { + writeString(s, PROTOCOL_VERSION); + writeString(s, cmd); + + for (int i=0; i<3; i++) { + if (i < args.length && args[i] != null) { + writeString(s, (String)args[i]); + } else { + writeString(s, ""); + } + } + } catch (IOException x) { + ioe = x; + } + + + // Create an input stream to read reply + SocketInputStream sis = new SocketInputStream(s); + + // Read the command completion status + int completionStatus; + try { + completionStatus = readInt(sis); + } catch (IOException x) { + sis.close(); + if (ioe != null) { + throw ioe; + } else { + throw x; + } + } + + if (completionStatus != 0) { + sis.close(); + + // In the event of a protocol mismatch then the target VM + // returns a known error so that we can throw a reasonable + // error. + if (completionStatus == ATTACH_ERROR_BADVERSION) { + throw new IOException("Protocol mismatch with target VM"); + } + + // Special-case the "load" command so that the right exception is + // thrown. + if (cmd.equals("load")) { + throw new AgentLoadException("Failed to load agent library"); + } else { + throw new IOException("Command failed in target VM"); + } + } + + // Return the input stream so that the command output can be read + return sis; + } + + /* + * InputStream for the socket connection to get target VM + */ + private class SocketInputStream extends InputStream { + int s; + + public SocketInputStream(int s) { + this.s = s; + } + + public synchronized int read() throws IOException { + byte b[] = new byte[1]; + int n = this.read(b, 0, 1); + if (n == 1) { + return b[0] & 0xff; + } else { + return -1; + } + } + + public synchronized int read(byte[] bs, int off, int len) throws IOException { + if ((off < 0) || (off > bs.length) || (len < 0) || + ((off + len) > bs.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) + return 0; + + return AixVirtualMachine.read(s, bs, off, len); + } + + public void close() throws IOException { + AixVirtualMachine.close(s); + } + } + + // Return the socket file for the given process. + private String findSocketFile(int pid) { + File f = new File(tmpdir, ".java_pid" + pid); + if (!f.exists()) { + return null; + } + return f.getPath(); + } + + // On Solaris/Linux/Aix a simple handshake is used to start the attach mechanism + // if not already started. The client creates a .attach_pid file in the + // target VM's working directory (or temp directory), and the SIGQUIT handler + // checks for the file. + private File createAttachFile(int pid) throws IOException { + String fn = ".attach_pid" + pid; + String path = "/proc/" + pid + "/cwd/" + fn; + File f = new File(path); + try { + f.createNewFile(); + } catch (IOException x) { + f = new File(tmpdir, fn); + f.createNewFile(); + } + return f; + } + + /* + * Write/sends the given to the target VM. String is transmitted in + * UTF-8 encoding. + */ + private void writeString(int fd, String s) throws IOException { + if (s.length() > 0) { + byte b[]; + try { + b = s.getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException x) { + throw new InternalError(x); + } + AixVirtualMachine.write(fd, b, 0, b.length); + } + byte b[] = new byte[1]; + b[0] = 0; + write(fd, b, 0, 1); + } + + + //-- native methods + + static native void sendQuitTo(int pid) throws IOException; + + static native void checkPermissions(String path) throws IOException; + + static native int socket() throws IOException; + + static native void connect(int fd, String path) throws IOException; + + static native void close(int fd) throws IOException; + + static native int read(int fd, byte buf[], int off, int bufLen) throws IOException; + + static native void write(int fd, byte buf[], int off, int bufLen) throws IOException; + + static { + System.loadLibrary("attach"); + } +} diff --git a/src/aix/native/java/net/aix_close.c b/src/aix/native/java/net/aix_close.c new file mode 100644 --- /dev/null +++ b/src/aix/native/java/net/aix_close.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file contains implementations of NET_... functions. The NET_.. functions are + * wrappers for common file- and socket functions plus provisions for non-blocking IO. + * + * (basically, the layers remember all file descriptors waiting for a particular fd; + * all threads waiting on a certain fd can be woken up by sending them a signal; this + * is done e.g. when the fd is closed.) + * + * This was originally copied from the linux_close.c implementation. + * + * Side Note: This coding needs initialization. Under Linux this is done + * automatically via __attribute((constructor)), on AIX this is done manually + * (see aix_close_init). + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Stack allocated by thread when doing blocking operation + */ +typedef struct threadEntry { + pthread_t thr; /* this thread */ + struct threadEntry *next; /* next thread */ + int intr; /* interrupted */ +} threadEntry_t; + +/* + * Heap allocated during initialized - one entry per fd + */ +typedef struct { + pthread_mutex_t lock; /* fd lock */ + threadEntry_t *threads; /* threads blocked on fd */ +} fdEntry_t; + +/* + * Signal to unblock thread + */ +static int sigWakeup = (SIGRTMAX - 1); + +/* + * The fd table and the number of file descriptors + */ +static fdEntry_t *fdTable = NULL; +static int fdCount = 0; + +/* + * Null signal handler + */ +static void sig_wakeup(int sig) { +} + +/* + * Initialization routine (executed when library is loaded) + * Allocate fd tables and sets up signal handler. + * + * On AIX we don't have __attribute((constructor)) so we need to initialize + * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c') + */ +void aix_close_init() { + struct rlimit nbr_files; + sigset_t sigset; + struct sigaction sa; + + /* Check already initialized */ + if (fdCount > 0 && fdTable != NULL) { + return; + } + + /* + * Allocate table based on the maximum number of + * file descriptors. + */ + if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { + fprintf(stderr, "library initialization failed - " + "unable to get max # of allocated fds\n"); + abort(); + } + fdCount = nbr_files.rlim_max; + /* + * We have a conceptual problem here, when the number of files is + * unlimited. As a kind of workaround, we ensure the table is big + * enough for handle even a large number of files. Since SAP itself + * recommends a limit of 32000 files, we just use 64000 as 'infinity'. + */ + if (nbr_files.rlim_max == RLIM_INFINITY) { + fdCount = 64000; + } + fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (fdTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor table - out of memory"); + abort(); + } + + { + int i; + for (i=0; i < fdCount; i++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } + } + + /* + * Setup the signal handler + */ + sa.sa_handler = sig_wakeup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sigWakeup, &sa, NULL); + + sigemptyset(&sigset); + sigaddset(&sigset, sigWakeup); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +/* + * Return the fd table for this fd or NULL is fd out + * of range. + */ +static inline fdEntry_t *getFdEntry(int fd) +{ + if (fd < 0 || fd >= fdCount) { + return NULL; + } + return &fdTable[fd]; +} + +/* + * Start a blocking operation :- + * Insert thread onto thread list for the fd. + */ +static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) +{ + self->thr = pthread_self(); + self->intr = 0; + + pthread_mutex_lock(&(fdEntry->lock)); + { + self->next = fdEntry->threads; + fdEntry->threads = self; + } + pthread_mutex_unlock(&(fdEntry->lock)); +} + +/* + * End a blocking operation :- + * Remove thread from thread list for the fd + * If fd has been interrupted then set errno to EBADF + */ +static inline void endOp + (fdEntry_t *fdEntry, threadEntry_t *self) +{ + int orig_errno = errno; + pthread_mutex_lock(&(fdEntry->lock)); + { + threadEntry_t *curr, *prev=NULL; + curr = fdEntry->threads; + while (curr != NULL) { + if (curr == self) { + if (curr->intr) { + orig_errno = EBADF; + } + if (prev == NULL) { + fdEntry->threads = curr->next; + } else { + prev->next = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + } + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; +} + +/* + * Close or dup2 a file descriptor ensuring that all threads blocked on + * the file descriptor are notified via a wakeup signal. + * + * fd1 < 0 => close(fd2) + * fd1 >= 0 => dup2(fd1, fd2) + * + * Returns -1 with errno set if operation fails. + */ +static int closefd(int fd1, int fd2) { + int rv, orig_errno; + fdEntry_t *fdEntry = getFdEntry(fd2); + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Lock the fd to hold-off additional I/O on this fd. + */ + pthread_mutex_lock(&(fdEntry->lock)); + + { + /* + * And close/dup the file descriptor + * (restart if interrupted by signal) + */ + do { + if (fd1 < 0) { + rv = close(fd2); + } else { + rv = dup2(fd1, fd2); + } + } while (rv == -1 && errno == EINTR); + + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + curr = curr->next; + } + } + + /* + * Unlock without destroying errno + */ + orig_errno = errno; + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; + + return rv; +} + +/* + * Wrapper for dup2 - same semantics as dup2 system call except + * that any threads blocked in an I/O system call on fd2 will be + * preempted and return -1/EBADF; + */ +int NET_Dup2(int fd, int fd2) { + if (fd < 0) { + errno = EBADF; + return -1; + } + return closefd(fd, fd2); +} + +/* + * Wrapper for close - same semantics as close system call + * except that any threads blocked in an I/O on fd will be + * preempted and the I/O system call will return -1/EBADF. + */ +int NET_SocketClose(int fd) { + return closefd(-1, fd); +} + +/************** Basic I/O operations here ***************/ + +/* + * Macro to perform a blocking IO operation. Restarts + * automatically if interrupted by signal (other than + * our wakeup signal) + */ +#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ + int ret; \ + threadEntry_t self; \ + fdEntry_t *fdEntry = getFdEntry(FD); \ + if (fdEntry == NULL) { \ + errno = EBADF; \ + return -1; \ + } \ + do { \ + startOp(fdEntry, &self); \ + ret = FUNC; \ + endOp(fdEntry, &self); \ + } while (ret == -1 && errno == EINTR); \ + return ret; \ +} + +int NET_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, int *fromlen) { + socklen_t socklen = *fromlen; + BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) ); + *fromlen = socklen; +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen) { + BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); +} + +int NET_Accept(int s, struct sockaddr *addr, int *addrlen) { + socklen_t socklen = *addrlen; + BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) ); + *addrlen = socklen; +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); +} + +#ifndef USE_SELECT +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); +} +#else +int NET_Select(int s, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) { + BLOCKING_IO_RETURN_INT( s-1, + select(s, readfds, writefds, exceptfds, timeout) ); +} +#endif + +/* + * Wrapper for poll(s, timeout). + * Auto restarts with adjusted timeout if interrupted by + * signal other than our wakeup signal. + */ +int NET_Timeout(int s, long timeout) { + long prevtime = 0, newtime; + struct timeval t; + fdEntry_t *fdEntry = getFdEntry(s); + + /* + * Check that fd hasn't been closed. + */ + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Pick up current time as may need to adjust timeout + */ + if (timeout > 0) { + gettimeofday(&t, NULL); + prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; + } + + for(;;) { + struct pollfd pfd; + int rv; + threadEntry_t self; + + /* + * Poll the fd. If interrupted by our wakeup signal + * errno will be set to EBADF. + */ + pfd.fd = s; + pfd.events = POLLIN | POLLERR; + + startOp(fdEntry, &self); + rv = poll(&pfd, 1, timeout); + endOp(fdEntry, &self); + + /* + * If interrupted then adjust timeout. If timeout + * has expired return 0 (indicating timeout expired). + */ + if (rv < 0 && errno == EINTR) { + if (timeout > 0) { + gettimeofday(&t, NULL); + newtime = t.tv_sec * 1000 + t.tv_usec / 1000; + timeout -= newtime - prevtime; + if (timeout <= 0) { + return 0; + } + prevtime = newtime; + } + } else { + return rv; + } + + } +} diff --git a/src/aix/native/sun/nio/ch/AixPollPort.c b/src/aix/native/sun/nio/ch/AixPollPort.c new file mode 100644 --- /dev/null +++ b/src/aix/native/sun/nio/ch/AixPollPort.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 SAP AG. 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_AixPollPort.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Initially copied from src/solaris/native/sun/nio/ch/nio_util.h */ +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + +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_AixPollPort_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_AixPollPort_eventSize(JNIEnv* env, jclass this) { + return sizeof(struct pollfd); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_AixPollPort_eventsOffset(JNIEnv* env, jclass this) { + return offsetof(struct pollfd, events); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_AixPollPort_reventsOffset(JNIEnv* env, jclass this) { + return offsetof(struct pollfd, revents); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_AixPollPort_fdOffset(JNIEnv* env, jclass this) { + return offsetof(struct pollfd, fd); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_AixPollPort_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_AixPollPort_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_AixPollPort_pollsetPoll(JNIEnv *env, jclass c, + jint ps, jlong address, jint numfds) { + struct pollfd *events = jlong_to_ptr(address); + int res; + + RESTARTABLE(_pollset_poll(ps, events, numfds, -1), res); + if (res < 0) { + JNU_ThrowIOExceptionWithLastError(env, "pollset_poll failed"); + } + return res; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_AixPollPort_pollsetDestroy(JNIEnv *env, jclass c, jint ps) { + int res; + RESTARTABLE(_pollset_destroy((pollset_t)ps), res); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_AixPollPort_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_AixPollPort_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_AixPollPort_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_AixPollPort_close0(JNIEnv *env, jclass c, jint fd) { + int res; + RESTARTABLE(close(fd), res); +} diff --git a/src/aix/native/sun/nio/fs/AixNativeDispatcher.c b/src/aix/native/sun/nio/fs/AixNativeDispatcher.c new file mode 100644 --- /dev/null +++ b/src/aix/native/sun/nio/fs/AixNativeDispatcher.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. 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 +#include +#include +#include + +#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 jint JNICALL +Java_sun_nio_fs_AixNativeDispatcher_init(JNIEnv* env, jclass this) +{ + jint flags = 0; + jclass clazz; + + clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); + if (clazz == NULL) { + return 0; + } + entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); + entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); + entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); + entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); + entry_cls = (*env)->NewGlobalRef(env, clazz); + + return 0; +} + +/** + * 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); + 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; +} diff --git a/src/aix/native/sun/tools/attach/AixVirtualMachine.c b/src/aix/native/sun/tools/attach/AixVirtualMachine.c new file mode 100644 --- /dev/null +++ b/src/aix/native/sun/tools/attach/AixVirtualMachine.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 SAP AG. 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Based on 'LinuxVirtualMachine.c'. Non-relevant code has been removed and all + * occurrences of the string "Linux" have been replaced by "Aix". + */ + +#include "sun_tools_attach_AixVirtualMachine.h" + +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + + +/* + * Class: sun_tools_attach_AixVirtualMachine + * Method: socket + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_socket + (JNIEnv *env, jclass cls) +{ + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + JNU_ThrowIOExceptionWithLastError(env, "socket"); + } + /* added time out values */ + else { + struct timeval tv; + tv.tv_sec = 2 * 60; + tv.tv_usec = 0; + + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)); + } + return (jint)fd; +} + +/* + * Class: sun_tools_attach_AixVirtualMachine + * Method: connect + * Signature: (ILjava/lang/String;)I + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_connect + (JNIEnv *env, jclass cls, jint fd, jstring path) +{ + jboolean isCopy; + const char* p = GetStringPlatformChars(env, path, &isCopy); + if (p != NULL) { + struct sockaddr_un addr; + int err = 0; + + /* added missing structure initialization */ + memset(&addr,0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, p); + /* We must call bind with the actual socketaddr length. This is obligatory for AS400. */ + if (connect(fd, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) { + err = errno; + } + + if (isCopy) { + JNU_ReleaseStringPlatformChars(env, path, p); + } + + /* + * If the connect failed then we throw the appropriate exception + * here (can't throw it before releasing the string as can't call + * JNI with pending exception) + */ + if (err != 0) { + if (err == ENOENT) { + JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL); + } else { + char* msg = strdup(strerror(err)); + JNU_ThrowIOException(env, msg); + if (msg != NULL) { + free(msg); + } + } + } + } +} + + +/* + * Structure and callback function used to send a QUIT signal to all + * children of a given process + */ +typedef struct { + pid_t ppid; +} SendQuitContext; + +static void SendQuitCallback(const pid_t pid, void* user_data) { + SendQuitContext* context = (SendQuitContext*)user_data; + pid_t parent = getParent(pid); + if (parent == context->ppid) { + kill(pid, SIGQUIT); + } +} + +/* + * Class: sun_tools_attach_AixVirtualMachine + * Method: sendQuitTo + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_sendQuitTo + (JNIEnv *env, jclass cls, jint pid) +{ + if (kill((pid_t)pid, SIGQUIT)) { + JNU_ThrowIOExceptionWithLastError(env, "kill"); + } +} + +/* + * Class: sun_tools_attach_AixVirtualMachine + * Method: checkPermissions + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_checkPermissions + (JNIEnv *env, jclass cls, jstring path) +{ + jboolean isCopy; + const char* p = GetStringPlatformChars(env, path, &isCopy); + if (p != NULL) { + struct stat64 sb; + uid_t uid, gid; + int res; + /* added missing initialization of the stat64 buffer */ + memset(&sb, 0, sizeof(struct stat64)); + + /* + * Check that the path is owned by the effective uid/gid of this + * process. Also check that group/other access is not allowed. + */ + uid = geteuid(); + gid = getegid(); + + res = stat64(p, &sb); + if (res != 0) { + /* save errno */ + res = errno; + } + + /* release p here before we throw an I/O exception */ + if (isCopy) { + JNU_ReleaseStringPlatformChars(env, path, p); + } + + if (res == 0) { + if ( (sb.st_uid != uid) || (sb.st_gid != gid) || + ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) { + JNU_ThrowIOException(env, "well-known file is not secure"); + } + } else { + char* msg = strdup(strerror(res)); + JNU_ThrowIOException(env, msg); + if (msg != NULL) { + free(msg); + } + } + } +} + +/* + * Class: sun_tools_attach_AixVirtualMachine + * Method: close + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_close + (JNIEnv *env, jclass cls, jint fd) +{ + int res; + /* Fixed deadlock when this call of close by the client is not seen by the attach server + * which has accepted the (very short) connection already and is waiting for the request. But read don't get a byte, + * because the close is lost without shutdown. + */ + shutdown(fd, 2); + RESTARTABLE(close(fd), res); +} + +/* + * Class: sun_tools_attach_AixVirtualMachine + * Method: read + * Signature: (I[BI)I + */ +JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_read + (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen) +{ + unsigned char buf[128]; + size_t len = sizeof(buf); + ssize_t n; + + size_t remaining = (size_t)(baLen - off); + if (len > remaining) { + len = remaining; + } + + RESTARTABLE(read(fd, buf+off, len), n); + if (n == -1) { + JNU_ThrowIOExceptionWithLastError(env, "read"); + } else { + if (n == 0) { + n = -1; // EOF + } else { + (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf+off)); + } + } + return n; +} + +/* + * Class: sun_tools_attach_AixVirtualMachine + * Method: write + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_write + (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen) +{ + size_t remaining = bufLen; + do { + unsigned char buf[128]; + size_t len = sizeof(buf); + int n; + + if (len > remaining) { + len = remaining; + } + (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf); + + RESTARTABLE(write(fd, buf, len), n); + if (n > 0) { + off += n; + remaining -= n; + } else { + JNU_ThrowIOExceptionWithLastError(env, "write"); + return; + } + + } while (remaining > 0); +} diff --git a/src/aix/porting/porting_aix.c b/src/aix/porting/porting_aix.c new file mode 100644 --- /dev/null +++ b/src/aix/porting/porting_aix.c @@ -0,0 +1,86 @@ +/* + * Copyright 2012, 2013 SAP AG. 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 +#include +#include + +#include "porting_aix.h" + +static unsigned char dladdr_buffer[0x4000]; + +static void fill_dll_info(void) { + int rc = loadquery(L_GETINFO,dladdr_buffer, sizeof(dladdr_buffer)); + if (rc == -1) { + fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno)); + fflush(stderr); + } +} + +static int dladdr_dont_reload(void* addr, Dl_info* info) { + const struct ld_info* p = (struct ld_info*) dladdr_buffer; + info->dli_fbase = 0; info->dli_fname = 0; + info->dli_sname = 0; info->dli_saddr = 0; + for (;;) { + if (addr >= p->ldinfo_textorg && + addr < (((char*)p->ldinfo_textorg) + p->ldinfo_textsize)) { + info->dli_fname = p->ldinfo_filename; + info->dli_fbase = p->ldinfo_textorg; + return 1; /* [sic] */ + } + if (!p->ldinfo_next) { + break; + } + p = (struct ld_info*)(((char*)p) + p->ldinfo_next); + } + return 0; /* [sic] */ +} + +#ifdef __cplusplus +extern "C" +#endif +int dladdr(void *addr, Dl_info *info) { + static int loaded = 0; + if (!loaded) { + fill_dll_info(); + loaded = 1; + } + if (!addr) { + return 0; /* [sic] */ + } + /* Address could be AIX function descriptor? */ + void* const addr0 = *( (void**) addr ); + int rc = dladdr_dont_reload(addr, info); + if (rc == 0) { + rc = dladdr_dont_reload(addr0, info); + if (rc == 0) { /* [sic] */ + fill_dll_info(); /* refill, maybe loadquery info is outdated */ + rc = dladdr_dont_reload(addr, info); + if (rc == 0) { + rc = dladdr_dont_reload(addr0, info); + } + } + } + return rc; +} diff --git a/src/aix/porting/porting_aix.h b/src/aix/porting/porting_aix.h new file mode 100644 --- /dev/null +++ b/src/aix/porting/porting_aix.h @@ -0,0 +1,59 @@ +/* + * Copyright 2012, 2013 SAP AG. 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. + * + */ + +/* + * Header file to contain porting-relevant code which does not have a + * home anywhere else. + * This is intially based on hotspot/src/os/aix/vm/{loadlib,porting}_aix.{hpp,cpp} + */ + +/* + * Aix' own version of dladdr(). + * This function tries to mimick dladdr(3) on Linux + * (see http://linux.die.net/man/3/dladdr) + * dladdr(3) is not POSIX but a GNU extension, and is not available on AIX. + * + * Differences between AIX dladdr and Linux dladdr: + * + * 1) Dl_info.dli_fbase: can never work, is disabled. + * 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 */ + void *dli_fbase; /* doesn't make sence on AIX */ + const char *dli_sname; /* symbol name; "" if not known */ + void *dli_saddr; /* address of *entry* of function; not function descriptor; */ +} Dl_info; + +#ifdef __cplusplus +extern "C" +#endif +int dladdr(void *addr, Dl_info *info); diff --git a/src/share/bin/jli_util.h b/src/share/bin/jli_util.h --- a/src/share/bin/jli_util.h +++ b/src/share/bin/jli_util.h @@ -85,6 +85,9 @@ #ifdef MACOSX #define JLI_Lseek lseek #endif +#ifdef _AIX +#define JLI_Lseek lseek +#endif #endif /* _WIN32 */ /* diff --git a/src/share/lib/security/java.security-aix b/src/share/lib/security/java.security-aix new file mode 100644 --- /dev/null +++ b/src/share/lib/security/java.security-aix @@ -0,0 +1,497 @@ +# +# This is the "master security properties file". +# +# An alternate java.security properties file may be specified +# from the command line via the system property +# +# -Djava.security.properties= +# +# This properties file appends to the master security properties file. +# If both properties files specify values for the same key, the value +# from the command-line properties file is selected, as it is the last +# one loaded. +# +# Also, if you specify +# +# -Djava.security.properties== (2 equals), +# +# then that properties file completely overrides the master security +# properties file. +# +# To disable the ability to specify an additional properties file from +# the command line, set the key security.overridePropertiesFile +# to false in the master security properties file. It is set to true +# by default. + +# In this file, various security properties are set for use by +# java.security classes. This is where users can statically register +# Cryptography Package Providers ("providers" for short). The term +# "provider" refers to a package or set of packages that supply a +# concrete implementation of a subset of the cryptography aspects of +# the Java Security API. A provider may, for example, implement one or +# more digital signature algorithms or message digest algorithms. +# +# Each provider must implement a subclass of the Provider class. +# To register a provider in this master security properties file, +# specify the Provider subclass name and priority in the format +# +# security.provider.= +# +# This declares a provider, and specifies its preference +# order n. The preference order is the order in which providers are +# searched for requested algorithms (when no specific provider is +# requested). The order is 1-based; 1 is the most preferred, followed +# by 2, and so on. +# +# must specify the subclass of the Provider class whose +# constructor sets the values of various properties that are required +# for the Java Security API to look up the algorithms or other +# facilities implemented by the provider. +# +# There must be at least one provider specification in java.security. +# There is a default provider that comes standard with the JDK. It +# is called the "SUN" provider, and its Provider subclass +# named Sun appears in the sun.security.provider package. Thus, the +# "SUN" provider is registered via the following: +# +# security.provider.1=sun.security.provider.Sun +# +# (The number 1 is used for the default provider.) +# +# Note: Providers can be dynamically registered instead by calls to +# either the addProvider or insertProviderAt method in the Security +# class. + +# +# List of providers and their preference orders (see above): +# +security.provider.1=sun.security.provider.Sun +security.provider.2=sun.security.rsa.SunRsaSign +security.provider.3=sun.security.ec.SunEC +security.provider.4=com.sun.net.ssl.internal.ssl.Provider +security.provider.5=com.sun.crypto.provider.SunJCE +security.provider.6=sun.security.jgss.SunProvider +security.provider.7=com.sun.security.sasl.Provider +security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI +security.provider.9=sun.security.smartcardio.SunPCSC + +# +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "SHA1PRNG" and +# "NativePRNG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Solaris/Linux/MacOS), the +# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from +# special device files such as file:/dev/random. +# +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# SHA1PRNG: +# the traditional system/thread activity algorithm will be used. +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. +# +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass +# +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# SHA1PRNG in the Sun provider. +# +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +securerandom.strongAlgorithms=NativePRNGBlocking:SUN + +# +# Class to instantiate as the javax.security.auth.login.Configuration +# provider. +# +login.configuration.provider=sun.security.provider.ConfigFile + +# +# Default login configuration file +# +#login.config.url.1=file:${user.home}/.java.login.config + +# +# Class to instantiate as the system Policy. This is the name of the class +# that will be used as the Policy object. +# +policy.provider=sun.security.provider.PolicyFile + +# The default is to have a single system-wide policy file, +# and a policy file in the user's home directory. +policy.url.1=file:${java.home}/lib/security/java.policy +policy.url.2=file:${user.home}/.java.policy + +# whether or not we expand properties in the policy file +# if this is set to false, properties (${...}) will not be expanded in policy +# files. +policy.expandProperties=true + +# whether or not we allow an extra policy to be passed on the command line +# with -Djava.security.policy=somefile. Comment out this line to disable +# this feature. +policy.allowSystemProperty=true + +# whether or not we look into the IdentityScope for trusted Identities +# when encountering a 1.1 signed JAR file. If the identity is found +# and is trusted, we grant it AllPermission. +policy.ignoreIdentityScope=false + +# +# Default keystore type. +# +keystore.type=jks + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageAccess unless the +# corresponding RuntimePermission ("accessClassInPackage."+package) has +# been granted. +package.access=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.,\ + com.sun.media.sound.,\ + com.sun.proxy.,\ + com.sun.corba.se.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.security.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ + com.oracle.xmlns.internal.,\ + com.oracle.webservices.internal.,\ + oracle.jrockit.jfr.,\ + org.jcp.xml.dsig.internal.,\ + jdk.internal.,\ + jdk.nashorn.internal.,\ + jdk.nashorn.tools. + + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageDefinition unless the +# corresponding RuntimePermission ("defineClassInPackage."+package) has +# been granted. +# +# by default, none of the class loaders supplied with the JDK call +# checkPackageDefinition. +# +package.definition=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.,\ + com.sun.media.sound.,\ + com.sun.proxy.,\ + com.sun.corba.se.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.security.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ + com.oracle.xmlns.internal.,\ + com.oracle.webservices.internal.,\ + oracle.jrockit.jfr.,\ + org.jcp.xml.dsig.internal.,\ + jdk.internal.,\ + jdk.nashorn.internal.,\ + jdk.nashorn.tools. + + +# +# Determines whether this properties file can be appended to +# or overridden on the command line via -Djava.security.properties +# +security.overridePropertiesFile=true + +# +# Determines the default key and trust manager factory algorithms for +# the javax.net.ssl package. +# +ssl.KeyManagerFactory.algorithm=SunX509 +ssl.TrustManagerFactory.algorithm=PKIX + +# +# The Java-level namelookup cache policy for successful lookups: +# +# any negative value: caching forever +# any positive value: the number of seconds to cache an address for +# zero: do not cache +# +# default value is forever (FOREVER). For security reasons, this +# caching is made forever when a security manager is set. When a security +# manager is not set, the default behavior in this implementation +# is to cache for 30 seconds. +# +# NOTE: setting this to anything other than the default value can have +# serious security implications. Do not set it unless +# you are sure you are not exposed to DNS spoofing attack. +# +#networkaddress.cache.ttl=-1 + +# The Java-level namelookup cache policy for failed lookups: +# +# any negative value: cache forever +# any positive value: the number of seconds to cache negative lookup results +# zero: do not cache +# +# In some Microsoft Windows networking environments that employ +# the WINS name service in addition to DNS, name service lookups +# that fail may take a noticeably long time to return (approx. 5 seconds). +# For this reason the default caching policy is to maintain these +# results for 10 seconds. +# +# +networkaddress.cache.negative.ttl=10 + +# +# Properties to configure OCSP for certificate revocation checking +# + +# Enable OCSP +# +# By default, OCSP is not used for certificate revocation checking. +# This property enables the use of OCSP when set to the value "true". +# +# NOTE: SocketPermission is required to connect to an OCSP responder. +# +# Example, +# ocsp.enable=true + +# +# Location of the OCSP responder +# +# By default, the location of the OCSP responder is determined implicitly +# from the certificate being validated. This property explicitly specifies +# the location of the OCSP responder. The property is used when the +# Authority Information Access extension (defined in RFC 3280) is absent +# from the certificate or when it requires overriding. +# +# Example, +# ocsp.responderURL=http://ocsp.example.net:80 + +# +# Subject name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. In cases where +# the subject name alone is not sufficient to uniquely identify the certificate +# then both the "ocsp.responderCertIssuerName" and +# "ocsp.responderCertSerialNumber" properties must be used instead. When this +# property is set then those two properties are ignored. +# +# Example, +# ocsp.responderCertSubjectName="CN=OCSP Responder, O=XYZ Corp" + +# +# Issuer name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. When this +# property is set then the "ocsp.responderCertSerialNumber" property must also +# be set. When the "ocsp.responderCertSubjectName" property is set then this +# property is ignored. +# +# Example, +# ocsp.responderCertIssuerName="CN=Enterprise CA, O=XYZ Corp" + +# +# Serial number of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# of hexadecimal digits (colon or space separators may be present) which +# identifies a certificate in the set of certificates supplied during cert path +# validation. When this property is set then the "ocsp.responderCertIssuerName" +# property must also be set. When the "ocsp.responderCertSubjectName" property +# is set then this property is ignored. +# +# Example, +# ocsp.responderCertSerialNumber=2A:FF:00 + +# +# Policy for failed Kerberos KDC lookups: +# +# When a KDC is unavailable (network error, service failure, etc), it is +# put inside a blacklist and accessed less often for future requests. The +# value (case-insensitive) for this policy can be: +# +# tryLast +# KDCs in the blacklist are always tried after those not on the list. +# +# tryLess[:max_retries,timeout] +# KDCs in the blacklist are still tried by their order in the configuration, +# but with smaller max_retries and timeout values. max_retries and timeout +# are optional numerical parameters (default 1 and 5000, which means once +# and 5 seconds). Please notes that if any of the values defined here is +# more than what is defined in krb5.conf, it will be ignored. +# +# Whenever a KDC is detected as available, it is removed from the blacklist. +# The blacklist is reset when krb5.conf is reloaded. You can add +# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is +# reloaded whenever a JAAS authentication is attempted. +# +# Example, +# krb5.kdc.bad.policy = tryLast +# krb5.kdc.bad.policy = tryLess:2,2000 +krb5.kdc.bad.policy = tryLast + +# Algorithm restrictions for certification path (CertPath) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# for certification path building and validation. For example, "MD2" is +# generally no longer considered to be a secure hash algorithm. This section +# describes the mechanism for disabling algorithms based on algorithm name +# and/or key length. This includes algorithms used in certificates, as well +# as revocation information such as CRLs and signed OCSP Responses. +# +# The syntax of the disabled algorithm string is described as this Java +# BNF-style: +# DisabledAlgorithms: +# " DisabledAlgorithm { , DisabledAlgorithm } " +# +# DisabledAlgorithm: +# AlgorithmName [Constraint] +# +# AlgorithmName: +# (see below) +# +# Constraint: +# KeySizeConstraint +# +# KeySizeConstraint: +# keySize Operator DecimalInteger +# +# Operator: +# <= | < | == | != | >= | > +# +# DecimalInteger: +# DecimalDigits +# +# DecimalDigits: +# DecimalDigit {DecimalDigit} +# +# DecimalDigit: one of +# 1 2 3 4 5 6 7 8 9 0 +# +# The "AlgorithmName" is the standard algorithm name of the disabled +# algorithm. See "Java Cryptography Architecture Standard Algorithm Name +# Documentation" for information about Standard Algorithm Names. Matching +# is performed using a case-insensitive sub-element matching rule. (For +# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and +# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a +# sub-element of the certificate algorithm name, the algorithm will be +# rejected during certification path building and validation. For example, +# the assertion algorithm name "DSA" will disable all certificate algorithms +# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion +# will not disable algorithms related to "ECDSA". +# +# A "Constraint" provides further guidance for the algorithm being specified. +# The "KeySizeConstraint" requires a key of a valid size range if the +# "AlgorithmName" is of a key algorithm. The "DecimalInteger" indicates the +# key size specified in number of bits. For example, "RSA keySize <= 1024" +# indicates that any RSA key with key size less than or equal to 1024 bits +# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates +# that any RSA key with key size less than 1024 or greater than 2048 should +# be disabled. Note that the "KeySizeConstraint" only makes sense to key +# algorithms. +# +# Note: This property is currently used by Oracle's PKIX implementation. It +# is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 +# +# +jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024 + +# Algorithm restrictions for Secure Socket Layer/Transport Layer Security +# (SSL/TLS) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# when using SSL/TLS. This section describes the mechanism for disabling +# algorithms during SSL/TLS security parameters negotiation, including cipher +# suites selection, peer authentication and key exchange mechanisms. +# +# For PKI-based peer authentication and key exchange mechanisms, this list +# of disabled algorithms will also be checked during certification path +# building and validation, including algorithms used in certificates, as +# well as revocation information such as CRLs and signed OCSP Responses. +# This is in addition to the jdk.certpath.disabledAlgorithms property above. +# +# See the specification of "jdk.certpath.disabledAlgorithms" for the +# syntax of the disabled algorithm string. +# +# Note: This property is currently used by Oracle's JSSE implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 + diff --git a/src/share/native/common/check_code.c b/src/share/native/common/check_code.c --- a/src/share/native/common/check_code.c +++ b/src/share/native/common/check_code.c @@ -90,6 +90,41 @@ #include "classfile_constants.h" #include "opcodes.in_out" +/* On AIX malloc(0) and calloc(0, ...) return a NULL pointer, which is legal, + * but the code here does not handles it. So we wrap the methods and return non-NULL + * pointers even if we allocate 0 bytes. + */ +#ifdef _AIX +static int aix_dummy; +static void* aix_malloc(size_t len) { + if (len == 0) { + return &aix_dummy; + } + return malloc(len); +} + +static void* aix_calloc(size_t n, size_t size) { + if (n == 0) { + return &aix_dummy; + } + return calloc(n, size); +} + +static void aix_free(void* p) { + if (p == &aix_dummy) { + return; + } + free(p); +} + +#undef malloc +#undef calloc +#undef free +#define malloc aix_malloc +#define calloc aix_calloc +#define free aix_free +#endif + #ifdef __APPLE__ /* use setjmp/longjmp versions that do not save/restore the signal mask */ #define setjmp _setjmp diff --git a/src/share/native/java/net/net_util.c b/src/share/native/java/net/net_util.c --- a/src/share/native/java/net/net_util.c +++ b/src/share/native/java/net/net_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ supporting socket APIs are available */ IPv6_available = IPv6_supported() & (!preferIPv4Stack); - initLocalAddrTable (); + platformInit(); parseExclusiveBindProperty(env); return JNI_VERSION_1_2; diff --git a/src/share/native/java/net/net_util.h b/src/share/native/java/net/net_util.h --- a/src/share/native/java/net/net_util.h +++ b/src/share/native/java/net/net_util.h @@ -140,7 +140,7 @@ JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port); -void initLocalAddrTable (); +void platformInit(); void parseExclusiveBindProperty(JNIEnv *env); void diff --git a/src/share/native/sun/awt/medialib/mlib_sys.c b/src/share/native/sun/awt/medialib/mlib_sys.c --- a/src/share/native/sun/awt/medialib/mlib_sys.c +++ b/src/share/native/sun/awt/medialib/mlib_sys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,10 +86,13 @@ void *__mlib_malloc(mlib_u32 size) { -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(AIX) /* * Currently, all MS C compilers for Win32 platforms default to 8 byte * alignment. -- from stdlib.h of MS VC++5.0. + * + * On AIX, the malloc subroutine returns a pointer to space suitably + * aligned for the storage of any type of object (see 'man malloc'). */ return (void *) malloc(size); #elif defined(MACOSX) diff --git a/src/share/native/sun/awt/medialib/mlib_types.h b/src/share/native/sun/awt/medialib/mlib_types.h --- a/src/share/native/sun/awt/medialib/mlib_types.h +++ b/src/share/native/sun/awt/medialib/mlib_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ typedef float mlib_f32; typedef double mlib_d64; -#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__GNUC__) +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__GNUC__) || defined(_AIX) #include #include diff --git a/src/share/native/sun/font/layout/KernTable.cpp b/src/share/native/sun/font/layout/KernTable.cpp --- a/src/share/native/sun/font/layout/KernTable.cpp +++ b/src/share/native/sun/font/layout/KernTable.cpp @@ -39,7 +39,7 @@ #include -#define DEBUG 0 +#define DEBUG_KERN_TABLE 0 U_NAMESPACE_BEGIN @@ -99,14 +99,14 @@ : pairsSwapped(NULL), fTable(base) { if(LE_FAILURE(success) || (fTable.isEmpty())) { -#if DEBUG +#if DEBUG_KERN_TABLE fprintf(stderr, "no kern data\n"); #endif return; } LEReferenceTo header(fTable, success); -#if DEBUG +#if DEBUG_KERN_TABLE // dump first 32 bytes of header for (int i = 0; i < 64; ++i) { fprintf(stderr, "%0.2x ", ((const char*)header.getAlias())[i]&0xff); @@ -171,7 +171,7 @@ fprintf(stderr, " searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift); fprintf(stderr, "[[ ignored font table entries: range %d selector %d shift %d ]]\n", SWAPW(table->searchRange), SWAPW(table->entrySelector), SWAPW(table->rangeShift)); #endif -#if DEBUG +#if DEBUG_KERN_TABLE fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairsSwapped); fprintf(stderr, " searchRange(pairs): %d entrySelector: %d rangeShift(pairs): %d\n", @@ -242,7 +242,7 @@ p = tp; } -#if DEBUG +#if DEBUG_KERN_TABLE fprintf(stderr, "binary search for %0.8x\n", key); #endif @@ -251,13 +251,13 @@ probe >>= 1; tp = (const PairInfo*)(p + (probe/KERN_PAIRINFO_SIZE)); le_uint32 tkey = tp->key; -#if DEBUG +#if DEBUG_KERN_TABLE fprintf(stdout, " %.3d (%0.8x)\n", (tp - pairsSwapped), tkey); #endif if (tkey <= key) { if (tkey == key) { le_int16 value = SWAPW(tp->value); -#if DEBUG +#if DEBUG_KERN_TABLE fprintf(stdout, "binary found kerning pair %x:%x at %d, value: 0x%x (%g)\n", storage[i-1], storage[i], i, value & 0xffff, font->xUnitsToPoints(value)); fflush(stdout); diff --git a/src/share/native/sun/security/ec/impl/ecc_impl.h b/src/share/native/sun/security/ec/impl/ecc_impl.h --- a/src/share/native/sun/security/ec/impl/ecc_impl.h +++ b/src/share/native/sun/security/ec/impl/ecc_impl.h @@ -65,6 +65,13 @@ typedef enum boolean { B_FALSE, B_TRUE } boolean_t; #endif /* _ALLBSD_SOURCE */ +#ifdef AIX +#define B_FALSE FALSE +#define B_TRUE TRUE +typedef unsigned char uint8_t; +typedef unsigned long ulong_t; +#endif /* AIX */ + #ifdef _WIN32 typedef unsigned char uint8_t; typedef unsigned long ulong_t; diff --git a/src/solaris/back/exec_md.c b/src/solaris/back/exec_md.c --- a/src/solaris/back/exec_md.c +++ b/src/solaris/back/exec_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,8 @@ #include "sys.h" #include "util.h" -#if defined(LINUX) || defined(_ALLBSD_SOURCE) - /* Linux */ +#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX) + /* Linux, BSD, AIX */ #define FORK() fork() #else /* Solaris (make sure we always get the POSIX-specified behavior) */ diff --git a/src/solaris/bin/java_md_solinux.c b/src/solaris/bin/java_md_solinux.c --- a/src/solaris/bin/java_md_solinux.c +++ b/src/solaris/bin/java_md_solinux.c @@ -41,7 +41,11 @@ #define JVM_DLL "libjvm.so" #define JAVA_DLL "libjava.so" +#ifdef AIX +#define LD_LIBRARY_PATH "LIBPATH" +#else #define LD_LIBRARY_PATH "LD_LIBRARY_PATH" +#endif /* help jettison the LD_LIBRARY_PATH settings in the future */ #ifndef SETENV_REQUIRED @@ -287,6 +291,11 @@ char *dmllp = NULL; char *p; /* a utility pointer */ +#ifdef AIX + /* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */ + return JNI_TRUE; +#endif + llp = getenv("LD_LIBRARY_PATH"); #ifdef __solaris__ dmllp = (CURRENT_DATA_MODEL == 32) @@ -598,7 +607,7 @@ * If not on Solaris, assume only a single LD_LIBRARY_PATH * variable. */ - runpath = getenv("LD_LIBRARY_PATH"); + runpath = getenv(LD_LIBRARY_PATH); #endif /* __solaris__ */ /* runpath contains current effective LD_LIBRARY_PATH setting */ @@ -606,8 +615,12 @@ jvmpath = JLI_StringDup(jvmpath); new_runpath = JLI_MemAlloc(((runpath != NULL) ? JLI_StrLen(runpath) : 0) + 2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) + +#ifdef AIX + /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */ + JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib//jli:") + +#endif JLI_StrLen(jvmpath) + 52); - newpath = new_runpath + JLI_StrLen("LD_LIBRARY_PATH="); + newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "="); /* @@ -619,9 +632,12 @@ if (lastslash) *lastslash = '\0'; - sprintf(new_runpath, "LD_LIBRARY_PATH=" + sprintf(new_runpath, LD_LIBRARY_PATH "=" "%s:" "%s/lib/%s:" +#ifdef AIX + "%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */ +#endif "%s/../lib/%s", jvmpath, #ifdef DUAL_MODE @@ -629,6 +645,9 @@ jrepath, GetArchPath(wanted) #else /* !DUAL_MODE */ jrepath, arch, +#ifdef AIX + jrepath, arch, +#endif jrepath, arch #endif /* DUAL_MODE */ ); @@ -1000,7 +1019,7 @@ int ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) { int rslt; -#ifdef __linux__ +#ifndef __solaris__ pthread_t tid; pthread_attr_t attr; pthread_attr_init(&attr); @@ -1025,7 +1044,7 @@ } pthread_attr_destroy(&attr); -#else /* ! __linux__ */ +#else /* __solaris__ */ thread_t tid; long flags = 0; if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) { @@ -1036,7 +1055,7 @@ /* See above. Continue in current thread if thr_create() failed */ rslt = continuation(args); } -#endif /* __linux__ */ +#endif /* !__solaris__ */ return rslt; } diff --git a/src/solaris/bin/java_md_solinux.h b/src/solaris/bin/java_md_solinux.h --- a/src/solaris/bin/java_md_solinux.h +++ b/src/solaris/bin/java_md_solinux.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,23 +45,19 @@ * A collection of useful strings. One should think of these as #define * entries, but actual strings can be more efficient (with many compilers). */ -#ifdef __linux__ +#ifdef __solaris__ +static const char *system_dir = "/usr/jdk"; +static const char *user_dir = "/jdk"; +#else /* !__solaris__, i.e. Linux, AIX,.. */ static const char *system_dir = "/usr/java"; static const char *user_dir = "/java"; -#else /* Solaris */ -static const char *system_dir = "/usr/jdk"; -static const char *user_dir = "/jdk"; #endif #include -#ifdef __linux__ +#ifdef __solaris__ +#include +#else #include -#else -#include #endif -#define JVM_DLL "libjvm.so" -#define JAVA_DLL "libjava.so" -#define LD_LIBRARY_PATH "LD_LIBRARY_PATH" - #endif /* JAVA_MD_SOLINUX_H */ diff --git a/src/solaris/classes/java/lang/UNIXProcess.java.aix b/src/solaris/classes/java/lang/UNIXProcess.java.aix new file mode 100644 --- /dev/null +++ b/src/solaris/classes/java/lang/UNIXProcess.java.aix @@ -0,0 +1,419 @@ +/* + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.concurrent.Executors; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.security.AccessController; +import static java.security.AccessController.doPrivileged; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * java.lang.Process subclass in the UNIX environment. + * + * @author Mario Wolczko and Ross Knippel. + * @author Konstantin Kladko (ported to Linux) + * @author Martin Buchholz + * @author Volker Simonis (ported to AIX) + */ +final class UNIXProcess extends Process { + private static final sun.misc.JavaIOFileDescriptorAccess fdAccess + = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); + + private final int pid; + private int exitcode; + private boolean hasExited; + + private /* final */ OutputStream stdin; + private /* final */ InputStream stdout; + private /* final */ InputStream stderr; + + private static enum LaunchMechanism { + FORK(1), + POSIX_SPAWN(2); + + private int value; + LaunchMechanism(int x) {value = x;} + }; + + /* On AIX, the default is to spawn */ + private static final LaunchMechanism launchMechanism; + private static byte[] helperpath; + + private static byte[] toCString(String s) { + if (s == null) + return null; + byte[] bytes = s.getBytes(); + byte[] result = new byte[bytes.length + 1]; + System.arraycopy(bytes, 0, + result, 0, + bytes.length); + result[result.length-1] = (byte)0; + return result; + } + + static { + launchMechanism = AccessController.doPrivileged( + new PrivilegedAction() + { + public LaunchMechanism run() { + String javahome = System.getProperty("java.home"); + String osArch = System.getProperty("os.arch"); + + helperpath = toCString(javahome + "/lib/" + osArch + "/jspawnhelper"); + String s = System.getProperty( + "jdk.lang.Process.launchMechanism", "posix_spawn"); + + try { + return LaunchMechanism.valueOf(s.toUpperCase()); + } catch (IllegalArgumentException e) { + throw new Error(s + " is not a supported " + + "process launch mechanism on this platform."); + } + } + }); + } + + /* this is for the reaping thread */ + private native int waitForProcessExit(int pid); + + /** + * Create a process. Depending on the mode flag, this is done by + * one of the following mechanisms. + * - fork(2) and exec(2) + * - clone(2) and exec(2) + * - vfork(2) and exec(2) + * + * @param fds an array of three file descriptors. + * Indexes 0, 1, and 2 correspond to standard input, + * standard output and standard error, respectively. On + * input, a value of -1 means to create a pipe to connect + * child and parent processes. On output, a value which + * is not -1 is the parent pipe fd corresponding to the + * pipe which has been created. An element of this array + * is -1 on input if and only if it is not -1 on + * output. + * @return the pid of the subprocess + */ + private native int forkAndExec(int mode, byte[] helperpath, + byte[] prog, + byte[] argBlock, int argc, + byte[] envBlock, int envc, + byte[] dir, + int[] fds, + boolean redirectErrorStream) + throws IOException; + + /** + * The thread factory used to create "process reaper" daemon threads. + */ + private static class ProcessReaperThreadFactory implements ThreadFactory { + private final static ThreadGroup group = getRootThreadGroup(); + + private static ThreadGroup getRootThreadGroup() { + return doPrivileged(new PrivilegedAction () { + public ThreadGroup run() { + ThreadGroup root = Thread.currentThread().getThreadGroup(); + while (root.getParent() != null) + root = root.getParent(); + return root; + }}); + } + + public Thread newThread(Runnable grimReaper) { + // Our thread stack requirement is quite modest. + Thread t = new Thread(group, grimReaper, "process reaper", 32768); + t.setDaemon(true); + // A small attempt (probably futile) to avoid priority inversion + t.setPriority(Thread.MAX_PRIORITY); + return t; + } + } + + /** + * The thread pool of "process reaper" daemon threads. + */ + private static final Executor processReaperExecutor = + doPrivileged(new PrivilegedAction() { + public Executor run() { + return Executors.newCachedThreadPool + (new ProcessReaperThreadFactory()); + }}); + + UNIXProcess(final byte[] prog, + final byte[] argBlock, final int argc, + final byte[] envBlock, final int envc, + final byte[] dir, + final int[] fds, + final boolean redirectErrorStream) + throws IOException { + + pid = forkAndExec(launchMechanism.value, + helperpath, + prog, + argBlock, argc, + envBlock, envc, + dir, + fds, + redirectErrorStream); + + try { + doPrivileged(new PrivilegedExceptionAction() { + public Void run() throws IOException { + initStreams(fds); + return null; + }}); + } catch (PrivilegedActionException ex) { + throw (IOException) ex.getException(); + } + } + + static FileDescriptor newFileDescriptor(int fd) { + FileDescriptor fileDescriptor = new FileDescriptor(); + fdAccess.set(fileDescriptor, fd); + return fileDescriptor; + } + + void initStreams(int[] fds) throws IOException { + stdin = (fds[0] == -1) ? + ProcessBuilder.NullOutputStream.INSTANCE : + new ProcessPipeOutputStream(fds[0]); + + stdout = (fds[1] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new ProcessPipeInputStream(fds[1]); + + stderr = (fds[2] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new ProcessPipeInputStream(fds[2]); + + processReaperExecutor.execute(new Runnable() { + public void run() { + int exitcode = waitForProcessExit(pid); + UNIXProcess.this.processExited(exitcode); + }}); + } + + void processExited(int exitcode) { + synchronized (this) { + this.exitcode = exitcode; + hasExited = true; + notifyAll(); + } + + if (stdout instanceof ProcessPipeInputStream) + ((ProcessPipeInputStream) stdout).processExited(); + + if (stderr instanceof ProcessPipeInputStream) + ((ProcessPipeInputStream) stderr).processExited(); + + if (stdin instanceof ProcessPipeOutputStream) + ((ProcessPipeOutputStream) stdin).processExited(); + } + + public OutputStream getOutputStream() { + return stdin; + } + + public InputStream getInputStream() { + return stdout; + } + + public InputStream getErrorStream() { + return stderr; + } + + public synchronized int waitFor() throws InterruptedException { + while (!hasExited) { + wait(); + } + return exitcode; + } + + @Override + public synchronized boolean waitFor(long timeout, TimeUnit unit) + throws InterruptedException + { + if (hasExited) return true; + if (timeout <= 0) return false; + + long timeoutAsNanos = unit.toNanos(timeout); + long startTime = System.nanoTime(); + long rem = timeoutAsNanos; + + while (!hasExited && (rem > 0)) { + wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1)); + rem = timeoutAsNanos - (System.nanoTime() - startTime); + } + return hasExited; + } + + public synchronized int exitValue() { + if (!hasExited) { + throw new IllegalThreadStateException("process hasn't exited"); + } + return exitcode; + } + + private static native void destroyProcess(int pid, boolean force); + private void destroy(boolean force) { + // There is a risk that pid will be recycled, causing us to + // kill the wrong process! So we only terminate processes + // that appear to still be running. Even with this check, + // there is an unavoidable race condition here, but the window + // is very small, and OSes try hard to not recycle pids too + // soon, so this is quite safe. + synchronized (this) { + if (!hasExited) + destroyProcess(pid, force); + } + try { stdin.close(); } catch (IOException ignored) {} + try { stdout.close(); } catch (IOException ignored) {} + try { stderr.close(); } catch (IOException ignored) {} + } + + public void destroy() { + destroy(false); + } + + @Override + public Process destroyForcibly() { + destroy(true); + return this; + } + + @Override + public synchronized boolean isAlive() { + return !hasExited; + } + + private static native void init(); + + static { + init(); + } + + /** + * A buffered input stream for a subprocess pipe file descriptor + * that allows the underlying file descriptor to be reclaimed when + * the process exits, via the processExited hook. + * + * This is tricky because we do not want the user-level InputStream to be + * closed until the user invokes close(), and we need to continue to be + * able to read any buffered data lingering in the OS pipe buffer. + */ + static class ProcessPipeInputStream extends BufferedInputStream { + private final Object closeLock = new Object(); + + ProcessPipeInputStream(int fd) { + super(new FileInputStream(newFileDescriptor(fd))); + } + + private InputStream drainInputStream(InputStream in) + throws IOException { + int n = 0; + int j; + byte[] a = null; + synchronized (closeLock) { + if (buf == null) // asynchronous close()? + return null; // discard + j = in.available(); + } + while (j > 0) { + a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); + synchronized (closeLock) { + if (buf == null) // asynchronous close()? + return null; // discard + n += in.read(a, n, j); + j = in.available(); + } + } + return (a == null) ? + ProcessBuilder.NullInputStream.INSTANCE : + new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n)); + } + + /** Called by the process reaper thread when the process exits. */ + synchronized void processExited() { + try { + InputStream in = this.in; + if (in != null) { + InputStream stragglers = drainInputStream(in); + in.close(); + this.in = stragglers; + } + } catch (IOException ignored) { } + } + + @Override + public void close() throws IOException { + // BufferedInputStream#close() is not synchronized unlike most other methods. + // Synchronizing helps avoid racing with drainInputStream(). + synchronized (closeLock) { + super.close(); + } + } + } + + /** + * A buffered output stream for a subprocess pipe file descriptor + * that allows the underlying file descriptor to be reclaimed when + * the process exits, via the processExited hook. + */ + static class ProcessPipeOutputStream extends BufferedOutputStream { + ProcessPipeOutputStream(int fd) { + super(new FileOutputStream(newFileDescriptor(fd))); + } + + /** Called by the process reaper thread when the process exits. */ + synchronized void processExited() { + OutputStream out = this.out; + if (out != null) { + try { + out.close(); + } catch (IOException ignored) { + // We know of no reason to get an IOException, but if + // we do, there's nothing else to do but carry on. + } + this.out = ProcessBuilder.NullOutputStream.INSTANCE; + } + } + } +} diff --git a/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java --- a/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java +++ b/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java @@ -68,6 +68,8 @@ return createProvider("sun.nio.ch.LinuxAsynchronousChannelProvider"); if (osname.contains("OS X")) return createProvider("sun.nio.ch.BsdAsynchronousChannelProvider"); + if (osname.equals("AIX")) + return createProvider("sun.nio.ch.AixAsynchronousChannelProvider"); throw new InternalError("platform not recognized"); } } diff --git a/src/solaris/classes/sun/nio/ch/Port.java b/src/solaris/classes/sun/nio/ch/Port.java --- a/src/solaris/classes/sun/nio/ch/Port.java +++ b/src/solaris/classes/sun/nio/ch/Port.java @@ -77,11 +77,21 @@ } /** + * Callback method for implementations that need special handling when fd is + * removed (currently only needed in the AIX-Port - see AixPollPort.java). + */ + protected void preUnregister(int fd) { + // Do nothing by default. + } + + /** * Unregister channel identified by its file descriptor */ final void unregister(int fd) { boolean checkForShutdown = false; + preUnregister(fd); + fdToChannelLock.writeLock().lock(); try { fdToChannel.remove(Integer.valueOf(fd)); diff --git a/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java b/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java --- a/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java +++ b/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -63,6 +63,8 @@ return createProvider("sun.nio.fs.LinuxFileSystemProvider"); if (osname.contains("OS X")) return createProvider("sun.nio.fs.MacOSXFileSystemProvider"); + if (osname.equals("AIX")) + return createProvider("sun.nio.fs.AixFileSystemProvider"); throw new AssertionError("Platform not recognized"); } } diff --git a/src/solaris/demo/jvmti/hprof/hprof_md.c b/src/solaris/demo/jvmti/hprof/hprof_md.c --- a/src/solaris/demo/jvmti/hprof/hprof_md.c +++ b/src/solaris/demo/jvmti/hprof/hprof_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,7 +42,7 @@ #include #include -#if !defined(LINUX) && !defined(_ALLBSD_SOURCE) +#if !defined(LINUX) && !defined(_ALLBSD_SOURCE) && !defined(AIX) #include #endif @@ -65,6 +65,10 @@ #include "jvm_md.h" #include "hprof.h" +#ifdef AIX +#include "porting_aix.h" /* For the 'dladdr' function. */ +#endif + int md_getpid(void) { @@ -86,7 +90,7 @@ void md_init(void) { -#if defined(LINUX) || defined(_ALLBSD_SOURCE) +#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX) /* No Hi-Res timer option? */ #else if ( gdata->micro_state_accounting ) { @@ -253,7 +257,7 @@ jlong md_get_microsecs(void) { -#if defined(LINUX) || defined(_ALLBSD_SOURCE) +#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX) return (jlong)(md_timeofday() * (jlong)1000); /* Milli to micro */ #else return (jlong)(gethrtime()/(hrtime_t)1000); /* Nano seconds to micro seconds */ @@ -271,7 +275,7 @@ jlong md_get_thread_cpu_timemillis(void) { -#if defined(LINUX) || defined(_ALLBSD_SOURCE) +#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX) return md_timeofday(); #else return (jlong)(gethrvtime()/1000); /* Nano seconds to milli seconds */ @@ -286,7 +290,7 @@ Dl_info dlinfo; libdir[0] = 0; -#if defined(LINUX) || defined(_ALLBSD_SOURCE) +#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX) addr = (void*)&Agent_OnLoad; #else /* Just using &Agent_OnLoad will get the first external symbol with @@ -457,3 +461,5 @@ sym = dlsym(handle, name); return sym; } + + diff --git a/src/solaris/native/common/jdk_util_md.h b/src/solaris/native/common/jdk_util_md.h --- a/src/solaris/native/common/jdk_util_md.h +++ b/src/solaris/native/common/jdk_util_md.h @@ -39,6 +39,10 @@ #include #define ISNANF(f) isnanf(f) #define ISNAND(d) isnan(d) +#elif defined(_AIX) +#include +#define ISNANF(f) _isnanf(f) +#define ISNAND(d) _isnan(d) #else #error "missing platform-specific definition here" #endif diff --git a/src/solaris/native/java/io/io_util_md.c b/src/solaris/native/java/io/io_util_md.c --- a/src/solaris/native/java/io/io_util_md.c +++ b/src/solaris/native/java/io/io_util_md.c @@ -35,7 +35,7 @@ #include #endif -#if defined(__linux__) || defined(_ALLBSD_SOURCE) +#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX) #include #endif diff --git a/src/solaris/native/java/lang/UNIXProcess_md.c b/src/solaris/native/java/lang/UNIXProcess_md.c --- a/src/solaris/native/java/lang/UNIXProcess_md.c +++ b/src/solaris/native/java/lang/UNIXProcess_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ #include #include -#if defined(__solaris__) || defined(_ALLBSD_SOURCE) +#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) #include #endif @@ -455,7 +455,7 @@ return resultPid; } -#if defined(__solaris__) || defined(_ALLBSD_SOURCE) +#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) static pid_t spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { pid_t resultPid; @@ -551,7 +551,7 @@ return vforkChild(c); case MODE_FORK: return forkChild(c); -#if defined(__solaris__) || defined(_ALLBSD_SOURCE) +#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) case MODE_POSIX_SPAWN: return spawnChild(env, process, c, helperpath); #endif diff --git a/src/solaris/native/java/lang/childproc.c b/src/solaris/native/java/lang/childproc.c --- a/src/solaris/native/java/lang/childproc.c +++ b/src/solaris/native/java/lang/childproc.c @@ -66,6 +66,9 @@ #define FD_DIR "/dev/fd" #define dirent64 dirent #define readdir64 readdir +#elif defined(_AIX) +/* AIX does not understand '/proc/self' - it requires the real process ID */ +#define FD_DIR aix_fd_dir #else #define FD_DIR "/proc/self/fd" #endif @@ -87,6 +90,12 @@ close(from_fd); /* for possible use by opendir() */ close(from_fd + 1); /* another one for good luck */ +#if defined(_AIX) + /* AIX does not understand '/proc/self' - it requires the real process ID */ + char aix_fd_dir[32]; /* the pid has at most 19 digits */ + snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid()); +#endif + if ((dp = opendir(FD_DIR)) == NULL) return 0; diff --git a/src/solaris/native/java/net/NetworkInterface.c b/src/solaris/native/java/net/NetworkInterface.c --- a/src/solaris/native/java/net/NetworkInterface.c +++ b/src/solaris/native/java/net/NetworkInterface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,13 @@ #include #endif +#if defined(_AIX) +#include +#include +#include +#include +#endif + #ifdef __linux__ #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" #endif @@ -1041,8 +1048,8 @@ } -/** Linux **/ -#ifdef __linux__ +/** Linux, AIX **/ +#if defined(__linux__) || defined(_AIX) /* Open socket for further ioct calls, try v4 socket first and * if it falls return v6 socket */ @@ -1080,11 +1087,13 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { struct ifconf ifc; struct ifreq *ifreqP; - char *buf; + char *buf = NULL; int numifs; unsigned i; + int siocgifconfRequest = SIOCGIFCONF; +#if defined(__linux__) /* need to do a dummy SIOCGIFCONF to determine the buffer size. * SIOCGIFCOUNT doesn't work */ @@ -1093,11 +1102,21 @@ NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed"); return ifs; } +#elif defined(_AIX) + ifc.ifc_buf = NULL; + if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGSIZIFCONF failed"); + return ifs; + } +#endif /* __linux__ */ CHECKED_MALLOC3(buf,char *, ifc.ifc_len); ifc.ifc_buf = buf; - if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { +#if defined(_AIX) + siocgifconfRequest = CSIOCGIFCONF; +#endif + if (ioctl(sock, siocgifconfRequest, (char *)&ifc) < 0) { NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed"); (void) free(buf); return ifs; @@ -1108,6 +1127,9 @@ */ ifreqP = ifc.ifc_req; for (i=0; iifr_addr.sa_family != AF_INET) continue; +#endif /* * Add to the list */ @@ -1135,7 +1157,7 @@ * Enumerates and returns all IPv6 interfaces on Linux */ -#ifdef AF_INET6 +#if defined(AF_INET6) && defined(__linux__) static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { FILE *f; char addr6[40], devname[21]; @@ -1179,11 +1201,103 @@ #endif +/* + * Enumerates and returns all IPv6 interfaces on AIX + */ + +#if defined(AF_INET6) && defined(_AIX) +static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { + struct ifconf ifc; + struct ifreq *ifreqP; + char *buf; + int numifs; + unsigned i; + unsigned bufsize; + char *cp, *cplimit; + + /* use SIOCGSIZIFCONF to get size for SIOCGIFCONF */ + + ifc.ifc_buf = NULL; + if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", + "ioctl SIOCGSIZIFCONF failed"); + return ifs; + } + bufsize = ifc.ifc_len; + + buf = (char *)malloc(bufsize); + if (!buf) { + JNU_ThrowOutOfMemoryError(env, "Network interface native buffer allocation failed"); + return ifs; + } + ifc.ifc_len = bufsize; + ifc.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", + "ioctl CSIOCGIFCONF failed"); + free(buf); + return ifs; + } + + /* + * Iterate through each interface + */ + ifreqP = ifc.ifc_req; + cp = (char *)ifc.ifc_req; + cplimit = cp + ifc.ifc_len; + + for ( ; cp < cplimit; cp += (sizeof(ifreqP->ifr_name) + MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr)))) { + ifreqP = (struct ifreq *)cp; + struct ifreq if2; + + memset((char *)&if2, 0, sizeof(if2)); + strcpy(if2.ifr_name, ifreqP->ifr_name); + + /* + * Skip interface that aren't UP + */ + if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) >= 0) { + if (!(if2.ifr_flags & IFF_UP)) { + continue; + } + } + + if (ifreqP->ifr_addr.sa_family != AF_INET6) + continue; + + /* + * Add to the list + */ + ifs = addif(env, sock, ifreqP->ifr_name, ifs, + (struct sockaddr *)&(ifreqP->ifr_addr), + AF_INET6, 0); + + /* + * If an exception occurred then free the list + */ + if ((*env)->ExceptionOccurred(env)) { + free(buf); + freeif(ifs); + return NULL; + } + } + + /* + * Free socket and buffer + */ + free(buf); + return ifs; +} +#endif + + static int getIndex(int sock, const char *name){ /* * Try to get the interface index - * (Not supported on Solaris 2.6 or 7) */ +#if defined(_AIX) + return if_nametoindex(name); +#else struct ifreq if2; strcpy(if2.ifr_name, name); @@ -1192,6 +1306,7 @@ } return if2.ifr_ifindex; +#endif } /** @@ -1258,6 +1373,46 @@ * MAC address. Returns -1 if there is no hardware address on that interface. */ static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) { +#if defined (_AIX) + int size; + struct kinfo_ndd *nddp; + void *end; + + size = getkerninfo(KINFO_NDD, 0, 0, 0); + if (size == 0) { + return -1; + } + + if (size < 0) { + perror("getkerninfo 1"); + return -1; + } + + nddp = (struct kinfo_ndd *)malloc(size); + + if (!nddp) { + return -1; + } + + if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) { + perror("getkerninfo 2"); + return -1; + } + + end = (void *)nddp + size; + while ((void *)nddp < end) { + if (!strcmp(nddp->ndd_alias, ifname) || + !strcmp(nddp->ndd_name, ifname)) { + bcopy(nddp->ndd_addr, buf, 6); + return 6; + } else { + nddp++; + } + } + + return -1; + +#elif defined(__linux__) static struct ifreq ifr; int i; @@ -1279,6 +1434,7 @@ } return -1; +#endif } static int getMTU(JNIEnv *env, int sock, const char *ifname) { diff --git a/src/solaris/native/java/net/PlainSocketImpl.c b/src/solaris/native/java/net/PlainSocketImpl.c --- a/src/solaris/native/java/net/PlainSocketImpl.c +++ b/src/solaris/native/java/net/PlainSocketImpl.c @@ -963,7 +963,7 @@ } if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { -#ifdef __solaris__ +#if defined(__solaris__) || defined(_AIX) if (errno == EINVAL) { // On Solaris setsockopt will set errno to EINVAL if the socket // is closed. The default error message is then confusing diff --git a/src/solaris/native/java/net/net_util_md.c b/src/solaris/native/java/net/net_util_md.c --- a/src/solaris/native/java/net/net_util_md.c +++ b/src/solaris/native/java/net/net_util_md.c @@ -738,14 +738,23 @@ return 0; } -void initLocalAddrTable () { +void platformInit () { initLoopbackRoutes(); initLocalIfs(); } +#elif defined(_AIX) + +/* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */ +extern void aix_close_init(); + +void platformInit () { + aix_close_init(); +} + #else -void initLocalAddrTable () {} +void platformInit () {} #endif @@ -987,7 +996,11 @@ { java_net_SocketOptions_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF }, { java_net_SocketOptions_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF }, { java_net_SocketOptions_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE }, +#if defined(_AIX) + { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEPORT }, +#else { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR }, +#endif { java_net_SocketOptions_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST }, { java_net_SocketOptions_IP_TOS, IPPROTO_IP, IP_TOS }, { java_net_SocketOptions_IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF }, @@ -1387,6 +1400,29 @@ } #endif +#ifdef _AIX + if (level == SOL_SOCKET) { + if (opt == SO_SNDBUF || opt == SO_RCVBUF) { + /* + * Just try to set the requested size. If it fails we will leave the + * socket option as is. Setting the buffer size means only a hint in + * the jse2/java software layer, see javadoc. In the previous + * solution the buffer has always been truncated to a length of + * 0x100000 Byte, even if the technical limit has not been reached. + * This kind of absolute truncation was unexpected in the jck tests. + */ + int ret = setsockopt(fd, level, opt, arg, len); + if ((ret == 0) || (ret == -1 && errno == ENOBUFS)) { + // Accept failure because of insufficient buffer memory resources. + return 0; + } else { + // Deliver all other kinds of errors. + return ret; + } + } + } +#endif + /* * On Linux the receive buffer is used for both socket * structures and the the packet payload. The implication diff --git a/src/solaris/native/java/net/net_util_md.h b/src/solaris/native/java/net/net_util_md.h --- a/src/solaris/native/java/net/net_util_md.h +++ b/src/solaris/native/java/net/net_util_md.h @@ -37,7 +37,17 @@ #endif -#if defined(__linux__) || defined(MACOSX) +/* + AIX needs a workaround for I/O cancellation, see: + http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm + ... + The close subroutine is blocked until all subroutines which use the file + descriptor return to usr space. For example, when a thread is calling close + and another thread is calling select with the same file descriptor, the + close subroutine does not return until the select call returns. + ... +*/ +#if defined(__linux__) || defined(MACOSX) || defined (_AIX) extern int NET_Timeout(int s, long timeout); extern int NET_Read(int s, void* buf, size_t len); extern int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, diff --git a/src/solaris/native/java/util/TimeZone_md.c b/src/solaris/native/java/util/TimeZone_md.c --- a/src/solaris/native/java/util/TimeZone_md.c +++ b/src/solaris/native/java/util/TimeZone_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,7 @@ return NULL; } -#if defined(__linux__) || defined(MACOSX) || (defined(__solaris__) \ +#if defined(_AIX) || defined(__linux__) || defined(MACOSX) || (defined(__solaris__) \ && (defined(_POSIX_PTHREAD_SEMANTICS) || defined(_LP64))) while (readdir_r(dirp, entry, &dp) == 0 && dp != NULL) { #else @@ -615,6 +615,14 @@ #endif /*__solaris__*/ #endif /*__linux__*/ +#ifdef _AIX +static char * +getPlatformTimeZoneID() +{ + return NULL; +} +#endif + /* * findJavaTZ_md() maps platform time zone ID to Java time zone ID * using /lib/tzmappings. If the TZ value is not found, it @@ -635,7 +643,7 @@ #if defined(__linux__) || defined(_ALLBSD_SOURCE) if (tz == NULL) { #else -#ifdef __solaris__ +#if defined (__solaris__) || defined(_AIX) if (tz == NULL || *tz == '\0') { #endif #endif diff --git a/src/solaris/native/sun/awt/awt_LoadLibrary.c b/src/solaris/native/sun/awt/awt_LoadLibrary.c --- a/src/solaris/native/sun/awt/awt_LoadLibrary.c +++ b/src/solaris/native/sun/awt/awt_LoadLibrary.c @@ -37,6 +37,10 @@ #include "awt_Plugin.h" +#ifdef AIX +#include "porting_aix.h" /* For the 'dladdr' function. */ +#endif + #ifdef DEBUG #define VERBOSE_AWT_DEBUG #endif diff --git a/src/solaris/native/sun/awt/fontpath.c b/src/solaris/native/sun/awt/fontpath.c --- a/src/solaris/native/sun/awt/fontpath.c +++ b/src/solaris/native/sun/awt/fontpath.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ #define MAXFDIRS 512 /* Max number of directories that contain fonts */ -#if !defined(__linux__) +#if defined(__solaris__) /* * This can be set in the makefile to "/usr/X11" if so desired. */ @@ -114,7 +114,7 @@ NULL, /* terminates the list */ }; -#else /* __linux */ +#elif defined( __linux__) /* All the known interesting locations we have discovered on * various flavors of Linux */ @@ -134,6 +134,12 @@ "/usr/share/fonts/default/Type1", /* RH 9.0 */ NULL, /* terminates the list */ }; +#elif defined(_AIX) +static char *fullAixFontPath[] = { + "/usr/lpp/X11/lib/X11/fonts/Type1", /* from X11.fnt.iso_T1 */ + "/usr/lpp/X11/lib/X11/fonts/TrueType", /* from X11.fnt.ucs.ttf */ + NULL, /* terminates the list */ +}; #endif static char **getFontConfigLocations(); @@ -497,10 +503,11 @@ #if defined(__linux__) knowndirs = fullLinuxFontPath; -#else /* IF SOLARIS */ +#elif defined(__solaris__) knowndirs = fullSolarisFontPath; +#elif defined(_AIX) + knowndirs = fullAixFontPath; #endif - /* REMIND: this code requires to be executed when the GraphicsEnvironment * is already initialised. That is always true, but if it were not so, * this code could throw an exception and the fontpath would fail to @@ -592,6 +599,25 @@ } } #endif + +#if defined(_AIX) + /* On AIX, fontconfig is not a standard package supported by IBM. + * instead it has to be installed from the "AIX Toolbox for Linux Applications" + * site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html + * and will be installed under /opt/freeware/lib/libfontconfig.a. + * Notice that the archive contains the real 32- and 64-bit shared libraries. + * We first try to load 'libfontconfig.so' from the default library path in the + * case the user has installed a private version of the library and if that + * doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a + */ + libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY); + if (libfontconfig == NULL) { + libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)", RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY); + if (libfontconfig == NULL) { + return NULL; + } + } +#else /* 64 bit sparc should pick up the right version from the lib path. * New features may be added to libfontconfig, this is expected to * be compatible with old features, but we may need to start @@ -606,6 +632,7 @@ return NULL; } } +#endif /* Version 1.0 of libfontconfig crashes if HOME isn't defined in * the environment. This should generally never happen, but we can't @@ -1203,7 +1230,7 @@ */ if (fontformat != NULL && (strcmp((char*)fontformat, "TrueType") != 0) -#ifdef __linux__ +#if defined(__linux__) || defined(_AIX) && (strcmp((char*)fontformat, "Type 1") != 0) #endif ) { diff --git a/src/solaris/native/sun/java2d/x11/X11SurfaceData.c b/src/solaris/native/sun/java2d/x11/X11SurfaceData.c --- a/src/solaris/native/sun/java2d/x11/X11SurfaceData.c +++ b/src/solaris/native/sun/java2d/x11/X11SurfaceData.c @@ -56,8 +56,8 @@ int x, y; } X11RIPrivate; -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define XSD_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define XSD_MIN(a,b) ((a) < (b) ? (a) : (b)) static LockFunc X11SD_Lock; static GetRasInfoFunc X11SD_GetRasInfo; @@ -1090,10 +1090,10 @@ x2 = x1 + DisplayWidth(awt_display, xsdo->configData->awt_visInfo.screen); y2 = y1 + DisplayHeight(awt_display, xsdo->configData->awt_visInfo.screen); - x1 = MAX(bounds->x1, x1); - y1 = MAX(bounds->y1, y1); - x2 = MIN(bounds->x2, x2); - y2 = MIN(bounds->y2, y2); + x1 = XSD_MAX(bounds->x1, x1); + y1 = XSD_MAX(bounds->y1, y1); + x2 = XSD_MIN(bounds->x2, x2); + y2 = XSD_MIN(bounds->y2, y2); if ((x1 >= x2) || (y1 >= y2)) { return FALSE; } diff --git a/src/solaris/native/sun/java2d/x11/XRBackendNative.c b/src/solaris/native/sun/java2d/x11/XRBackendNative.c --- a/src/solaris/native/sun/java2d/x11/XRBackendNative.c +++ b/src/solaris/native/sun/java2d/x11/XRBackendNative.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,8 +72,8 @@ #include -#ifdef __solaris__ -/* Solaris 10 will not have these symbols at runtime */ +#if defined(__solaris__) || defined(_AIX) +/* Solaris 10 and AIX will not have these symbols at runtime */ typedef Picture (*XRenderCreateLinearGradientFuncType) (Display *dpy, @@ -147,7 +147,7 @@ return JNI_FALSE; } -#ifdef __solaris__ +#if defined(__solaris__) || defined(_AIX) xrenderlib = dlopen("libXrender.so",RTLD_GLOBAL|RTLD_LAZY); if (xrenderlib != NULL) { diff --git a/src/solaris/native/sun/management/OperatingSystemImpl.c b/src/solaris/native/sun/management/OperatingSystemImpl.c --- a/src/solaris/native/sun/management/OperatingSystemImpl.c +++ b/src/solaris/native/sun/management/OperatingSystemImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ #include #include #endif -#else +#elif !defined(_AIX) #include #endif #include @@ -57,9 +57,13 @@ #include #include +#if defined(_AIX) +#include +#endif + static jlong page_size = 0; -#if defined(_ALLBSD_SOURCE) +#if defined(_ALLBSD_SOURCE) || defined(_AIX) #define MB (1024UL * 1024UL) #else @@ -326,6 +330,12 @@ */ // throw_internal_error(env, "unimplemented in FreeBSD") return (128 * MB); +#elif defined(_AIX) + perfstat_memory_total_t memory_info; + if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) { + return (jlong)(memory_info.real_free * 4L * 1024L); + } + return -1; #else // solaris / linux jlong num_avail_physical_pages = sysconf(_SC_AVPHYS_PAGES); return (num_avail_physical_pages * page_size); @@ -349,6 +359,12 @@ return -1; } return result; +#elif defined(_AIX) + perfstat_memory_total_t memory_info; + if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) { + return (jlong)(memory_info.real_total * 4L * 1024L); + } + return -1; #else // solaris / linux jlong num_physical_pages = sysconf(_SC_PHYS_PAGES); return (num_physical_pages * page_size); diff --git a/src/solaris/native/sun/nio/ch/Net.c b/src/solaris/native/sun/nio/ch/Net.c --- a/src/solaris/native/sun/nio/ch/Net.c +++ b/src/solaris/native/sun/nio/ch/Net.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,9 @@ #include "nio.h" #include "sun_nio_ch_PollArrayWrapper.h" +#ifdef _AIX +#include +#endif /** * IP_MULTICAST_ALL supported since 2.6.31 but may not be available at @@ -51,24 +54,46 @@ #endif #endif -#ifdef _ALLBSD_SOURCE +#if defined(_ALLBSD_SOURCE) || defined(_AIX) #ifndef IP_BLOCK_SOURCE +#if defined(_AIX) + +#define IP_BLOCK_SOURCE 58 /* Block data from a given source to a given group */ +#define IP_UNBLOCK_SOURCE 59 /* Unblock data from a given source to a given group */ +#define IP_ADD_SOURCE_MEMBERSHIP 60 /* Join a source-specific group */ +#define IP_DROP_SOURCE_MEMBERSHIP 61 /* Leave a source-specific group */ + +#else + #define IP_ADD_SOURCE_MEMBERSHIP 70 /* join a source-specific group */ #define IP_DROP_SOURCE_MEMBERSHIP 71 /* drop a single source */ #define IP_BLOCK_SOURCE 72 /* block a source */ #define IP_UNBLOCK_SOURCE 73 /* unblock a source */ +#endif /* _AIX */ + #endif /* IP_BLOCK_SOURCE */ #ifndef MCAST_BLOCK_SOURCE +#if defined(_AIX) + +#define MCAST_BLOCK_SOURCE 64 +#define MCAST_UNBLOCK_SOURCE 65 +#define MCAST_JOIN_SOURCE_GROUP 66 +#define MCAST_LEAVE_SOURCE_GROUP 67 + +#else + #define MCAST_JOIN_SOURCE_GROUP 82 /* join a source-specific group */ #define MCAST_LEAVE_SOURCE_GROUP 83 /* leave a single source */ #define MCAST_BLOCK_SOURCE 84 /* block a source */ #define MCAST_UNBLOCK_SOURCE 85 /* unblock a source */ +#endif /* _AIX */ + #endif /* MCAST_BLOCK_SOURCE */ #ifndef IPV6_ADD_MEMBERSHIP @@ -123,6 +148,36 @@ } #endif +#ifdef _AIX + +/* + * Checks whether or not "socket extensions for multicast source filters" is supported. + * Returns JNI_TRUE if it is supported, JNI_FALSE otherwise + */ +static jboolean isSourceFilterSupported(){ + static jboolean alreadyChecked = JNI_FALSE; + static jboolean result = JNI_TRUE; + if (alreadyChecked != JNI_TRUE){ + struct utsname uts; + memset(&uts, 0, sizeof(uts)); + strcpy(uts.sysname, "?"); + const int utsRes = uname(&uts); + int major = -1; + int minor = -1; + major = atoi(uts.version); + minor = atoi(uts.release); + if (strcmp(uts.sysname, "AIX") == 0) { + if (major < 6 || (major == 6 && minor < 1)) {// unsupported on aix < 6.1 + result = JNI_FALSE; + } + } + alreadyChecked = JNI_TRUE; + } + return result; +} + +#endif /* _AIX */ + JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) { @@ -475,6 +530,14 @@ /* no IPv4 include-mode filtering for now */ return IOS_UNAVAILABLE; #else + +#ifdef _AIX + /* check AIX for support of source filtering */ + if (isSourceFilterSupported() != JNI_TRUE){ + return IOS_UNAVAILABLE; + } +#endif + mreq_source.imr_multiaddr.s_addr = htonl(group); mreq_source.imr_sourceaddr.s_addr = htonl(source); mreq_source.imr_interface.s_addr = htonl(interf); @@ -486,7 +549,7 @@ n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); if (n < 0) { - if (join && (errno == ENOPROTOOPT)) + if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) return IOS_UNAVAILABLE; handleSocketError(env, errno); } @@ -505,6 +568,13 @@ int n; int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; +#ifdef _AIX + /* check AIX for support of source filtering */ + if (isSourceFilterSupported() != JNI_TRUE){ + return IOS_UNAVAILABLE; + } +#endif + mreq_source.imr_multiaddr.s_addr = htonl(group); mreq_source.imr_sourceaddr.s_addr = htonl(source); mreq_source.imr_interface.s_addr = htonl(interf); @@ -512,7 +582,7 @@ n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, (void*)&mreq_source, sizeof(mreq_source)); if (n < 0) { - if (block && (errno == ENOPROTOOPT)) + if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) return IOS_UNAVAILABLE; handleSocketError(env, errno); } @@ -550,7 +620,7 @@ n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); if (n < 0) { - if (join && (errno == ENOPROTOOPT)) + if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) return IOS_UNAVAILABLE; handleSocketError(env, errno); } @@ -579,7 +649,7 @@ n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req)); if (n < 0) { - if (block && (errno == ENOPROTOOPT)) + if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) return IOS_UNAVAILABLE; handleSocketError(env, errno); } diff --git a/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c b/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c --- a/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c +++ b/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c @@ -42,7 +42,7 @@ #include #endif -#ifdef __linux__ +#if defined(__linux__) || defined(_AIX) #include #endif @@ -294,7 +294,13 @@ jsize len; jbyteArray bytes; +#ifdef _AIX + /* strerror() is not thread-safe on AIX so we have to use strerror_r() */ + char buffer[256]; + msg = (strerror_r((int)error, buffer, 256) == 0) ? buffer : "Error while calling strerror_r"; +#else msg = strerror((int)error); +#endif len = strlen(msg); bytes = (*env)->NewByteArray(env, len); if (bytes != NULL) { @@ -674,6 +680,15 @@ /* EINTR not listed as a possible error */ /* TDB: reentrant version probably not required here */ res = readdir64_r(dirp, ptr, &result); + +#ifdef _AIX + /* On AIX, readdir_r() returns EBADF (i.e. '9') and sets 'result' to NULL for the */ + /* directory stream end. Otherwise, 'errno' will contain the error code. */ + if (res != 0) { + res = (result == NULL && res == EBADF) ? 0 : errno; + } +#endif + if (res != 0) { throwUnixException(env, res); return NULL; @@ -877,6 +892,18 @@ if (err == -1) { throwUnixException(env, errno); } else { +#ifdef _AIX + /* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */ + /* This is too big for a Java signed long and fools various tests. */ + if (buf.f_blocks == ULONG_MAX) { + buf.f_blocks = 0; + } + /* The number of free or available blocks can never exceed the total number of blocks */ + if (buf.f_blocks == 0) { + buf.f_bfree = 0; + buf.f_bavail = 0; + } +#endif (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); diff --git a/src/solaris/native/sun/security/pkcs11/j2secmod_md.c b/src/solaris/native/sun/security/pkcs11/j2secmod_md.c --- a/src/solaris/native/sun/security/pkcs11/j2secmod_md.c +++ b/src/solaris/native/sun/security/pkcs11/j2secmod_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,11 @@ { const char *libName = (*env)->GetStringUTFChars(env, jLibName, NULL); // look up existing handle only, do not load +#if defined(AIX) + void *hModule = dlopen(libName, RTLD_LAZY); +#else void *hModule = dlopen(libName, RTLD_NOLOAD); +#endif dprintf2("-handle for %s: %u\n", libName, hModule); (*env)->ReleaseStringUTFChars(env, jLibName, libName); return ptr_to_jlong(hModule); diff --git a/src/windows/native/java/net/net_util_md.c b/src/windows/native/java/net/net_util_md.c --- a/src/windows/native/java/net/net_util_md.c +++ b/src/windows/native/java/net/net_util_md.c @@ -125,8 +125,8 @@ return TRUE; } -void initLocalAddrTable () {} -void parseExclusiveBindProperty (JNIEnv *env) {} +void platformInit() {} +void parseExclusiveBindProperty(JNIEnv *env) {} /* * Since winsock doesn't have the equivalent of strerror(errno) diff --git a/test/java/lang/ProcessBuilder/Basic.java b/test/java/lang/ProcessBuilder/Basic.java --- a/test/java/lang/ProcessBuilder/Basic.java +++ b/test/java/lang/ProcessBuilder/Basic.java @@ -58,6 +58,9 @@ /* used for Mac OS X only */ static final String cfUserTextEncoding = System.getenv("__CF_USER_TEXT_ENCODING"); + /* used for AIX only */ + static final String libpath = System.getenv("LIBPATH"); + private static String commandOutput(Reader r) throws Throwable { StringBuilder sb = new StringBuilder(); int c; @@ -75,7 +78,11 @@ String output = commandOutput(r); equal(p.waitFor(), 0); equal(p.exitValue(), 0); - return output; + // The debug/fastdebug versions of the VM may write some warnings to stdout + // (i.e. "Warning: Cannot open log file: hotspot.log" if the VM is started + // in a directory without write permissions). These warnings will confuse tests + // which match the entire output of the child process so better filter them out. + return output.replaceAll("Warning:.*\\n", ""); } private static String commandOutput(ProcessBuilder pb) { @@ -584,6 +591,12 @@ System.getProperty("os.name").startsWith("Windows"); } + static class AIX { + public static boolean is() { return is; } + private static final boolean is = + System.getProperty("os.name").equals("AIX"); + } + static class Unix { public static boolean is() { return is; } private static final boolean is = @@ -637,7 +650,7 @@ private static boolean isEnglish(String envvar) { String val = getenv(envvar); - return (val == null) || val.matches("en.*"); + return (val == null) || val.matches("en.*") || val.matches("C"); } /** Returns true if we can expect English OS error strings */ @@ -712,6 +725,14 @@ return cleanedVars.replace(javaMainClassStr,""); } + /* Only used for AIX -- + * AIX adds the variable AIXTHREAD_GUARDPAGES=0 to the environment. + * Remove it from the list of env variables + */ + private static String removeAixExpectedVars(String vars) { + return vars.replace("AIXTHREAD_GUARDPAGES=0,",""); + } + private static String sortByLinesWindowsly(String text) { String[] lines = text.split("\n"); Arrays.sort(lines, new WindowsComparator()); @@ -1160,13 +1181,20 @@ ProcessBuilder pb = new ProcessBuilder(); pb.environment().clear(); String expected = Windows.is() ? "SystemRoot="+systemRoot+",": ""; + expected = AIX.is() ? "LIBPATH="+libpath+",": expected; if (Windows.is()) { pb.environment().put("SystemRoot", systemRoot); } + if (AIX.is()) { + pb.environment().put("LIBPATH", libpath); + } String result = getenvInChild(pb); if (MacOSX.is()) { result = removeMacExpectedVars(result); } + if (AIX.is()) { + result = removeAixExpectedVars(result); + } equal(result, expected); } catch (Throwable t) { unexpected(t); } @@ -1681,10 +1709,14 @@ } Process p = Runtime.getRuntime().exec(cmdp, envp); String expected = Windows.is() ? "=C:=\\,=ExitValue=3,SystemRoot="+systemRoot+"," : "=C:=\\,"; + expected = AIX.is() ? expected + "LIBPATH="+libpath+",": expected; String commandOutput = commandOutput(p); if (MacOSX.is()) { commandOutput = removeMacExpectedVars(commandOutput); } + if (AIX.is()) { + commandOutput = removeAixExpectedVars(commandOutput); + } equal(commandOutput, expected); if (Windows.is()) { ProcessBuilder pb = new ProcessBuilder(childArgs); @@ -1736,9 +1768,14 @@ if (MacOSX.is()) { commandOutput = removeMacExpectedVars(commandOutput); } + if (AIX.is()) { + commandOutput = removeAixExpectedVars(commandOutput); + } check(commandOutput.equals(Windows.is() ? "LC_ALL=C,SystemRoot="+systemRoot+"," - : "LC_ALL=C,"), + : AIX.is() + ? "LC_ALL=C,LIBPATH="+libpath+"," + : "LC_ALL=C,"), "Incorrect handling of envstrings containing NULs"); } catch (Throwable t) { unexpected(t); } @@ -2015,7 +2052,12 @@ if (Unix.is() && new File("/bin/bash").exists() && new File("/bin/sleep").exists()) { - final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 6666)" }; + // Notice that we only destroy the process created by us (i.e. + // our child) but not our grandchild (i.e. '/bin/sleep'). So + // pay attention that the grandchild doesn't run too long to + // avoid polluting the process space with useless processes. + // Running the grandchild for 60s should be more than enough. + final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 60)" }; final ProcessBuilder pb = new ProcessBuilder(cmd); final Process p = pb.start(); final InputStream stdout = p.getInputStream(); @@ -2037,12 +2079,26 @@ reader.start(); Thread.sleep(100); p.destroy(); - // Subprocess is now dead, but file descriptors remain open. check(p.waitFor() != 0); check(p.exitValue() != 0); + // Subprocess is now dead, but file descriptors remain open. + // Make sure the test will fail if we don't manage to close + // the open streams within 30 seconds. Notice that this time + // must be shorter than the sleep time of the grandchild. + Timer t = new Timer("test/java/lang/ProcessBuilder/Basic.java process reaper", true); + t.schedule(new TimerTask() { + public void run() { + fail("Subprocesses which create subprocesses of " + + "their own caused the parent to hang while " + + "waiting for file descriptors to be closed."); + System.exit(-1); + } + }, 30000); stdout.close(); stderr.close(); stdin.close(); + // All streams successfully closed so we can cancel the timer. + t.cancel(); //---------------------------------------------------------- // There remain unsolved issues with asynchronous close. // Here's a highly non-portable experiment to demonstrate: @@ -2188,8 +2244,9 @@ } long end = System.nanoTime(); // give waitFor(timeout) a wide berth (100ms) - if ((end - start) > 100000000) - fail("Test failed: waitFor took too long"); + // Old AIX machines my need a little longer. + if ((end - start) > 100000000L * (AIX.is() ? 4 : 1)) + fail("Test failed: waitFor took too long (" + (end - start) + "ns)"); p.destroy(); p.waitFor(); @@ -2216,7 +2273,7 @@ long end = System.nanoTime(); if ((end - start) < 500000000) - fail("Test failed: waitFor didn't take long enough"); + fail("Test failed: waitFor didn't take long enough (" + (end - start) + "ns)"); p.destroy(); @@ -2224,7 +2281,7 @@ p.waitFor(1000, TimeUnit.MILLISECONDS); end = System.nanoTime(); if ((end - start) > 900000000) - fail("Test failed: waitFor took too long on a dead process."); + fail("Test failed: waitFor took too long on a dead process. (" + (end - start) + "ns)"); } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- diff --git a/test/java/lang/ProcessBuilder/DestroyTest.java b/test/java/lang/ProcessBuilder/DestroyTest.java --- a/test/java/lang/ProcessBuilder/DestroyTest.java +++ b/test/java/lang/ProcessBuilder/DestroyTest.java @@ -154,6 +154,9 @@ } else if (osName.equals("SunOS")) { return new UnixTest( File.createTempFile("ProcessTrap-", ".sh",null)); + } else if (osName.equals("AIX")) { + return new UnixTest( + File.createTempFile("ProcessTrap-", ".sh",null)); } return null; }