# HG changeset patch # User simonis # Date 1389687300 -3600 # Node ID f324ac2b9acb033ea2501e460965335d2cc1c91c # Parent c1e75d17b9931386539ffee166b4da0307881b04 8031581: PPC64: Addons and fixes for AIX to pass the jdk regression tests diff --git a/make/CompileJavaClasses.gmk b/make/CompileJavaClasses.gmk --- a/make/CompileJavaClasses.gmk +++ b/make/CompileJavaClasses.gmk @@ -228,9 +228,9 @@ # Exclude another implicitly not included file. EXFILES += sun/util/locale/AsciiUtil.java -ifeq (, $(filter $(OPENJDK_TARGET_OS), solaris macosx)) +ifeq (, $(filter $(OPENJDK_TARGET_OS), solaris macosx aix)) # - # only solaris and macosx + # only solaris, macosx and aix # EXFILES += sun/nio/fs/PollingWatchService.java endif diff --git a/make/lib/NioLibraries.gmk b/make/lib/NioLibraries.gmk --- a/make/lib/NioLibraries.gmk +++ b/make/lib/NioLibraries.gmk @@ -120,7 +120,7 @@ BUILD_LIBNIO_FILES += \ AixPollPort.c \ InheritedChannel.c \ - NativeThread.c \ + AixNativeThread.c \ PollArrayWrapper.c \ UnixAsynchronousServerSocketChannelImpl.c \ UnixAsynchronousSocketChannelImpl.c \ diff --git a/src/aix/classes/sun/nio/ch/AixPollPort.java b/src/aix/classes/sun/nio/ch/AixPollPort.java --- a/src/aix/classes/sun/nio/ch/AixPollPort.java +++ b/src/aix/classes/sun/nio/ch/AixPollPort.java @@ -42,6 +42,30 @@ final class AixPollPort extends Port { + + static final short NATIVE_POLLIN = 0x0001; + static final short NATIVE_POLLOUT = 0x0002; + static final short NATIVE_POLLERR = 0x4000; + static final short NATIVE_POLLHUP = 0x2000; + + private static int nativeToJavaEvents(int nativeEvents) { + int javaEvents = 0; + if ((nativeEvents & NATIVE_POLLIN) > 0) javaEvents |= POLLIN; + if ((nativeEvents & NATIVE_POLLOUT) > 0) javaEvents |= POLLOUT; + if ((nativeEvents & NATIVE_POLLERR) > 0) javaEvents |= POLLERR; + if ((nativeEvents & NATIVE_POLLHUP) > 0) javaEvents |= POLLHUP; + return javaEvents; + } + + private static int javaToNativeEvents(int javaEvents) { + int nativeEvents = 0; + if ((javaEvents & POLLIN) > 0) nativeEvents |= NATIVE_POLLIN; + if ((javaEvents & POLLOUT) > 0) nativeEvents |= NATIVE_POLLOUT; + if ((javaEvents & POLLERR) > 0) nativeEvents |= NATIVE_POLLERR; + if ((javaEvents & POLLHUP) > 0) nativeEvents |= NATIVE_POLLHUP; + return nativeEvents; + } + private static final Unsafe unsafe = Unsafe.getUnsafe(); static { @@ -495,14 +519,18 @@ * Returns event->events */ private static int getEvents(long eventAddress) { - return unsafe.getChar(eventAddress + OFFSETOF_EVENTS); + return nativeToJavaEvents(unsafe.getChar(eventAddress + OFFSETOF_EVENTS)); } /** * Returns event->revents */ private static int getRevents(long eventAddress) { - return unsafe.getChar(eventAddress + OFFSETOF_REVENTS); + return nativeToJavaEvents(unsafe.getChar(eventAddress + OFFSETOF_REVENTS)); + } + + private static int pollsetCtl(int pollset, int opcode, int fd, int events) { + return pollsetCtl0(pollset, opcode, fd, javaToNativeEvents(events)); } // -- Native methods -- @@ -519,7 +547,7 @@ private static native int pollsetCreate() throws IOException; - private static native int pollsetCtl(int pollset, int opcode, int fd, int events); + private static native int pollsetCtl0(int pollset, int opcode, int fd, int events); private static native int pollsetPoll(int pollset, long pollAddress, int numfds) throws IOException; diff --git a/src/aix/native/java/net/aix_close.c b/src/aix/native/java/net/aix_close.c --- a/src/aix/native/java/net/aix_close.c +++ b/src/aix/native/java/net/aix_close.c @@ -234,6 +234,28 @@ pthread_mutex_lock(&(fdEntry->lock)); { + /* On fast machines we see that we enter dup2 before the + * accepting thread had a chance to get and process the signal. + * So in case we woke a thread up, give it some time to cope. + * Also see https://bugs.openjdk.java.net/browse/JDK-8006395 */ + int num_woken = 0; + + /* + * 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 ); + num_woken ++; + curr = curr->next; + } + + if (num_woken > 0) { + usleep(num_woken * 50); + } + /* * And close/dup the file descriptor * (restart if interrupted by signal) @@ -245,17 +267,6 @@ 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; - } } /* @@ -313,6 +324,18 @@ return ret; \ } +int IO_Fcntl(int s, int cmd, void *arg) { + BLOCKING_IO_RETURN_INT( s, fcntl(s, cmd, arg) ); +} + +int IO_Write(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, write(s, buf, len) ); +} + +int IO_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, read(s, buf, len) ); +} + int NET_Read(int s, void* buf, size_t len) { BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); } @@ -425,3 +448,37 @@ } } + +/* hard coded values in java code do not match system header values */ +#define JAVA_POLLIN 0x0001 +#define JAVA_POLLOUT 0x0004 +#define JAVA_POLLERR 0x0008 +#define JAVA_POLLHUP 0x0010 +#define JAVA_POLLNVAL 0x0020 +#define JAVA_POLLREMOVE 0x0800 /* not used yet in Java but ment to deregister fd */ + +/* declared in src/solaris/native/java/net/net_util_md.h for AIX only */ +int javaToNativeEvents(int javaEvents) { + int nativeEvents = 0; + if (javaEvents & JAVA_POLLIN) nativeEvents |= POLLIN; + if (javaEvents & JAVA_POLLOUT) nativeEvents |= POLLOUT; + if (javaEvents & JAVA_POLLERR) nativeEvents |= POLLERR; + if (javaEvents & JAVA_POLLHUP) nativeEvents |= POLLHUP; + if (javaEvents & JAVA_POLLNVAL) nativeEvents |= POLLNVAL; + if (javaEvents & JAVA_POLLREMOVE) { + /* For the time being we don't support JAVA_POLLREMOVE on AIX. Just check. */ + fprintf(stderr, "POLLREMOVE not supported on AIX"); + } + return nativeEvents; +} + +/* declared in src/solaris/native/java/net/net_util_md.h for AIX only */ +int nativeToJavaEvents(int nativeEvents) { + int javaEvents = 0; + if (nativeEvents & POLLIN) javaEvents |= JAVA_POLLIN; + if (nativeEvents & POLLOUT) javaEvents |= JAVA_POLLOUT; + if (nativeEvents & POLLERR) javaEvents |= JAVA_POLLERR; + if (nativeEvents & POLLHUP) javaEvents |= JAVA_POLLHUP; + if (nativeEvents & POLLNVAL) javaEvents |= JAVA_POLLNVAL; + return javaEvents; +} diff --git a/src/aix/native/sun/nio/ch/AixNativeThread.c b/src/aix/native/sun/nio/ch/AixNativeThread.c new file mode 100644 --- /dev/null +++ b/src/aix/native/sun/nio/ch/AixNativeThread.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "sun_nio_ch_NativeThread.h" + +#include +#include + +/* Also defined in src/aix/native/java/net/aix_close.c */ +#define INTERRUPT_SIGNAL (SIGRTMAX - 1) + +static void +nullHandler(int sig) +{ +} + + +JNIEXPORT void JNICALL +Java_sun_nio_ch_NativeThread_init(JNIEnv *env, jclass cl) +{ + /* Install the null handler for INTERRUPT_SIGNAL. This might overwrite the + * handler previously installed by java/net/aix_close.c, but that's okay + * since neither handler actually does anything. We install our own + * handler here simply out of paranoia; ultimately the two mechanisms + * should somehow be unified, perhaps within the VM. + */ + + sigset_t ss; + struct sigaction sa, osa; + sa.sa_handler = nullHandler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + if (sigaction(INTERRUPT_SIGNAL, &sa, &osa) < 0) + JNU_ThrowIOExceptionWithLastError(env, "sigaction"); +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_NativeThread_current(JNIEnv *env, jclass cl) +{ + return (long)pthread_self(); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_NativeThread_signal(JNIEnv *env, jclass cl, jlong thread) +{ + if (pthread_kill((pthread_t)thread, INTERRUPT_SIGNAL)) + JNU_ThrowIOExceptionWithLastError(env, "Thread signal failed"); +} diff --git a/src/aix/native/sun/nio/ch/AixPollPort.c b/src/aix/native/sun/nio/ch/AixPollPort.c --- a/src/aix/native/sun/nio/ch/AixPollPort.c +++ b/src/aix/native/sun/nio/ch/AixPollPort.c @@ -101,8 +101,8 @@ } JNIEXPORT jint JNICALL -Java_sun_nio_ch_AixPollPort_pollsetCtl(JNIEnv *env, jclass c, jint ps, - jint opcode, jint fd, jint events) { +Java_sun_nio_ch_AixPollPort_pollsetCtl0(JNIEnv *env, jclass c, jint ps, + jint opcode, jint fd, jint events) { struct poll_ctl event; int res; diff --git a/src/share/classes/java/nio/file/CopyMoveHelper.java b/src/share/classes/java/nio/file/CopyMoveHelper.java --- a/src/share/classes/java/nio/file/CopyMoveHelper.java +++ b/src/share/classes/java/nio/file/CopyMoveHelper.java @@ -130,7 +130,7 @@ // copy basic attributes to target if (opts.copyAttributes) { BasicFileAttributeView view = - Files.getFileAttributeView(target, BasicFileAttributeView.class, linkOptions); + Files.getFileAttributeView(target, BasicFileAttributeView.class); try { view.setTimes(attrs.lastModifiedTime(), attrs.lastAccessTime(), diff --git a/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java b/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java --- a/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java +++ b/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java @@ -1297,7 +1297,7 @@ } String osName = AccessController.doPrivileged( new GetPropertyAction("os.name")); - if ("SunOS".equals(osName) || "Linux".equals(osName) + if ("SunOS".equals(osName) || "Linux".equals(osName) || "AIX".equals(osName) || osName.contains("OS X")) { charset("x-COMPOUND_TEXT", "COMPOUND_TEXT", new String[] { diff --git a/src/share/classes/sun/tools/attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider b/src/share/classes/sun/tools/attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider --- a/src/share/classes/sun/tools/attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider +++ b/src/share/classes/sun/tools/attach/META-INF/services/com.sun.tools.attach.spi.AttachProvider @@ -31,3 +31,4 @@ #[windows]sun.tools.attach.WindowsAttachProvider #[linux]sun.tools.attach.LinuxAttachProvider #[macosx]sun.tools.attach.BsdAttachProvider +#[aix]sun.tools.attach.AixAttachProvider \ No newline at end of file diff --git a/src/share/native/java/util/zip/zip_util.c b/src/share/native/java/util/zip/zip_util.c --- a/src/share/native/java/util/zip/zip_util.c +++ b/src/share/native/java/util/zip/zip_util.c @@ -659,7 +659,10 @@ entries = zip->entries = calloc(total, sizeof(entries[0])); tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions table = zip->table = malloc(tablelen * sizeof(table[0])); - if (entries == NULL || table == NULL) goto Catch; + /* According to ISO C it is perfectly legel for malloc to return zero + * if called with a zero argument. We check this for 'entries' but not + * for 'table' because 'tablelen' can't be zero (see computation above). */ + if ((entries == NULL && total != 0) || table == NULL) goto Catch; for (j = 0; j < tablelen; j++) table[j] = ZIP_ENDCHAIN; diff --git a/src/share/native/sun/management/DiagnosticCommandImpl.c b/src/share/native/sun/management/DiagnosticCommandImpl.c --- a/src/share/native/sun/management/DiagnosticCommandImpl.c +++ b/src/share/native/sun/management/DiagnosticCommandImpl.c @@ -23,6 +23,7 @@ * questions. */ +#include #include #include "management.h" #include "sun_management_DiagnosticCommandImpl.h" @@ -56,7 +57,8 @@ jobject resultList; dcmd_arg_info_array = (dcmdArgInfo*) malloc(num_arg * sizeof(dcmdArgInfo)); - if (dcmd_arg_info_array == NULL) { + /* According to ISO C it is perfectly legel for malloc to return zero if called with a zero argument */ + if (dcmd_arg_info_array == NULL && num_arg != 0) { return NULL; } jmm_interface->GetDiagnosticCommandArgumentsInfo(env, command, @@ -117,9 +119,9 @@ return NULL; } num_commands = (*env)->GetArrayLength(env, commands); - dcmd_info_array = (dcmdInfo*) malloc(num_commands * - sizeof(dcmdInfo)); - if (dcmd_info_array == NULL) { + dcmd_info_array = (dcmdInfo*) malloc(num_commands * sizeof(dcmdInfo)); + /* According to ISO C it is perfectly legel for malloc to return zero if called with a zero argument */ + if (dcmd_info_array == NULL && num_commands != 0) { JNU_ThrowOutOfMemoryError(env, NULL); } jmm_interface->GetDiagnosticCommandInfo(env, commands, dcmd_info_array); diff --git a/src/share/transport/socket/socketTransport.c b/src/share/transport/socket/socketTransport.c --- a/src/share/transport/socket/socketTransport.c +++ b/src/share/transport/socket/socketTransport.c @@ -506,6 +506,19 @@ if (fd < 0) { return JDWPTRANSPORT_ERROR_NONE; } +#ifdef _AIX + /* + 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. + ... + */ + shutdown(fd, 2); +#endif if (dbgsysSocketClose(fd) < 0) { /* * close failed - it's pointless to restore socketFD here because diff --git a/src/solaris/classes/java/lang/UNIXProcess.java.aix b/src/solaris/classes/java/lang/UNIXProcess.java.aix --- a/src/solaris/classes/java/lang/UNIXProcess.java.aix +++ b/src/solaris/classes/java/lang/UNIXProcess.java.aix @@ -338,9 +338,23 @@ * 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. + * + * On AIX this is especially tricky, because the 'close()' system call + * will block if another thread is at the same time blocked in a file + * operation (e.g. 'read()') on the same file descriptor. We therefore + * combine this 'ProcessPipeInputStream' with the DeferredCloseInputStream + * approach used on Solaris (see "UNIXProcess.java.solaris"). This means + * that every potentially blocking operation on the file descriptor + * increments a counter before it is executed and decrements it once it + * finishes. The 'close()' operation will only be executed if there are + * no pending operations. Otherwise it is deferred after the last pending + * operation has finished. + * */ static class ProcessPipeInputStream extends BufferedInputStream { private final Object closeLock = new Object(); + private int useCount = 0; + private boolean closePending = false; ProcessPipeInputStream(int fd) { super(new FileInputStream(newFileDescriptor(fd))); @@ -382,12 +396,83 @@ } catch (IOException ignored) { } } + private void raise() { + synchronized (closeLock) { + useCount++; + } + } + + private void lower() throws IOException { + synchronized (closeLock) { + useCount--; + if (useCount == 0 && closePending) { + closePending = false; + super.close(); + } + } + } + + @Override + public int read() throws IOException { + raise(); + try { + return super.read(); + } finally { + lower(); + } + } + + @Override + public int read(byte[] b) throws IOException { + raise(); + try { + return super.read(b); + } finally { + lower(); + } + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + raise(); + try { + return super.read(b, off, len); + } finally { + lower(); + } + } + + @Override + public long skip(long n) throws IOException { + raise(); + try { + return super.skip(n); + } finally { + lower(); + } + } + + @Override + public int available() throws IOException { + raise(); + try { + return super.available(); + } finally { + lower(); + } + } + @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(); + if (useCount == 0) { + super.close(); + } + else { + closePending = true; + } } } } 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 @@ -1265,12 +1265,17 @@ if (ifreqP->ifr_addr.sa_family != AF_INET6) continue; + if (ioctl(sock, SIOCGIFSITE6, (char *)&if2) >= 0) { + struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifreqP->ifr_addr); + s6->sin6_scope_id = if2.ifr_site6; + } + /* * Add to the list */ ifs = addif(env, sock, ifreqP->ifr_name, ifs, (struct sockaddr *)&(ifreqP->ifr_addr), - AF_INET6, 0); + AF_INET6, 0); /* * If an exception occurred then free the list 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 @@ -996,11 +996,7 @@ { 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 }, @@ -1285,6 +1281,7 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, int len) { + #ifndef IPTOS_TOS_MASK #define IPTOS_TOS_MASK 0x1e #endif @@ -1305,9 +1302,6 @@ #else static long maxsockbuf = -1; #endif - - int addopt; - struct linger *ling; #endif /* @@ -1479,10 +1473,12 @@ } } +#endif +#if defined(_ALLBSD_SOURCE) || defined(_AIX) /* * On Solaris, SO_REUSEADDR will allow multiple datagram - * sockets to bind to the same port. The network jck tests + * sockets to bind to the same port. The network jck tests check * for this "feature", so we need to emulate it by turning on * SO_REUSEPORT as well for that combination. */ @@ -1496,11 +1492,9 @@ } if (sotype == SOCK_DGRAM) { - addopt = SO_REUSEPORT; - setsockopt(fd, level, addopt, arg, len); + setsockopt(fd, level, SO_REUSEPORT, arg, len); } } - #endif return setsockopt(fd, level, opt, arg, len); @@ -1670,7 +1664,7 @@ if (timeout <= 0) { return read_rv > 0 ? 0 : -1; } - newTime = prevTime; + prevTime = newTime; if (read_rv > 0) { break; 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 @@ -47,6 +47,12 @@ close subroutine does not return until the select call returns. ... */ +#if defined (_AIX) +extern int IO_Fcntl(int s, int cmd, void *arg); +extern int IO_Read(int s, void* buf, size_t len); +extern int IO_Write(int s, void* buf, size_t len); +#endif + #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); @@ -56,7 +62,7 @@ extern int NET_Send(int s, void *msg, int len, unsigned int flags); extern int NET_SendTo(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); -extern int NET_Writev(int s, const struct iovec * vector, int count); +extern int NET_WriteV(int s, const struct iovec * vector, int count); extern int NET_Connect(int s, struct sockaddr *addr, int addrlen); extern int NET_Accept(int s, struct sockaddr *addr, int *addrlen); extern int NET_SocketClose(int s); @@ -87,6 +93,12 @@ #endif +#ifdef _AIX +/* defined in src/aix/native/java/net/aix_close.c */ +int javaToNativeEvents(int javaEvents); +int nativeToJavaEvents(int nativeEvents); +#endif + #if defined(__linux__) && defined(AF_INET6) int getDefaultIPv6Interface(struct in6_addr *target_addr); #endif 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 @@ -433,7 +433,16 @@ struct dirent* dentp; jlong fds = 0; - dirp = opendir("/proc/self/fd"); +#if defined(_AIX) +/* AIX does not understand '/proc/self' - it requires the real process ID */ +#define FD_DIR aix_fd_dir + char aix_fd_dir[32]; /* the pid has at most 19 digits */ + snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid()); +#else +#define FD_DIR "/proc/self/fd" +#endif + + dirp = opendir(FD_DIR); if (dirp == NULL) { throw_internal_error(env, "Unable to open directory /proc/self/fd"); return -1; diff --git a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c --- a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c @@ -81,7 +81,7 @@ rv = connect(fd, 0, 0); #endif -#if defined(__linux__) || defined(_ALLBSD_SOURCE) +#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX) { int len; SOCKADDR sa; @@ -115,6 +115,14 @@ if (rv < 0 && errno == EADDRNOTAVAIL) rv = errno = 0; #endif +#if defined(_AIX) + /* See W. Richard Stevens, "UNIX Network Programming, Volume 1", p. 254: + * 'Setting the address family to AF_UNSPEC might return EAFNOSUPPORT + * but that is acceptable. + */ + if (rv < 0 && errno == EAFNOSUPPORT) + rv = errno = 0; +#endif } #endif diff --git a/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c b/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c --- a/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c +++ b/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c @@ -75,7 +75,11 @@ jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); +#ifdef _AIX + return convertReturnVal(env, IO_Read(fd, buf, len), JNI_TRUE); +#else return convertReturnVal(env, read(fd, buf, len), JNI_TRUE); +#endif } JNIEXPORT jint JNICALL @@ -94,7 +98,11 @@ { jint fd = fdval(env, fdo); struct iovec *iov = (struct iovec *)jlong_to_ptr(address); +#ifdef _AIX + return convertLongReturnVal(env, NET_ReadV(fd, iov, len), JNI_TRUE); +#else return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE); +#endif } JNIEXPORT jint JNICALL @@ -104,7 +112,11 @@ jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); +#ifdef _AIX + return convertReturnVal(env, IO_Write(fd, buf, len), JNI_FALSE); +#else return convertReturnVal(env, write(fd, buf, len), JNI_FALSE); +#endif } JNIEXPORT jint JNICALL @@ -123,7 +135,11 @@ { jint fd = fdval(env, fdo); struct iovec *iov = (struct iovec *)jlong_to_ptr(address); +#ifdef _AIX + return convertLongReturnVal(env, NET_WriteV(fd, iov, len), JNI_FALSE); +#else return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE); +#endif } static jlong @@ -147,6 +163,19 @@ if (md == JNI_FALSE) { result = fdatasync(fd); } else { +#ifdef _AIX + /* On AIX, calling fsync on a file descriptor that is opened only for + * reading results in an error ("EBADF: The FileDescriptor parameter is + * not a valid file descriptor open for writing."). + * However, at this point it is not possibly anymore to read the + * 'writable' attribute of the corresponding file channel so we have to + * use 'fcntl'. + */ + int getfl = fcntl(fd, F_GETFL); + if (getfl >= 0 && (getfl & O_ACCMODE) == O_RDONLY) { + return 0; + } +#endif result = fsync(fd); } return handle(env, result, "Force failed"); @@ -198,7 +227,13 @@ } else { cmd = F_SETLK64; } + +#ifdef _AIX + lockResult = IO_Fcntl(fd, cmd, &fl); +#else lockResult = fcntl(fd, cmd, &fl); +#endif + if (lockResult < 0) { if ((cmd == F_SETLK64) && (errno == EAGAIN || errno == EACCES)) return sun_nio_ch_FileDispatcherImpl_NO_LOCK; @@ -235,7 +270,16 @@ static void closeFileDescriptor(JNIEnv *env, int fd) { if (fd != -1) { +#ifdef _AIX + /* On AIX we can get a deadlock if a filedescriptor is closed + * asynchronously while being in accept() state. So better use + * the NET_SocketClose to get interruptible IO on AIX (see aix_close.c). + * (Dispite its name, this function also works for ordinary files.) + */ + int result = NET_SocketClose(fd); +#else int result = close(fd); +#endif if (result < 0) JNU_ThrowIOExceptionWithLastError(env, "Close failed"); } @@ -253,7 +297,11 @@ { jint fd = fdval(env, fdo); if (preCloseFD >= 0) { +#ifdef _AIX + if (NET_Dup2(preCloseFD, fd) < 0) +#else if (dup2(preCloseFD, fd) < 0) +#endif JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); } } 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 @@ -103,12 +103,24 @@ #endif /* IPV6_ADD_MEMBERSHIP */ +#if defined(_AIX) + +struct my_ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_sourceaddr; + struct in_addr imr_interface; +}; + +#else + struct my_ip_mreq_source { struct in_addr imr_multiaddr; struct in_addr imr_interface; struct in_addr imr_sourceaddr; }; +#endif /* _AIX */ + struct my_group_source_req { uint32_t gsr_interface; /* interface index */ struct sockaddr_storage gsr_group; /* group address */ @@ -198,7 +210,7 @@ JNIEXPORT jboolean JNICALL Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) { -#ifdef MACOSX +#if defined(MACOSX) || defined(_AIX) /* for now IPv6 sockets cannot join IPv4 multicast groups */ return JNI_FALSE; #else @@ -735,12 +747,21 @@ { struct pollfd pfd; int rv; +#ifdef _AIX + /* The hard coded event constants from Java do not match system values on AIX. */ + events = javaToNativeEvents(events); +#endif + pfd.fd = fdval(env, fdo); pfd.events = events; rv = poll(&pfd, 1, timeout); if (rv >= 0) { +#ifdef _AIX + return nativeToJavaEvents(pfd.revents); +#else return pfd.revents; +#endif } else if (errno == EINTR) { return IOS_INTERRUPTED; } else { diff --git a/src/solaris/native/sun/nio/ch/PollArrayWrapper.c b/src/solaris/native/sun/nio/ch/PollArrayWrapper.c --- a/src/solaris/native/sun/nio/ch/PollArrayWrapper.c +++ b/src/solaris/native/sun/nio/ch/PollArrayWrapper.c @@ -32,6 +32,11 @@ #include #include +#ifdef _AIX +/* needed for javaToNativeEvents()/nativeToJavaEvents() */ +#include "net_util_md.h" +#endif + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -78,12 +83,28 @@ a = (struct pollfd *) jlong_to_ptr(address); +#ifdef _AIX + /* The hard coded event constants from Java do not match the system values */ + int i; + for (i=0; i= 0) { break; }