Skip to content

Commit

Permalink
Remove OFF_T_SIZE and map portable ftruncate
Browse files Browse the repository at this point in the history
  • Loading branch information
dbwiddis committed Jun 14, 2020
1 parent 813b4a7 commit ecb4d66
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 99 deletions.
2 changes: 1 addition & 1 deletion CHANGES.md
Expand Up @@ -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
---------
Expand Down
4 changes: 2 additions & 2 deletions 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
Expand Down Expand Up @@ -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);

Expand Down
74 changes: 5 additions & 69 deletions contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java
Expand Up @@ -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.
* <p>
* Portable versions of C library methods which ensure appropriate bit width for
* {@code off_t} arguments are defined in {@link LibCUtil}.
*
* @see <A HREF=
* "https://pubs.opengroup.org/onlinepubs/009695399/utilities/c99.html#tagtcjh_11">IEEE
Expand All @@ -86,7 +89,6 @@ public ssize_t(long value) {
* Std 1003.1-2017 (POSIX v7)</A>
*/
class off_t extends IntegerType {
public static final off_t ZERO = new off_t();

private static final long serialVersionUID = 1L;

Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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.
* <p>
* 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').
* <p>
* 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.
* <p>
* 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
Expand Down
77 changes: 54 additions & 23 deletions contrib/platform/src/com/sun/jna/platform/unix/LibCUtil.java
Expand Up @@ -35,32 +35,23 @@ public class LibCUtil {

private static final NativeLibrary LIBC = NativeLibrary.getInstance("c");

/** Size of a native <code>off_t</code> 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() {
Expand Down Expand Up @@ -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.
* <p>
* 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').
* <p>
* 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");
Expand Down
Expand Up @@ -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;

Expand All @@ -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);
Expand Down

0 comments on commit ecb4d66

Please sign in to comment.