/
githubmirror
/
galahad
Обзор
Документация
Войти
/
githubmirror
/
galahad
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/aix/native/libnio/MappedMemoryUtils.c
232 строки
8 KB
Maurizio Cimadamore
8339285: Test fails with assert(depth < max_critical_stack_depth) failed: can't have more than 10 critical frames
05 сен 2024, 21:11
05 сен 2024, 21:11
9e1af8c
Код
Авторство
О чём код?
/* * Copyright (c) 2001, 2024, 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 "jni.h" #include "jni_util.h" #include "jvm.h" #include "jlong.h" #include "java_nio_MappedMemoryUtils.h" #include <assert.h> #include <sys/mman.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include <sys/procfs.h> #include <unistd.h> typedef char mincore_vec_t; static long calculate_number_of_pages_in_range(void* address, size_t len, size_t pagesize) { uintptr_t address_unaligned = (uintptr_t) address; uintptr_t address_aligned = address_unaligned & (~(pagesize - 1)); size_t len2 = len + (address_unaligned - address_aligned); long numPages = (len2 + pagesize - 1) / pagesize; return numPages; } jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, jlong len, jlong numPages) { jboolean loaded = JNI_TRUE; int result = 0; long i = 0; void *a = (void *) jlong_to_ptr(address); mincore_vec_t* vec = NULL; /* See JDK-8186665 */ size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); if ((long)pagesize == -1) { return JNI_FALSE; } numPages = (jlong) calculate_number_of_pages_in_range(a, len, pagesize); /* Include space for one sentinel byte at the end of the buffer * to catch overflows. */ vec = (mincore_vec_t*) malloc(numPages + 1); if (vec == NULL) { JNU_ThrowOutOfMemoryError(env, NULL); return JNI_FALSE; } vec[numPages] = '\x7f'; /* Write sentinel. */ result = mincore(a, (size_t)len, vec); assert(vec[numPages] == '\x7f'); /* Check sentinel. */ if (result == -1) { JNU_ThrowIOExceptionWithLastError(env, "mincore failed"); free(vec); return JNI_FALSE; } for (i=0; i<numPages; i++) { if (vec[i] == 0) { loaded = JNI_FALSE; break; } } free(vec); return loaded; } void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, jlong len) { char *a = (char *)jlong_to_ptr(address); int result = madvise((caddr_t)a, (size_t)len, MADV_WILLNEED); if (result == -1) { JNU_ThrowIOExceptionWithMessageAndLastError(env, "madvise with advise MADV_WILLNEED failed"); } } void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, jlong len) { char *a = (char *)jlong_to_ptr(address); int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED); if (result == -1) { JNU_ThrowIOExceptionWithMessageAndLastError(env, "madvise with advise MADV_DONTNEED failed"); } } static void set_error_if_shared(JNIEnv* env, prmap_t* map_entry) { if (map_entry->pr_mflags & MA_SHARED) { // MA_SHARED => MAP_SHARED => !MAP_PRIVATE. This error is valid and should be thrown. JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed (MAP_SHARED)"); return; } else { // O.W. MAP_PRIVATE or no flag was specified and EINVAL is the expected behaviour. return; } } static void check_proc_map_array(JNIEnv* env, FILE* proc_file, prmap_t* map_entry, void* end_address) { while (!feof(proc_file)) { memset(map_entry, '\0', sizeof(prmap_t)); fread((char*)map_entry, sizeof(prmap_t), 1, proc_file); if (ferror(proc_file)) { JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed (could not read /proc/<pid>/map)"); return; } else if (map_entry->pr_vaddr <= end_address && (uint64_t)end_address <= (uint64_t)map_entry->pr_vaddr + map_entry->pr_size) { set_error_if_shared(env, map_entry); return; } } JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed (address not found)"); } // '/proc/' + <pid> + '/map' + '\0' #define PFNAME_LEN 32 static void check_aix_einval(JNIEnv* env, void* end_address) { // If EINVAL is set for a mmap address on AIX, additional validation is required. // AIX will set EINVAL when msync is called on a mmap address that didn't receive MAP_SHARED // as a flag (since MAP_PRIVATE is the default). // https://www.ibm.com/docs/en/aix/7.2?topic=m-msync-subroutine FILE* proc_file; { char* fname = (char*) malloc(sizeof(char) * PFNAME_LEN); if (fname == NULL) { JNU_ThrowOutOfMemoryError(env, NULL); return; } pid_t the_pid = getpid(); jio_snprintf(fname, PFNAME_LEN, "/proc/%d/map", the_pid); proc_file = fopen(fname, "r"); free(fname); } if (!proc_file) { JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed (could not open /proc/<pid>/map)"); return; } { prmap_t* map_entry = (prmap_t*) malloc(sizeof(prmap_t)); if (map_entry == NULL) { JNU_ThrowOutOfMemoryError(env, NULL); fclose(proc_file); return; } check_proc_map_array(env, proc_file, map_entry, end_address); free(map_entry); } fclose(proc_file); } // Normally we would just let msync handle this, but since we'll be (potentially) ignoring // the error code returned by msync, we check the args before the call instead. static int validate_msync_address(size_t address) { size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); if (address % pagesize != 0) { errno = EINVAL; return -1; } return 0; } void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, jlong address, jlong len) { void* a = (void *)jlong_to_ptr(address); if (validate_msync_address((size_t)a) > 0) { JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed (arguments invalid)"); return; } int result = msync(a, (size_t)len, MS_SYNC); if (result == -1) { void* end_address = (void*)jlong_to_ptr(address + len); if (errno == EINVAL) { check_aix_einval(env, end_address); return; } JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed"); } } #define FD "Ljava/io/FileDescriptor;" static JNINativeMethod methods[] = { {"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0}, {"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0}, {"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0}, {"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0}, }; JNIEXPORT void JNICALL Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls) { (*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])); }