From ecb4d6684036236326fa9aa2873fa4e2f09a6006 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sun, 14 Jun 2020 15:28:59 -0700 Subject: [PATCH] Remove OFF_T_SIZE and map portable ftruncate --- CHANGES.md | 2 +- .../src/com/sun/jna/platform/linux/LibC.java | 4 +- .../com/sun/jna/platform/unix/LibCAPI.java | 74 ++---------------- .../com/sun/jna/platform/unix/LibCUtil.java | 77 +++++++++++++------ .../com/sun/jna/platform/linux/LibRTTest.java | 6 +- 5 files changed, 64 insertions(+), 99 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 60bdf75096..36b7b130df 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,7 +17,7 @@ Features * [#1194](https://github.com/java-native-access/jna/pull/1194): Add `GetConsoleScreenBufferInfo`, `ReadConsoleInput` and `WriteConsole` with associated structures to `c.s.j.p.win32.Wincon` - [@rednoah](https://github.com/rednoah). * [#1198](https://github.com/java-native-access/jna/pull/1198): Add `NetSessionEnum` to `c.s.j.p.win32.Netapi32` and `WTSEnumerateSessions`, `WTSQuerySessionInformation`, and `WTSFreeMemory` to `c.s.j.p.win32.Wtsapi32` - [@dbwiddis](https://github.com/dbwiddis). * [#1200](https://github.com/java-native-access/jna/pull/1200): Add mappings for `libudev` to `c.s.j.p.linux.Udev` - [@dbwiddis](https://github.com/dbwiddis). -* [#1202](https://github.com/java-native-access/jna/pull/1202): Add mappings supporting shared memory `c.s.j.p.unix.LibCAPI` including `size_t`, `ssize_t`, and `off_t` types and `mmap()`, `munmap()`, `msync()`, `ftruncate()`, and `close()` methods, `c.s.j.p.unix.LibCUtil` exposing `OFF_T_SIZE` and mapping `mmap()`, `c.s.j.p.linux.LibRT` methods `shm_open()` and `shm_unlink()` - [@dbwiddis](https://github.com/dbwiddis). +* [#1202](https://github.com/java-native-access/jna/pull/1202): Add mappings supporting shared memory `c.s.j.p.unix.LibCAPI` including `size_t`, `ssize_t`, and `off_t` types, `c.s.j.p.linux.LibC` methods `munmap()`, `msync()`, and `close()`, `c.s.j.p.unix.LibCUtil` mapping `mmap()` and `ftruncate()`, and `c.s.j.p.linux.LibRT` methods `shm_open()` and `shm_unlink()` - [@dbwiddis](https://github.com/dbwiddis). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/linux/LibC.java b/contrib/platform/src/com/sun/jna/platform/linux/LibC.java index c5e2860bba..ae21e0c9c5 100644 --- a/contrib/platform/src/com/sun/jna/platform/linux/LibC.java +++ b/contrib/platform/src/com/sun/jna/platform/linux/LibC.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2017,2020 Daniel Widdis, All Rights Reserved +/* Copyright (c) 2017 Daniel Widdis, All Rights Reserved * * The contents of this file is dual-licensed under 2 * alternative Open Source/Free licenses: LGPL 2.1 or later and @@ -38,7 +38,7 @@ /** * LibC structures and functions unique to Linux */ -public interface LibC extends LibCAPI, ErrNo, Fcntl, Mman, Library { +public interface LibC extends LibCAPI, Library { String NAME = "c"; LibC INSTANCE = Native.load(NAME, LibC.class); diff --git a/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java b/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java index ba202fc04b..23dce12c45 100644 --- a/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java +++ b/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java @@ -77,6 +77,9 @@ public ssize_t(long value) { * systems, the bit width of this type may be dependent on compile-time options * in the end-user's library. The parameter {@code ilp32OffBig} permits this * type to be defined as 64-bit on a 32-bit operating system. + *

+ * Portable versions of C library methods which ensure appropriate bit width for + * {@code off_t} arguments are defined in {@link LibCUtil}. * * @see IEEE @@ -86,7 +89,6 @@ public ssize_t(long value) { * Std 1003.1-2017 (POSIX v7) */ class off_t extends IntegerType { - public static final off_t ZERO = new off_t(); private static final long serialVersionUID = 1L; @@ -128,7 +130,7 @@ public off_t(long value) { * If {@code true}, use 64-bit width. */ public off_t(long value, boolean ilp32OffBig) { - super(ilp32OffBig ? 8 : LibCUtil.OFF_T_SIZE, value); + super(ilp32OffBig ? 8 : Native.LONG_SIZE, value); } } @@ -221,75 +223,9 @@ public off_t(long value, boolean ilp32OffBig) { */ int close(int fd); - /** - * Causes the regular file referenced by {@code fd} to be truncated to a size of - * precisely {@code length} bytes. - *

- * If the file previously was larger than this size, the extra data is lost. If - * the file previously was shorter, it is extended, and the extended part reads - * as null bytes ('\0'). - *

- * The file must be open for writing - * - * @param fd - * a file descriptor - * @param length - * the number of bytes to truncate or extend the file to - * @return On success, zero is returned. On error, -1 is returned, and - * {@code errno} is set appropriately. - */ - int ftruncate(int fd, off_t length); - - /** - * Creates a new mapping in the virtual address space of the calling process. - * - * @param addr - * The starting address for the new mapping. - *

- * If {@code addr} is NULL, then the kernel chooses the - * (page-aligned) address at which to create the mapping; this is the - * most portable method of creating a new mapping. If {@code addr} is - * not NULL, then the kernel takes it as a hint about where to place - * the mapping; on Linux, the kernel will pick a nearby page boundary - * (but always above or equal to the value specified by - * {@code /proc/sys/vm/mmap_min_addr}) and attempt to create the - * mapping there. If another mapping already exists there, the kernel - * picks a new address that may or may not depend on the hint. The - * address of the new mapping is returned as the result of the call. - * @param length - * Specifies the length of the mapping (which must be greater than - * 0). - * @param prot - * describes the desired memory protection of the mapping (and must - * not conflict with the open mode of the file). It is either - * {@code PROT_NONE} or the bitwise OR of one or more of - * {@code PROT_READ}, {@code PROT_WRITE}, or {@code PROT_EXEC}. - * @param flags - * determines whether updates to the mapping are visible to other - * processes mapping the same region, and whether updates are carried - * through to the underlying file. This behavior is determined by - * including exactly one of {@code MAP_SHARED}, - * {@code MAP_SHARED_VALIDATE}, or {@code MAP_PRIVATE}. In addition, - * 0 or more additional flags can be ORed in {@code flags}. - * @param fd - * The file descriptor for the object to be mapped. After the - * {@code mmap()} call has returned, the file descriptor can be - * closed immediately without invalidating the mapping. - * @param offset - * The contents of a file mapping (as opposed to an anonymous - * mapping), are initialized using {@code length} bytes starting at - * offset {@code offset} in the file (or other object) referred to by - * the file descriptor, {@code fd}. {@code offset} must be a multiple - * of the page size as returned by {@code sysconf(_SC_PAGE_SIZE)}. - * @return On success, returns a pointer to the mapped area. On error, the value - * {@code MAP_FAILED} (that is, (void *) -1) is returned, and - * {@code errno} is set to indicate the cause of the error. - */ - Pointer mmap(Pointer addr, size_t length, int prot, int flags, int fd, off_t offset); - /** * Flushes changes made to the in-core copy of a file that was mapped into - * memory using {@link LibCAPI#mmap(Pointer, size_t, int, int, int, off_t)} back + * memory using {@link LibCUtil#mmap(Pointer, long, int, int, int, long)} back * to the filesystem. Without use of this call, there is no guarantee that * changes are written back before {@link #munmap(Pointer, size_t)} is called. * To be more precise, the part of the file that corresponds to the memory area diff --git a/contrib/platform/src/com/sun/jna/platform/unix/LibCUtil.java b/contrib/platform/src/com/sun/jna/platform/unix/LibCUtil.java index 39e616f4e0..df9ec2af97 100644 --- a/contrib/platform/src/com/sun/jna/platform/unix/LibCUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/unix/LibCUtil.java @@ -35,32 +35,23 @@ public class LibCUtil { private static final NativeLibrary LIBC = NativeLibrary.getInstance("c"); - /** Size of a native off_t type, in bytes. */ - public static final int OFF_T_SIZE; - static { - // Observations shows, that without LFS, on linux, solaris, aix, mac OS and - // windows (apart from cygwin32) sizeof(off_t) == sizeof(long) - int size = Native.LONG_SIZE; - // On 64-bit, off_t is 64 bit, otherwise test compiler flags that would create - // 64-bit versions of off_t functions - if (size < 8) { - try { - LIBC.getFunction("mmap64", Function.THROW_LAST_ERROR); - // on 32-bit, mmap64 only exists when off_t is 64-bit - size = 8; - } catch (UnsatisfiedLinkError ex) { - } - } - OFF_T_SIZE = size; - } - - private static Function mmap; + private static Function mmap = null; + private static boolean mmap64 = false; + private static Function ftruncate = null; + private static boolean ftruncate64 = false; static { try { mmap = LIBC.getFunction("mmap64", Function.THROW_LAST_ERROR); + mmap64 = true; } catch (UnsatisfiedLinkError ex) { mmap = LIBC.getFunction("mmap", Function.THROW_LAST_ERROR); } + try { + ftruncate = LIBC.getFunction("ftruncate64", Function.THROW_LAST_ERROR); + ftruncate64 = true; + } catch (UnsatisfiedLinkError ex) { + ftruncate = LIBC.getFunction("ftruncate", Function.THROW_LAST_ERROR); + } } private LibCUtil() { @@ -123,15 +114,55 @@ public static Pointer mmap(Pointer addr, long length, int prot, int flags, int f params[2] = prot; params[3] = flags; params[4] = fd; - if (OFF_T_SIZE == 4) { + if (mmap64) { + params[5] = offset; + } else { require32Bit(offset, "offset"); params[5] = (int) offset; - } else { - params[5] = offset; } return mmap.invokePointer(params); } + /** + * Causes the regular file referenced by {@code fd} to be truncated to a size of + * precisely {@code length} bytes. + *

+ * If the file previously was larger than this size, the extra data is lost. If + * the file previously was shorter, it is extended, and the extended part reads + * as null bytes ('\0'). + *

+ * The file must be open for writing + * + * @param fd + * a file descriptor + * @param length + * the number of bytes to truncate or extend the file to + * @return On success, zero is returned. On error, -1 is returned, and + * {@code errno} is set appropriately. + */ + public static int ftruncate(int fd, long length) { + Object[] params = new Object[2]; + params[0] = fd; + if (ftruncate64) { + params[1] = length; + } else { + require32Bit(length, "length"); + params[1] = (int) length; + } + return ftruncate.invokeInt(params); + } + + /** + * Test that a value is 32-bit, throwing a custom exception otherwise + * + * @param val + * The value to test + * @param value + * The name of the value, to be inserted in the exception message if + * not 32-bit + * @throws IllegalArgumentException + * if {@code val} is not 32-bit + */ public static void require32Bit(long val, String value) { if (val > Integer.MAX_VALUE) { throw new IllegalArgumentException(value + " exceeds 32bit"); diff --git a/contrib/platform/test/com/sun/jna/platform/linux/LibRTTest.java b/contrib/platform/test/com/sun/jna/platform/linux/LibRTTest.java index 32800ba69c..73a0ce3b7a 100644 --- a/contrib/platform/test/com/sun/jna/platform/linux/LibRTTest.java +++ b/contrib/platform/test/com/sun/jna/platform/linux/LibRTTest.java @@ -42,7 +42,6 @@ import com.sun.jna.Native; import com.sun.jna.Pointer; -import com.sun.jna.platform.unix.LibCAPI.off_t; import com.sun.jna.platform.unix.LibCAPI.size_t; import com.sun.jna.platform.unix.LibCUtil; @@ -66,12 +65,11 @@ public void testMmapToShm() throws IOException { // Multiply by 4 to handle all possible encodings int bufLen = 4 * (share.length() + 1); size_t length = new size_t(bufLen); - off_t truncLen = new off_t(bufLen); // Allocate memory to the share (fills with null bytes) - int ret = LIBC.ftruncate(fd, truncLen); + int ret = LibCUtil.ftruncate(fd, bufLen); assertNotEquals("Failed to ftruncate. Error: " + Native.getLastError(), -1, ret); // Map a pointer to the share. Offset must be a multiple of page size - Pointer p = LIBC.mmap(null, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, off_t.ZERO); + Pointer p = LibCUtil.mmap(null, bufLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); assertNotEquals("Failed mmap to new share. Error: " + Native.getLastError(), MAP_FAILED, p); // We can now close the file descriptor ret = LIBC.close(fd);