Library.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.jni;
import java.io.File;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public final class Library {
/*
* Default library names - use 1.x in preference to 2.x if both are available as only 1.x supports the APR/Native
* connector.
*/
private static final String [] NAMES = {"tcnative-1", "libtcnative-1", "tcnative-2", "libtcnative-2"};
/* System property used to define CATALINA_HOME */
private static final String CATALINA_HOME_PROP = "catalina.home";
/*
* A handle to the unique Library singleton instance.
*/
private static Library _instance = null;
private static final AtomicLong generation = new AtomicLong(0);
private static final ReadWriteLock cleanUpLock = new ReentrantReadWriteLock();
private Library() throws Exception {
boolean loaded = false;
StringBuilder err = new StringBuilder();
File binLib = new File(System.getProperty(CATALINA_HOME_PROP), "bin");
for (int i = 0; i < NAMES.length; i++) {
File library = new File(binLib, System.mapLibraryName(NAMES[i]));
try {
System.load(library.getAbsolutePath());
loaded = true;
} catch (ThreadDeath | VirtualMachineError t) {
throw t;
} catch (Throwable t) {
if (library.exists()) {
// File exists but failed to load
throw t;
}
if (i > 0) {
err.append(", ");
}
err.append(t.getMessage());
}
if (loaded) {
break;
}
}
if (!loaded) {
String path = System.getProperty("java.library.path");
String [] paths = path.split(File.pathSeparator);
for (String value : NAMES) {
try {
System.loadLibrary(value);
loaded = true;
} catch (ThreadDeath | VirtualMachineError t) {
throw t;
} catch (Throwable t) {
String name = System.mapLibraryName(value);
for (String s : paths) {
File fd = new File(s, name);
if (fd.exists()) {
// File exists but failed to load
throw t;
}
}
if (err.length() > 0) {
err.append(", ");
}
err.append(t.getMessage());
}
if (loaded) {
break;
}
}
}
if (!loaded) {
StringBuilder names = new StringBuilder();
for (String name : NAMES) {
names.append(name);
names.append(", ");
}
throw new LibraryNotFoundError(names.substring(0, names.length() -2), err.toString());
}
}
private Library(String libraryName)
{
System.loadLibrary(libraryName);
}
/**
* Create Tomcat Native's global APR pool. This has to be the first call to TCN library.
*/
private static native boolean initialize();
/**
* Allows for thread safe termination when other threads may be attempting clean-up concurrently with the current
* thread. Waits for any threads currently holding the clean-up lock to release the lock and then calls
* {@link #terminate()}.
*/
public static void threadSafeTerminate() {
cleanUpLock.writeLock().lock();
try {
terminate();
} finally {
generation.incrementAndGet();
cleanUpLock.writeLock().unlock();
}
}
/**
* Destroys Tomcat Native's global APR pool. This has to be the last call to TCN library. This will destroy any APR
* root pools that have not been explicitly destroyed.
* <p>
* This method should only be used if the caller is certain that all other threads have finished using the native
* library.
*/
public static native void terminate();
/* Internal function for loading APR Features */
private static native boolean has(int what);
/* Internal function for loading APR Features */
private static native int version(int what);
/* Internal function for loading APR sizes */
private static native int size(int what);
/* TCN_MAJOR_VERSION */
public static int TCN_MAJOR_VERSION = 0;
/* TCN_MINOR_VERSION */
public static int TCN_MINOR_VERSION = 0;
/* TCN_PATCH_VERSION */
public static int TCN_PATCH_VERSION = 0;
/* TCN_IS_DEV_VERSION */
public static int TCN_IS_DEV_VERSION = 0;
/* APR_MAJOR_VERSION */
public static int APR_MAJOR_VERSION = 0;
/* APR_MINOR_VERSION */
public static int APR_MINOR_VERSION = 0;
/* APR_PATCH_VERSION */
public static int APR_PATCH_VERSION = 0;
/* APR_IS_DEV_VERSION */
public static int APR_IS_DEV_VERSION = 0;
/* TCN_VERSION_STRING */
public static native String versionString();
/* APR_VERSION_STRING */
public static native String aprVersionString();
/* APR Feature Macros */
@Deprecated
public static boolean APR_HAVE_IPV6 = false;
@Deprecated
public static boolean APR_HAS_SHARED_MEMORY = false;
@Deprecated
public static boolean APR_HAS_THREADS = false;
@Deprecated
public static boolean APR_HAS_SENDFILE = false;
@Deprecated
public static boolean APR_HAS_MMAP = false;
@Deprecated
public static boolean APR_HAS_FORK = false;
@Deprecated
public static boolean APR_HAS_RANDOM = false;
@Deprecated
public static boolean APR_HAS_OTHER_CHILD = false;
@Deprecated
public static boolean APR_HAS_DSO = false;
@Deprecated
public static boolean APR_HAS_SO_ACCEPTFILTER = false;
@Deprecated
public static boolean APR_HAS_UNICODE_FS = false;
@Deprecated
public static boolean APR_HAS_PROC_INVOKED = false;
@Deprecated
public static boolean APR_HAS_USER = false;
@Deprecated
public static boolean APR_HAS_LARGE_FILES = false;
@Deprecated
public static boolean APR_HAS_XTHREAD_FILES = false;
@Deprecated
public static boolean APR_HAS_OS_UUID = false;
/* Are we big endian? */
@Deprecated
public static boolean APR_IS_BIGENDIAN = false;
/* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible
* to poll on files/pipes.
*/
@Deprecated
public static boolean APR_FILES_AS_SOCKETS = false;
/* This macro indicates whether or not EBCDIC is the native character set.
*/
@Deprecated
public static boolean APR_CHARSET_EBCDIC = false;
/* Is the TCP_NODELAY socket option inherited from listening sockets?
*/
@Deprecated
public static boolean APR_TCP_NODELAY_INHERITED = false;
/* Is the O_NONBLOCK flag inherited from listening sockets?
*/
@Deprecated
public static boolean APR_O_NONBLOCK_INHERITED = false;
/* Poll operations are interruptable by apr_pollset_wakeup().
*/
@Deprecated
public static boolean APR_POLLSET_WAKEABLE = false;
/* Support for Unix Domain Sockets.
*/
@Deprecated
public static boolean APR_HAVE_UNIX = false;
@Deprecated
public static int APR_SIZEOF_VOIDP;
@Deprecated
public static int APR_PATH_MAX;
@Deprecated
public static int APRMAXHOSTLEN;
@Deprecated
public static int APR_MAX_IOVEC_SIZE;
@Deprecated
public static int APR_MAX_SECS_TO_LINGER;
@Deprecated
public static int APR_MMAP_THRESHOLD;
@Deprecated
public static int APR_MMAP_LIMIT;
/* return global TCN's APR pool */
@Deprecated
public static native long globalPool();
/**
* Setup any APR internal data structures. This MUST be the first function
* called for any APR library.
* @param libraryName the name of the library to load
*
* @return {@code true} if the native code was initialized successfully
* otherwise {@code false}
*
* @throws Exception if a problem occurred during initialization
*/
public static synchronized boolean initialize(String libraryName) throws Exception {
if (_instance == null) {
if (libraryName == null) {
_instance = new Library();
} else {
_instance = new Library(libraryName);
}
TCN_MAJOR_VERSION = version(0x01);
TCN_MINOR_VERSION = version(0x02);
TCN_PATCH_VERSION = version(0x03);
TCN_IS_DEV_VERSION = version(0x04);
APR_MAJOR_VERSION = version(0x11);
APR_MINOR_VERSION = version(0x12);
APR_PATCH_VERSION = version(0x13);
APR_IS_DEV_VERSION = version(0x14);
APR_SIZEOF_VOIDP = size(1);
APR_PATH_MAX = size(2);
APRMAXHOSTLEN = size(3);
APR_MAX_IOVEC_SIZE = size(4);
APR_MAX_SECS_TO_LINGER = size(5);
APR_MMAP_THRESHOLD = size(6);
APR_MMAP_LIMIT = size(7);
APR_HAVE_IPV6 = has(0);
APR_HAS_SHARED_MEMORY = has(1);
APR_HAS_THREADS = has(2);
APR_HAS_SENDFILE = has(3);
APR_HAS_MMAP = has(4);
APR_HAS_FORK = has(5);
APR_HAS_RANDOM = has(6);
APR_HAS_OTHER_CHILD = has(7);
APR_HAS_DSO = has(8);
APR_HAS_SO_ACCEPTFILTER = has(9);
APR_HAS_UNICODE_FS = has(10);
APR_HAS_PROC_INVOKED = has(11);
APR_HAS_USER = has(12);
APR_HAS_LARGE_FILES = has(13);
APR_HAS_XTHREAD_FILES = has(14);
APR_HAS_OS_UUID = has(15);
APR_IS_BIGENDIAN = has(16);
APR_FILES_AS_SOCKETS = has(17);
APR_CHARSET_EBCDIC = has(18);
APR_TCP_NODELAY_INHERITED = has(19);
APR_O_NONBLOCK_INHERITED = has(20);
APR_POLLSET_WAKEABLE = has(21);
APR_HAVE_UNIX = has(22);
if (APR_MAJOR_VERSION < 1) {
throw new UnsatisfiedLinkError("Unsupported APR Version (" +
aprVersionString() + ")");
}
if (!APR_HAS_THREADS) {
throw new UnsatisfiedLinkError("Missing threading support from APR");
}
}
return initialize();
}
public static boolean tryCleanUpLock(long cleanupGeneration) {
try {
boolean result = cleanUpLock.readLock().tryLock(0, TimeUnit.SECONDS);
if (result) {
if (generation.get() == cleanupGeneration) {
return true;
}
cleanUpLock.readLock().unlock();
}
} catch (InterruptedException e) {
// Treated the same way as not getting the lock
}
return false;
}
public static long getGeneration() {
return generation.get();
}
public static void returnCleanUpLock() {
cleanUpLock.readLock().unlock();
}
/**
* Calls System.load(filename). System.load() associates the
* loaded library with the class loader of the class that called
* the System method. A native library may not be loaded by more
* than one class loader, so calling the System method from a class that
* was loaded by a Webapp class loader will make it impossible for
* other Webapps to load it.
*
* Using this method will load the native library via a shared class
* loader (typically the Common class loader, but may vary in some
* configurations), so that it can be loaded by multiple Webapps.
*
* @param filename - absolute path of the native library
*
* @deprecated Unused. Will be removed in Tomcat 10.1.x
*/
@Deprecated
public static void load(String filename){
System.load(filename);
}
/**
* Calls System.loadLibrary(libname). System.loadLibrary() associates the
* loaded library with the class loader of the class that called
* the System method. A native library may not be loaded by more
* than one class loader, so calling the System method from a class that
* was loaded by a Webapp class loader will make it impossible for
* other Webapps to load it.
*
* Using this method will load the native library via a shared class
* loader (typically the Common class loader, but may vary in some
* configurations), so that it can be loaded by multiple Webapps.
*
* @param libname - the name of the native library
*
* @deprecated Unused. Will be removed in Tomcat 10.1.x
*/
@Deprecated
public static void loadLibrary(String libname){
System.loadLibrary(libname);
}
}