2011-02-09 11:08:10 +01:00
/*
2019-01-13 16:54:01 -05:00
* Copyright ( c ) 1999 , 2019 , Oracle and / or its affiliates . All rights reserved .
2013-07-26 00:59:18 +02:00
* 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 .
*
* 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 .
*
*/
2011-02-09 11:08:10 +01:00
2017-10-31 11:55:09 -04:00
# include "jvm.h"
2018-03-23 18:54:12 +01:00
# include "logging/log.hpp"
2018-03-08 09:56:29 +01:00
# include "memory/allocation.inline.hpp"
2019-02-05 20:18:00 -05:00
# include "os_posix.inline.hpp"
2013-07-26 00:59:18 +02:00
# include "utilities/globalDefinitions.hpp"
2012-06-28 17:03:16 -04:00
# include "runtime/frame.inline.hpp"
2018-03-16 09:12:13 -04:00
# include "runtime/interfaceSupport.inline.hpp"
2018-03-08 09:56:29 +01:00
# include "services/memTracker.hpp"
2017-07-05 11:33:17 +02:00
# include "utilities/align.hpp"
2019-03-08 11:23:30 +01:00
# include "utilities/events.hpp"
2018-03-23 18:54:12 +01:00
# include "utilities/formatBuffer.hpp"
2016-07-13 12:23:05 +02:00
# include "utilities/macros.hpp"
2011-02-09 11:08:10 +01:00
# include "utilities/vmError.hpp"
2018-07-17 15:59:47 -04:00
# include <dirent.h>
2017-05-30 17:14:52 -04:00
# include <dlfcn.h>
2018-11-15 17:08:59 +01:00
# include <grp.h>
# include <pwd.h>
2013-08-29 11:05:55 +02:00
# include <pthread.h>
# include <signal.h>
2017-11-29 17:03:10 -08:00
# include <sys/mman.h>
2017-05-30 17:14:52 -04:00
# include <sys/resource.h>
# include <sys/utsname.h>
# include <time.h>
# include <unistd.h>
2012-05-10 15:44:19 +02:00
2013-07-26 00:59:18 +02:00
// Todo: provide a os::get_max_process_id() or similar. Number of processes
// may have been configured, can be read more accurately from proc fs etc.
# ifndef MAX_PID
# define MAX_PID INT_MAX
# endif
# define IS_VALID_PID(p) (p > 0 && p < MAX_PID)
2011-02-09 11:08:10 +01:00
2018-05-31 14:09:04 -07:00
# define ROOT_UID 0
2017-11-29 17:03:10 -08:00
# ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
# endif
# define check_with_errno(check_type, cond, msg) \
do { \
int err = errno ; \
check_type ( cond , " %s; error='%s' (errno=%s) " , msg , os : : strerror ( err ) , \
os : : errno_name ( err ) ) ; \
} while ( false )
# define assert_with_errno(cond, msg) check_with_errno(assert, cond, msg)
# define guarantee_with_errno(cond, msg) check_with_errno(guarantee, cond, msg)
2011-02-09 11:08:10 +01:00
// Check core dump limit and report possible place where core can be found
2015-04-15 17:34:28 -07:00
void os : : check_dump_limit ( char * buffer , size_t bufferSize ) {
2016-05-09 14:15:39 +03:00
if ( ! FLAG_IS_DEFAULT ( CreateCoredumpOnCrash ) & & ! CreateCoredumpOnCrash ) {
jio_snprintf ( buffer , bufferSize , " CreateCoredumpOnCrash is disabled from command line " ) ;
VMError : : record_coredump_status ( buffer , false ) ;
return ;
}
2012-07-03 17:35:00 -07:00
int n ;
2011-02-09 11:08:10 +01:00
struct rlimit rlim ;
bool success ;
2014-12-14 20:18:17 -05:00
char core_path [ PATH_MAX ] ;
n = get_core_path ( core_path , PATH_MAX ) ;
2011-02-09 11:08:10 +01:00
2014-12-14 20:18:17 -05:00
if ( n < = 0 ) {
jio_snprintf ( buffer , bufferSize , " core.%d (may not exist) " , current_process_id ( ) ) ;
success = true ;
# ifdef LINUX
} else if ( core_path [ 0 ] = = ' " ' ) { // redirect to user process
jio_snprintf ( buffer , bufferSize , " Core dumps may be processed with %s " , core_path ) ;
success = true ;
# endif
} else if ( getrlimit ( RLIMIT_CORE , & rlim ) ! = 0 ) {
jio_snprintf ( buffer , bufferSize , " %s (may not exist) " , core_path ) ;
2011-02-09 11:08:10 +01:00
success = true ;
} else {
switch ( rlim . rlim_cur ) {
case RLIM_INFINITY :
2014-12-14 20:18:17 -05:00
jio_snprintf ( buffer , bufferSize , " %s " , core_path ) ;
2011-02-09 11:08:10 +01:00
success = true ;
break ;
case 0 :
jio_snprintf ( buffer , bufferSize , " Core dumps have been disabled. To enable core dumping, try \" ulimit -c unlimited \" before starting Java again " ) ;
success = false ;
break ;
default :
2017-05-30 15:41:23 -07:00
jio_snprintf ( buffer , bufferSize , " %s (max size " UINT64_FORMAT " kB). To ensure a full core dump, try \" ulimit -c unlimited \" before starting Java again " , core_path , uint64_t ( rlim . rlim_cur ) / 1024 ) ;
2011-02-09 11:08:10 +01:00
success = true ;
break ;
}
}
2014-12-14 20:18:17 -05:00
2015-04-15 17:34:28 -07:00
VMError : : record_coredump_status ( buffer , success ) ;
2011-02-09 11:08:10 +01:00
}
2014-08-07 12:18:58 -07:00
int os : : get_native_stack ( address * stack , int frames , int toSkip ) {
int frame_idx = 0 ;
int num_of_frames ; // number of frames captured
2012-06-28 17:03:16 -04:00
frame fr = os : : current_frame ( ) ;
2014-08-07 12:18:58 -07:00
while ( fr . pc ( ) & & frame_idx < frames ) {
if ( toSkip > 0 ) {
toSkip - - ;
} else {
stack [ frame_idx + + ] = fr . pc ( ) ;
}
2014-12-12 13:19:33 -05:00
if ( fr . fp ( ) = = NULL | | fr . cb ( ) ! = NULL | |
fr . sender_pc ( ) = = NULL | | os : : is_first_C_frame ( & fr ) ) break ;
2014-08-07 12:18:58 -07:00
if ( fr . sender_pc ( ) & & ! os : : is_first_C_frame ( & fr ) ) {
fr = os : : get_sender_for_C_frame ( & fr ) ;
} else {
break ;
}
2012-06-28 17:03:16 -04:00
}
2014-08-07 12:18:58 -07:00
num_of_frames = frame_idx ;
for ( ; frame_idx < frames ; frame_idx + + ) {
stack [ frame_idx ] = NULL ;
2012-06-28 17:03:16 -04:00
}
2014-08-07 12:18:58 -07:00
return num_of_frames ;
}
bool os : : unsetenv ( const char * name ) {
assert ( name ! = NULL , " Null pointer " ) ;
return ( : : unsetenv ( name ) = = 0 ) ;
2012-06-28 17:03:16 -04:00
}
2012-01-03 15:11:31 -05:00
int os : : get_last_error ( ) {
return errno ;
}
2018-07-03 15:08:01 -04:00
size_t os : : lasterror ( char * buf , size_t len ) {
if ( errno = = 0 ) return 0 ;
const char * s = os : : strerror ( errno ) ;
size_t n = : : strlen ( s ) ;
if ( n > = len ) {
n = len - 1 ;
}
: : strncpy ( buf , s , n ) ;
buf [ n ] = ' \0 ' ;
return n ;
}
2011-02-28 14:19:52 +01:00
void os : : wait_for_keypress_at_exit ( void ) {
// don't do anything on posix platforms
return ;
}
2012-05-10 15:44:19 +02:00
2017-11-29 17:03:10 -08:00
int os : : create_file_for_heap ( const char * dir ) {
const char name_template [ ] = " /jvmheap.XXXXXX " ;
2019-02-21 16:56:06 -08:00
size_t fullname_len = strlen ( dir ) + strlen ( name_template ) ;
char * fullname = ( char * ) os : : malloc ( fullname_len + 1 , mtInternal ) ;
2017-11-29 17:03:10 -08:00
if ( fullname = = NULL ) {
vm_exit_during_initialization ( err_msg ( " Malloc failed during creation of backing file for heap (%s) " , os : : strerror ( errno ) ) ) ;
return - 1 ;
}
2019-02-21 16:56:06 -08:00
int n = snprintf ( fullname , fullname_len + 1 , " %s%s " , dir , name_template ) ;
assert ( ( size_t ) n = = fullname_len , " Unexpected number of characters in string " ) ;
2017-11-29 17:03:10 -08:00
os : : native_path ( fullname ) ;
// set the file creation mask.
mode_t file_mode = S_IRUSR | S_IWUSR ;
// create a new file.
int fd = mkstemp ( fullname ) ;
if ( fd < 0 ) {
warning ( " Could not create file for heap with template %s " , fullname ) ;
os : : free ( fullname ) ;
return - 1 ;
}
// delete the name from the filesystem. When 'fd' is closed, the file (and space) will be deleted.
2019-02-22 18:54:23 -08:00
int ret = unlink ( fullname ) ;
2017-11-29 17:03:10 -08:00
assert_with_errno ( ret = = 0 , " unlink returned error " ) ;
os : : free ( fullname ) ;
return fd ;
}
static char * reserve_mmapped_memory ( size_t bytes , char * requested_addr ) {
char * addr ;
2017-12-01 11:26:22 -05:00
int flags = MAP_PRIVATE NOT_AIX ( | MAP_NORESERVE ) | MAP_ANONYMOUS ;
2017-11-29 17:03:10 -08:00
if ( requested_addr ! = NULL ) {
assert ( ( uintptr_t ) requested_addr % os : : vm_page_size ( ) = = 0 , " Requested address should be aligned to OS page size " ) ;
flags | = MAP_FIXED ;
}
// Map reserved/uncommitted pages PROT_NONE so we fail early if we
// touch an uncommitted page. Otherwise, the read/write might
// succeed if we have enough swap space to back the physical page.
addr = ( char * ) : : mmap ( requested_addr , bytes , PROT_NONE ,
flags , - 1 , 0 ) ;
if ( addr ! = MAP_FAILED ) {
MemTracker : : record_virtual_memory_reserve ( ( address ) addr , bytes , CALLER_PC ) ;
return addr ;
}
return NULL ;
}
static int util_posix_fallocate ( int fd , off_t offset , off_t len ) {
# ifdef __APPLE__
fstore_t store = { F_ALLOCATECONTIG , F_PEOFPOSMODE , 0 , len } ;
// First we try to get a continuous chunk of disk space
int ret = fcntl ( fd , F_PREALLOCATE , & store ) ;
if ( ret = = - 1 ) {
// Maybe we are too fragmented, try to allocate non-continuous range
store . fst_flags = F_ALLOCATEALL ;
ret = fcntl ( fd , F_PREALLOCATE , & store ) ;
}
if ( ret ! = - 1 ) {
return ftruncate ( fd , len ) ;
}
return - 1 ;
# else
return posix_fallocate ( fd , offset , len ) ;
# endif
}
// Map the given address range to the provided file descriptor.
char * os : : map_memory_to_file ( char * base , size_t size , int fd ) {
assert ( fd ! = - 1 , " File descriptor is not valid " ) ;
// allocate space for the file
2017-12-07 10:21:13 -08:00
int ret = util_posix_fallocate ( fd , 0 , ( off_t ) size ) ;
if ( ret ! = 0 ) {
vm_exit_during_initialization ( err_msg ( " Error in mapping Java heap at the given filesystem directory. error(%d) " , ret ) ) ;
2017-11-29 17:03:10 -08:00
return NULL ;
}
int prot = PROT_READ | PROT_WRITE ;
int flags = MAP_SHARED ;
if ( base ! = NULL ) {
flags | = MAP_FIXED ;
}
char * addr = ( char * ) mmap ( base , size , prot , flags , fd , 0 ) ;
if ( addr = = MAP_FAILED ) {
2017-12-07 10:21:13 -08:00
warning ( " Failed mmap to file. (%s) " , os : : strerror ( errno ) ) ;
2017-11-29 17:03:10 -08:00
return NULL ;
}
if ( base ! = NULL & & addr ! = base ) {
if ( ! os : : release_memory ( addr , size ) ) {
warning ( " Could not release memory on unsuccessful file mapping " ) ;
2017-12-07 10:21:13 -08:00
}
2017-11-29 17:03:10 -08:00
return NULL ;
}
return addr ;
}
char * os : : replace_existing_mapping_with_file_mapping ( char * base , size_t size , int fd ) {
assert ( fd ! = - 1 , " File descriptor is not valid " ) ;
assert ( base ! = NULL , " Base cannot be NULL " ) ;
return map_memory_to_file ( base , size , fd ) ;
}
2012-12-17 08:49:20 +01:00
// Multiple threads can race in this code, and can remap over each other with MAP_FIXED,
// so on posix, unmap the section at the start and at the end of the chunk that we mapped
// rather than unmapping and remapping the whole chunk to get requested alignment.
2017-11-29 17:03:10 -08:00
char * os : : reserve_memory_aligned ( size_t size , size_t alignment , int file_desc ) {
2012-12-17 08:49:20 +01:00
assert ( ( alignment & ( os : : vm_allocation_granularity ( ) - 1 ) ) = = 0 ,
" Alignment must be a multiple of allocation granularity (page size) " ) ;
assert ( ( size & ( alignment - 1 ) ) = = 0 , " size must be 'alignment' aligned " ) ;
size_t extra_size = size + alignment ;
assert ( extra_size > = size , " overflow, size is too large to allow alignment " ) ;
2017-11-29 17:03:10 -08:00
char * extra_base ;
if ( file_desc ! = - 1 ) {
// For file mapping, we do not call os:reserve_memory(extra_size, NULL, alignment, file_desc) because
// we need to deal with shrinking of the file space later when we release extra memory after alignment.
// We also cannot called os:reserve_memory() with file_desc set to -1 because on aix we might get SHM memory.
// So here to call a helper function while reserve memory for us. After we have a aligned base,
// we will replace anonymous mapping with file mapping.
extra_base = reserve_mmapped_memory ( extra_size , NULL ) ;
if ( extra_base ! = NULL ) {
MemTracker : : record_virtual_memory_reserve ( ( address ) extra_base , extra_size , CALLER_PC ) ;
}
} else {
extra_base = os : : reserve_memory ( extra_size , NULL , alignment ) ;
}
2012-12-17 08:49:20 +01:00
if ( extra_base = = NULL ) {
return NULL ;
}
// Do manual alignment
2017-07-04 15:58:10 +02:00
char * aligned_base = align_up ( extra_base , alignment ) ;
2012-12-17 08:49:20 +01:00
// [ | | ]
// ^ extra_base
// ^ extra_base + begin_offset == aligned_base
// extra_base + begin_offset + size ^
// extra_base + extra_size ^
// |<>| == begin_offset
// end_offset == |<>|
size_t begin_offset = aligned_base - extra_base ;
size_t end_offset = ( extra_base + extra_size ) - ( aligned_base + size ) ;
if ( begin_offset > 0 ) {
os : : release_memory ( extra_base , begin_offset ) ;
}
if ( end_offset > 0 ) {
os : : release_memory ( extra_base + begin_offset + size , end_offset ) ;
}
2017-11-29 17:03:10 -08:00
if ( file_desc ! = - 1 ) {
// After we have an aligned address, we can replace anonymous mapping with file mapping
if ( replace_existing_mapping_with_file_mapping ( aligned_base , size , file_desc ) = = NULL ) {
vm_exit_during_initialization ( err_msg ( " Error in mapping Java heap at the given filesystem directory " ) ) ;
}
MemTracker : : record_virtual_memory_commit ( ( address ) aligned_base , size , CALLER_PC ) ;
}
2012-12-17 08:49:20 +01:00
return aligned_base ;
}
2018-02-27 18:17:57 -05:00
int os : : vsnprintf ( char * buf , size_t len , const char * fmt , va_list args ) {
// All supported POSIX platforms provide C99 semantics.
int result = : : vsnprintf ( buf , len , fmt , args ) ;
// If an encoding error occurred (result < 0) then it's not clear
// whether the buffer is NUL terminated, so ensure it is.
if ( ( result < 0 ) & & ( len > 0 ) ) {
buf [ len - 1 ] = ' \0 ' ;
}
return result ;
2015-11-04 17:18:59 -05:00
}
2016-04-22 14:57:18 +02:00
int os : : get_fileno ( FILE * fp ) {
return NOT_AIX ( : : ) fileno ( fp ) ;
2016-04-11 12:22:09 +02:00
}
2016-10-21 10:18:11 +02:00
struct tm * os : : gmtime_pd ( const time_t * clock , struct tm * res ) {
return gmtime_r ( clock , res ) ;
}
2012-05-10 15:44:19 +02:00
void os : : Posix : : print_load_average ( outputStream * st ) {
st - > print ( " load average: " ) ;
double loadavg [ 3 ] ;
2019-10-08 09:33:57 +02:00
int res = os : : loadavg ( loadavg , 3 ) ;
if ( res ! = - 1 ) {
st - > print ( " %0.02f %0.02f %0.02f " , loadavg [ 0 ] , loadavg [ 1 ] , loadavg [ 2 ] ) ;
} else {
st - > print ( " Unavailable " ) ;
}
2012-05-10 15:44:19 +02:00
st - > cr ( ) ;
}
void os : : Posix : : print_rlimit_info ( outputStream * st ) {
st - > print ( " rlimit: " ) ;
struct rlimit rlim ;
st - > print ( " STACK " ) ;
getrlimit ( RLIMIT_STACK , & rlim ) ;
if ( rlim . rlim_cur = = RLIM_INFINITY ) st - > print ( " infinity " ) ;
2017-05-30 15:41:23 -07:00
else st - > print ( UINT64_FORMAT " k " , uint64_t ( rlim . rlim_cur ) / 1024 ) ;
2012-05-10 15:44:19 +02:00
st - > print ( " , CORE " ) ;
getrlimit ( RLIMIT_CORE , & rlim ) ;
if ( rlim . rlim_cur = = RLIM_INFINITY ) st - > print ( " infinity " ) ;
2017-05-30 15:41:23 -07:00
else st - > print ( UINT64_FORMAT " k " , uint64_t ( rlim . rlim_cur ) / 1024 ) ;
2012-05-10 15:44:19 +02:00
2013-07-26 00:59:18 +02:00
// Isn't there on solaris
2017-05-30 15:41:23 -07:00
# if defined(AIX)
st - > print ( " , NPROC " ) ;
st - > print ( " %d " , sysconf ( _SC_CHILD_MAX ) ) ;
# elif !defined(SOLARIS)
2012-05-10 15:44:19 +02:00
st - > print ( " , NPROC " ) ;
getrlimit ( RLIMIT_NPROC , & rlim ) ;
if ( rlim . rlim_cur = = RLIM_INFINITY ) st - > print ( " infinity " ) ;
2017-05-11 08:40:32 -07:00
else st - > print ( UINT64_FORMAT , uint64_t ( rlim . rlim_cur ) ) ;
2012-05-10 15:44:19 +02:00
# endif
st - > print ( " , NOFILE " ) ;
getrlimit ( RLIMIT_NOFILE , & rlim ) ;
if ( rlim . rlim_cur = = RLIM_INFINITY ) st - > print ( " infinity " ) ;
2017-05-11 08:40:32 -07:00
else st - > print ( UINT64_FORMAT , uint64_t ( rlim . rlim_cur ) ) ;
2012-05-10 15:44:19 +02:00
st - > print ( " , AS " ) ;
getrlimit ( RLIMIT_AS , & rlim ) ;
if ( rlim . rlim_cur = = RLIM_INFINITY ) st - > print ( " infinity " ) ;
2017-05-30 15:41:23 -07:00
else st - > print ( UINT64_FORMAT " k " , uint64_t ( rlim . rlim_cur ) / 1024 ) ;
st - > print ( " , DATA " ) ;
getrlimit ( RLIMIT_DATA , & rlim ) ;
if ( rlim . rlim_cur = = RLIM_INFINITY ) st - > print ( " infinity " ) ;
else st - > print ( UINT64_FORMAT " k " , uint64_t ( rlim . rlim_cur ) / 1024 ) ;
st - > print ( " , FSIZE " ) ;
getrlimit ( RLIMIT_FSIZE , & rlim ) ;
if ( rlim . rlim_cur = = RLIM_INFINITY ) st - > print ( " infinity " ) ;
else st - > print ( UINT64_FORMAT " k " , uint64_t ( rlim . rlim_cur ) / 1024 ) ;
2012-05-10 15:44:19 +02:00
st - > cr ( ) ;
}
void os : : Posix : : print_uname_info ( outputStream * st ) {
// kernel
st - > print ( " uname: " ) ;
struct utsname name ;
uname ( & name ) ;
2014-05-09 16:50:54 -04:00
st - > print ( " %s " , name . sysname ) ;
2014-09-08 22:48:09 -07:00
# ifdef ASSERT
st - > print ( " %s " , name . nodename ) ;
# endif
2014-05-09 16:50:54 -04:00
st - > print ( " %s " , name . release ) ;
st - > print ( " %s " , name . version ) ;
st - > print ( " %s " , name . machine ) ;
2012-05-10 15:44:19 +02:00
st - > cr ( ) ;
}
2018-11-15 17:08:59 +01:00
void os : : Posix : : print_umask ( outputStream * st , mode_t umsk ) {
st - > print ( ( umsk & S_IRUSR ) ? " r " : " - " ) ;
st - > print ( ( umsk & S_IWUSR ) ? " w " : " - " ) ;
st - > print ( ( umsk & S_IXUSR ) ? " x " : " - " ) ;
st - > print ( ( umsk & S_IRGRP ) ? " r " : " - " ) ;
st - > print ( ( umsk & S_IWGRP ) ? " w " : " - " ) ;
st - > print ( ( umsk & S_IXGRP ) ? " x " : " - " ) ;
st - > print ( ( umsk & S_IROTH ) ? " r " : " - " ) ;
st - > print ( ( umsk & S_IWOTH ) ? " w " : " - " ) ;
st - > print ( ( umsk & S_IXOTH ) ? " x " : " - " ) ;
}
void os : : Posix : : print_user_info ( outputStream * st ) {
unsigned id = ( unsigned ) : : getuid ( ) ;
st - > print ( " uid : %u " , id ) ;
id = ( unsigned ) : : geteuid ( ) ;
st - > print ( " euid : %u " , id ) ;
id = ( unsigned ) : : getgid ( ) ;
st - > print ( " gid : %u " , id ) ;
id = ( unsigned ) : : getegid ( ) ;
st - > print_cr ( " egid : %u " , id ) ;
st - > cr ( ) ;
mode_t umsk = : : umask ( 0 ) ;
: : umask ( umsk ) ;
st - > print ( " umask: %04o ( " , ( unsigned ) umsk ) ;
print_umask ( st , umsk ) ;
st - > print_cr ( " ) " ) ;
st - > cr ( ) ;
}
2015-07-22 00:03:45 -04:00
bool os : : get_host_name ( char * buf , size_t buflen ) {
struct utsname name ;
uname ( & name ) ;
jio_snprintf ( buf , buflen , " %s " , name . nodename ) ;
return true ;
}
2013-03-27 19:21:18 +01:00
bool os : : has_allocatable_memory_limit ( julong * limit ) {
struct rlimit rlim ;
int getrlimit_res = getrlimit ( RLIMIT_AS , & rlim ) ;
// if there was an error when calling getrlimit, assume that there is no limitation
// on virtual memory.
bool result ;
if ( ( getrlimit_res ! = 0 ) | | ( rlim . rlim_cur = = RLIM_INFINITY ) ) {
result = false ;
} else {
* limit = ( julong ) rlim . rlim_cur ;
result = true ;
}
# ifdef _LP64
return result ;
# else
// arbitrary virtual space limit for 32 bit Unices found by testing. If
// getrlimit above returned a limit, bound it with this limit. Otherwise
// directly use it.
const julong max_virtual_limit = ( julong ) 3800 * M ;
if ( result ) {
* limit = MIN2 ( * limit , max_virtual_limit ) ;
} else {
* limit = max_virtual_limit ;
}
2012-05-10 15:44:19 +02:00
2013-03-27 19:21:18 +01:00
// bound by actually allocatable memory. The algorithm uses two bounds, an
// upper and a lower limit. The upper limit is the current highest amount of
// memory that could not be allocated, the lower limit is the current highest
// amount of memory that could be allocated.
// The algorithm iteratively refines the result by halving the difference
// between these limits, updating either the upper limit (if that value could
// not be allocated) or the lower limit (if the that value could be allocated)
// until the difference between these limits is "small".
// the minimum amount of memory we care about allocating.
const julong min_allocation_size = M ;
julong upper_limit = * limit ;
// first check a few trivial cases
if ( is_allocatable ( upper_limit ) | | ( upper_limit < = min_allocation_size ) ) {
* limit = upper_limit ;
} else if ( ! is_allocatable ( min_allocation_size ) ) {
// we found that not even min_allocation_size is allocatable. Return it
// anyway. There is no point to search for a better value any more.
* limit = min_allocation_size ;
} else {
// perform the binary search.
julong lower_limit = min_allocation_size ;
while ( ( upper_limit - lower_limit ) > min_allocation_size ) {
julong temp_limit = ( ( upper_limit - lower_limit ) / 2 ) + lower_limit ;
2017-04-24 09:14:09 +02:00
temp_limit = align_down ( temp_limit , min_allocation_size ) ;
2013-03-27 19:21:18 +01:00
if ( is_allocatable ( temp_limit ) ) {
lower_limit = temp_limit ;
} else {
upper_limit = temp_limit ;
}
}
* limit = lower_limit ;
}
return true ;
# endif
}
2013-04-25 11:02:32 -07:00
const char * os : : get_current_directory ( char * buf , size_t buflen ) {
return getcwd ( buf , buflen ) ;
}
FILE * os : : open ( int fd , const char * mode ) {
return : : fdopen ( fd , mode ) ;
}
2013-07-17 13:48:15 +02:00
2019-01-13 16:54:01 -05:00
ssize_t os : : read_at ( int fd , void * buf , unsigned int nBytes , jlong offset ) {
return : : pread ( fd , buf , nBytes , offset ) ;
}
2016-05-09 15:46:12 +02:00
void os : : flockfile ( FILE * fp ) {
: : flockfile ( fp ) ;
}
void os : : funlockfile ( FILE * fp ) {
: : funlockfile ( fp ) ;
}
2018-07-17 15:59:47 -04:00
DIR * os : : opendir ( const char * dirname ) {
assert ( dirname ! = NULL , " just checking " ) ;
return : : opendir ( dirname ) ;
}
struct dirent * os : : readdir ( DIR * dirp ) {
assert ( dirp ! = NULL , " just checking " ) ;
return : : readdir ( dirp ) ;
}
int os : : closedir ( DIR * dirp ) {
assert ( dirp ! = NULL , " just checking " ) ;
return : : closedir ( dirp ) ;
}
2013-08-23 20:33:02 -04:00
// Builds a platform dependent Agent_OnLoad_<lib_name> function name
// which is used to find statically linked in agents.
// Parameters:
// sym_name: Symbol in library we are looking for
// lib_name: Name of library to look in, NULL for shared libs.
// is_absolute_path == true if lib_name is absolute path to agent
// such as "/a/b/libL.so"
// == false if only the base name of the library is passed in
// such as "L"
char * os : : build_agent_function_name ( const char * sym_name , const char * lib_name ,
bool is_absolute_path ) {
char * agent_entry_name ;
size_t len ;
size_t name_len ;
size_t prefix_len = strlen ( JNI_LIB_PREFIX ) ;
size_t suffix_len = strlen ( JNI_LIB_SUFFIX ) ;
const char * start ;
if ( lib_name ! = NULL ) {
2016-03-07 20:58:09 +03:00
name_len = strlen ( lib_name ) ;
2013-08-23 20:33:02 -04:00
if ( is_absolute_path ) {
// Need to strip path, prefix and suffix
if ( ( start = strrchr ( lib_name , * os : : file_separator ( ) ) ) ! = NULL ) {
lib_name = + + start ;
}
2016-03-07 20:58:09 +03:00
if ( strlen ( lib_name ) < = ( prefix_len + suffix_len ) ) {
2013-08-23 20:33:02 -04:00
return NULL ;
}
lib_name + = prefix_len ;
name_len = strlen ( lib_name ) - suffix_len ;
}
}
len = ( lib_name ! = NULL ? name_len : 0 ) + strlen ( sym_name ) + 2 ;
agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL ( char , len , mtThread ) ;
if ( agent_entry_name = = NULL ) {
return NULL ;
}
strcpy ( agent_entry_name , sym_name ) ;
if ( lib_name ! = NULL ) {
strcat ( agent_entry_name , " _ " ) ;
strncat ( agent_entry_name , lib_name , name_len ) ;
}
return agent_entry_name ;
}
2014-02-19 16:22:15 +00:00
2018-12-20 10:05:19 +01:00
void os : : naked_short_nanosleep ( jlong ns ) {
struct timespec req ;
assert ( ns > - 1 & & ns < NANOUNITS , " Un-interruptable sleep, short time use only " ) ;
req . tv_sec = 0 ;
req . tv_nsec = ns ;
: : nanosleep ( & req , NULL ) ;
return ;
}
void os : : naked_short_sleep ( jlong ms ) {
assert ( ms < MILLIUNITS , " Un-interruptable sleep, short time use only " ) ;
os : : naked_short_nanosleep ( ms * ( NANOUNITS / MILLIUNITS ) ) ;
return ;
}
2015-12-01 21:30:34 -05:00
static const struct {
int sig ; const char * name ;
}
g_signal_info [ ] =
2013-07-26 00:59:18 +02:00
{
2015-12-01 21:30:34 -05:00
{ SIGABRT , " SIGABRT " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGAIO
2015-12-01 21:30:34 -05:00
{ SIGAIO , " SIGAIO " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGALRM , " SIGALRM " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGALRM1
2015-12-01 21:30:34 -05:00
{ SIGALRM1 , " SIGALRM1 " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGBUS , " SIGBUS " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGCANCEL
2015-12-01 21:30:34 -05:00
{ SIGCANCEL , " SIGCANCEL " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGCHLD , " SIGCHLD " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGCLD
2015-12-01 21:30:34 -05:00
{ SIGCLD , " SIGCLD " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGCONT , " SIGCONT " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGCPUFAIL
2015-12-01 21:30:34 -05:00
{ SIGCPUFAIL , " SIGCPUFAIL " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGDANGER
2015-12-01 21:30:34 -05:00
{ SIGDANGER , " SIGDANGER " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGDIL
2015-12-01 21:30:34 -05:00
{ SIGDIL , " SIGDIL " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGEMT
2015-12-01 21:30:34 -05:00
{ SIGEMT , " SIGEMT " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGFPE , " SIGFPE " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGFREEZE
2015-12-01 21:30:34 -05:00
{ SIGFREEZE , " SIGFREEZE " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGGFAULT
2015-12-01 21:30:34 -05:00
{ SIGGFAULT , " SIGGFAULT " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGGRANT
2015-12-01 21:30:34 -05:00
{ SIGGRANT , " SIGGRANT " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGHUP , " SIGHUP " } ,
{ SIGILL , " SIGILL " } ,
2019-10-22 22:00:21 -04:00
# ifdef SIGINFO
{ SIGINFO , " SIGINFO " } ,
# endif
2015-12-01 21:30:34 -05:00
{ SIGINT , " SIGINT " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGIO
2015-12-01 21:30:34 -05:00
{ SIGIO , " SIGIO " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGIOINT
2015-12-01 21:30:34 -05:00
{ SIGIOINT , " SIGIOINT " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGIOT
2015-12-01 21:30:34 -05:00
// SIGIOT is there for BSD compatibility, but on most Unices just a
// synonym for SIGABRT. The result should be "SIGABRT", not
// "SIGIOT".
# if (SIGIOT != SIGABRT )
{ SIGIOT , " SIGIOT " } ,
# endif
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGKAP
2015-12-01 21:30:34 -05:00
{ SIGKAP , " SIGKAP " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGKILL , " SIGKILL " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGLOST
2015-12-01 21:30:34 -05:00
{ SIGLOST , " SIGLOST " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGLWP
2015-12-01 21:30:34 -05:00
{ SIGLWP , " SIGLWP " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGLWPTIMER
2015-12-01 21:30:34 -05:00
{ SIGLWPTIMER , " SIGLWPTIMER " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGMIGRATE
2015-12-01 21:30:34 -05:00
{ SIGMIGRATE , " SIGMIGRATE " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGMSG
2015-12-01 21:30:34 -05:00
{ SIGMSG , " SIGMSG " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGPIPE , " SIGPIPE " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGPOLL
2015-12-01 21:30:34 -05:00
{ SIGPOLL , " SIGPOLL " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGPRE
2015-12-01 21:30:34 -05:00
{ SIGPRE , " SIGPRE " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGPROF , " SIGPROF " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGPTY
2015-12-01 21:30:34 -05:00
{ SIGPTY , " SIGPTY " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGPWR
2015-12-01 21:30:34 -05:00
{ SIGPWR , " SIGPWR " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGQUIT , " SIGQUIT " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGRECONFIG
2015-12-01 21:30:34 -05:00
{ SIGRECONFIG , " SIGRECONFIG " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGRECOVERY
2015-12-01 21:30:34 -05:00
{ SIGRECOVERY , " SIGRECOVERY " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGRESERVE
2015-12-01 21:30:34 -05:00
{ SIGRESERVE , " SIGRESERVE " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGRETRACT
2015-12-01 21:30:34 -05:00
{ SIGRETRACT , " SIGRETRACT " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGSAK
2015-12-01 21:30:34 -05:00
{ SIGSAK , " SIGSAK " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGSEGV , " SIGSEGV " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGSOUND
2015-12-01 21:30:34 -05:00
{ SIGSOUND , " SIGSOUND " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
# ifdef SIGSTKFLT
{ SIGSTKFLT , " SIGSTKFLT " } ,
# endif
{ SIGSTOP , " SIGSTOP " } ,
{ SIGSYS , " SIGSYS " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGSYSERROR
2015-12-01 21:30:34 -05:00
{ SIGSYSERROR , " SIGSYSERROR " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGTALRM
2015-12-01 21:30:34 -05:00
{ SIGTALRM , " SIGTALRM " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGTERM , " SIGTERM " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGTHAW
2015-12-01 21:30:34 -05:00
{ SIGTHAW , " SIGTHAW " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGTRAP , " SIGTRAP " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGTSTP
2015-12-01 21:30:34 -05:00
{ SIGTSTP , " SIGTSTP " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGTTIN , " SIGTTIN " } ,
{ SIGTTOU , " SIGTTOU " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGURG
2015-12-01 21:30:34 -05:00
{ SIGURG , " SIGURG " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGUSR1 , " SIGUSR1 " } ,
{ SIGUSR2 , " SIGUSR2 " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGVIRT
2015-12-01 21:30:34 -05:00
{ SIGVIRT , " SIGVIRT " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGVTALRM , " SIGVTALRM " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGWAITING
2015-12-01 21:30:34 -05:00
{ SIGWAITING , " SIGWAITING " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGWINCH
2015-12-01 21:30:34 -05:00
{ SIGWINCH , " SIGWINCH " } ,
2013-07-26 00:59:18 +02:00
# endif
# ifdef SIGWINDOW
2015-12-01 21:30:34 -05:00
{ SIGWINDOW , " SIGWINDOW " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ SIGXCPU , " SIGXCPU " } ,
{ SIGXFSZ , " SIGXFSZ " } ,
2013-07-26 00:59:18 +02:00
# ifdef SIGXRES
2015-12-01 21:30:34 -05:00
{ SIGXRES , " SIGXRES " } ,
2013-07-26 00:59:18 +02:00
# endif
2015-12-01 21:30:34 -05:00
{ - 1 , NULL }
} ;
// Returned string is a constant. For unknown signals "UNKNOWN" is returned.
const char * os : : Posix : : get_signal_name ( int sig , char * out , size_t outlen ) {
2013-07-26 00:59:18 +02:00
const char * ret = NULL ;
# ifdef SIGRTMIN
if ( sig > = SIGRTMIN & & sig < = SIGRTMAX ) {
if ( sig = = SIGRTMIN ) {
ret = " SIGRTMIN " ;
} else if ( sig = = SIGRTMAX ) {
ret = " SIGRTMAX " ;
} else {
jio_snprintf ( out , outlen , " SIGRTMIN+%d " , sig - SIGRTMIN ) ;
return out ;
}
}
# endif
if ( sig > 0 ) {
2015-12-01 21:30:34 -05:00
for ( int idx = 0 ; g_signal_info [ idx ] . sig ! = - 1 ; idx + + ) {
if ( g_signal_info [ idx ] . sig = = sig ) {
ret = g_signal_info [ idx ] . name ;
2013-07-26 00:59:18 +02:00
break ;
}
}
}
if ( ! ret ) {
if ( ! is_valid_signal ( sig ) ) {
ret = " INVALID " ;
} else {
ret = " UNKNOWN " ;
}
}
2014-10-29 10:13:24 +01:00
if ( out & & outlen > 0 ) {
strncpy ( out , ret , outlen ) ;
out [ outlen - 1 ] = ' \0 ' ;
}
2013-07-26 00:59:18 +02:00
return out ;
}
2015-12-01 21:30:34 -05:00
int os : : Posix : : get_signal_number ( const char * signal_name ) {
char tmp [ 30 ] ;
const char * s = signal_name ;
if ( s [ 0 ] ! = ' S ' | | s [ 1 ] ! = ' I ' | | s [ 2 ] ! = ' G ' ) {
jio_snprintf ( tmp , sizeof ( tmp ) , " SIG%s " , signal_name ) ;
s = tmp ;
}
for ( int idx = 0 ; g_signal_info [ idx ] . sig ! = - 1 ; idx + + ) {
if ( strcmp ( g_signal_info [ idx ] . name , s ) = = 0 ) {
return g_signal_info [ idx ] . sig ;
}
}
return - 1 ;
}
int os : : get_signal_number ( const char * signal_name ) {
return os : : Posix : : get_signal_number ( signal_name ) ;
}
2013-07-26 00:59:18 +02:00
// Returns true if signal number is valid.
bool os : : Posix : : is_valid_signal ( int sig ) {
// MacOS not really POSIX compliant: sigaddset does not return
// an error for invalid signal numbers. However, MacOS does not
// support real time signals and simply seems to have just 33
// signals with no holes in the signal range.
# ifdef __APPLE__
return sig > = 1 & & sig < NSIG ;
# else
// Use sigaddset to check for signal validity.
sigset_t set ;
2017-06-13 08:09:17 +02:00
sigemptyset ( & set ) ;
2013-07-26 00:59:18 +02:00
if ( sigaddset ( & set , sig ) = = - 1 & & errno = = EINVAL ) {
return false ;
}
return true ;
# endif
}
2018-05-18 08:47:42 -04:00
bool os : : Posix : : is_sig_ignored ( int sig ) {
struct sigaction oact ;
sigaction ( sig , ( struct sigaction * ) NULL , & oact ) ;
void * ohlr = oact . sa_sigaction ? CAST_FROM_FN_PTR ( void * , oact . sa_sigaction )
: CAST_FROM_FN_PTR ( void * , oact . sa_handler ) ;
if ( ohlr = = CAST_FROM_FN_PTR ( void * , SIG_IGN ) ) {
return true ;
} else {
return false ;
}
}
2015-12-01 21:30:34 -05:00
// Returns:
2015-12-10 08:50:36 +01:00
// NULL for an invalid signal number
2015-12-01 21:30:34 -05:00
// "SIG<num>" for a valid but unknown signal number
// signal name otherwise.
const char * os : : exception_name ( int sig , char * buf , size_t size ) {
if ( ! os : : Posix : : is_valid_signal ( sig ) ) {
2015-12-10 08:50:36 +01:00
return NULL ;
2015-12-01 21:30:34 -05:00
}
const char * const name = os : : Posix : : get_signal_name ( sig , buf , size ) ;
if ( strcmp ( name , " UNKNOWN " ) = = 0 ) {
jio_snprintf ( buf , size , " SIG%d " , sig ) ;
}
return buf ;
}
2013-07-26 00:59:18 +02:00
# define NUM_IMPORTANT_SIGS 32
// Returns one-line short description of a signal set in a user provided buffer.
const char * os : : Posix : : describe_signal_set_short ( const sigset_t * set , char * buffer , size_t buf_size ) {
2013-08-22 09:39:54 -07:00
assert ( buf_size = = ( NUM_IMPORTANT_SIGS + 1 ) , " wrong buffer size " ) ;
2013-07-26 00:59:18 +02:00
// Note: for shortness, just print out the first 32. That should
// cover most of the useful ones, apart from realtime signals.
for ( int sig = 1 ; sig < = NUM_IMPORTANT_SIGS ; sig + + ) {
const int rc = sigismember ( set , sig ) ;
if ( rc = = - 1 & & errno = = EINVAL ) {
buffer [ sig - 1 ] = ' ? ' ;
} else {
buffer [ sig - 1 ] = rc = = 0 ? ' 0 ' : ' 1 ' ;
}
}
buffer [ NUM_IMPORTANT_SIGS ] = 0 ;
return buffer ;
}
// Prints one-line description of a signal set.
void os : : Posix : : print_signal_set_short ( outputStream * st , const sigset_t * set ) {
char buf [ NUM_IMPORTANT_SIGS + 1 ] ;
os : : Posix : : describe_signal_set_short ( set , buf , sizeof ( buf ) ) ;
2014-05-09 16:50:54 -04:00
st - > print ( " %s " , buf ) ;
2013-07-26 00:59:18 +02:00
}
// Writes one-line description of a combination of sigaction.sa_flags into a user
// provided buffer. Returns that buffer.
const char * os : : Posix : : describe_sa_flags ( int flags , char * buffer , size_t size ) {
char * p = buffer ;
size_t remaining = size ;
bool first = true ;
int idx = 0 ;
assert ( buffer , " invalid argument " ) ;
if ( size = = 0 ) {
return buffer ;
}
strncpy ( buffer , " none " , size ) ;
const struct {
2015-12-21 16:58:29 +00:00
// NB: i is an unsigned int here because SA_RESETHAND is on some
// systems 0x80000000, which is implicitly unsigned. Assignining
// it to an int field would be an overflow in unsigned-to-signed
// conversion.
unsigned int i ;
2013-07-26 00:59:18 +02:00
const char * s ;
} flaginfo [ ] = {
{ SA_NOCLDSTOP , " SA_NOCLDSTOP " } ,
{ SA_ONSTACK , " SA_ONSTACK " } ,
{ SA_RESETHAND , " SA_RESETHAND " } ,
{ SA_RESTART , " SA_RESTART " } ,
{ SA_SIGINFO , " SA_SIGINFO " } ,
{ SA_NOCLDWAIT , " SA_NOCLDWAIT " } ,
{ SA_NODEFER , " SA_NODEFER " } ,
# ifdef AIX
{ SA_ONSTACK , " SA_ONSTACK " } ,
{ SA_OLDSTYLE , " SA_OLDSTYLE " } ,
# endif
{ 0 , NULL }
} ;
for ( idx = 0 ; flaginfo [ idx ] . s & & remaining > 1 ; idx + + ) {
if ( flags & flaginfo [ idx ] . i ) {
if ( first ) {
jio_snprintf ( p , remaining , " %s " , flaginfo [ idx ] . s ) ;
first = false ;
} else {
jio_snprintf ( p , remaining , " |%s " , flaginfo [ idx ] . s ) ;
}
const size_t len = strlen ( p ) ;
p + = len ;
remaining - = len ;
}
}
buffer [ size - 1 ] = ' \0 ' ;
return buffer ;
}
// Prints one-line description of a combination of sigaction.sa_flags.
void os : : Posix : : print_sa_flags ( outputStream * st , int flags ) {
char buffer [ 0x100 ] ;
os : : Posix : : describe_sa_flags ( flags , buffer , sizeof ( buffer ) ) ;
2014-05-09 16:50:54 -04:00
st - > print ( " %s " , buffer ) ;
2013-07-26 00:59:18 +02:00
}
// Helper function for os::Posix::print_siginfo_...():
// return a textual description for signal code.
struct enum_sigcode_desc_t {
const char * s_name ;
const char * s_desc ;
} ;
static bool get_signal_code_description ( const siginfo_t * si , enum_sigcode_desc_t * out ) {
const struct {
int sig ; int code ; const char * s_code ; const char * s_desc ;
} t1 [ ] = {
{ SIGILL , ILL_ILLOPC , " ILL_ILLOPC " , " Illegal opcode. " } ,
{ SIGILL , ILL_ILLOPN , " ILL_ILLOPN " , " Illegal operand. " } ,
{ SIGILL , ILL_ILLADR , " ILL_ILLADR " , " Illegal addressing mode. " } ,
{ SIGILL , ILL_ILLTRP , " ILL_ILLTRP " , " Illegal trap. " } ,
{ SIGILL , ILL_PRVOPC , " ILL_PRVOPC " , " Privileged opcode. " } ,
{ SIGILL , ILL_PRVREG , " ILL_PRVREG " , " Privileged register. " } ,
{ SIGILL , ILL_COPROC , " ILL_COPROC " , " Coprocessor error. " } ,
{ SIGILL , ILL_BADSTK , " ILL_BADSTK " , " Internal stack error. " } ,
# if defined(IA64) && defined(LINUX)
{ SIGILL , ILL_BADIADDR , " ILL_BADIADDR " , " Unimplemented instruction address " } ,
{ SIGILL , ILL_BREAK , " ILL_BREAK " , " Application Break instruction " } ,
# endif
{ SIGFPE , FPE_INTDIV , " FPE_INTDIV " , " Integer divide by zero. " } ,
{ SIGFPE , FPE_INTOVF , " FPE_INTOVF " , " Integer overflow. " } ,
{ SIGFPE , FPE_FLTDIV , " FPE_FLTDIV " , " Floating-point divide by zero. " } ,
{ SIGFPE , FPE_FLTOVF , " FPE_FLTOVF " , " Floating-point overflow. " } ,
{ SIGFPE , FPE_FLTUND , " FPE_FLTUND " , " Floating-point underflow. " } ,
{ SIGFPE , FPE_FLTRES , " FPE_FLTRES " , " Floating-point inexact result. " } ,
{ SIGFPE , FPE_FLTINV , " FPE_FLTINV " , " Invalid floating-point operation. " } ,
{ SIGFPE , FPE_FLTSUB , " FPE_FLTSUB " , " Subscript out of range. " } ,
{ SIGSEGV , SEGV_MAPERR , " SEGV_MAPERR " , " Address not mapped to object. " } ,
{ SIGSEGV , SEGV_ACCERR , " SEGV_ACCERR " , " Invalid permissions for mapped object. " } ,
# ifdef AIX
// no explanation found what keyerr would be
{ SIGSEGV , SEGV_KEYERR , " SEGV_KEYERR " , " key error " } ,
# endif
# if defined(IA64) && !defined(AIX)
{ SIGSEGV , SEGV_PSTKOVF , " SEGV_PSTKOVF " , " Paragraph stack overflow " } ,
# endif
2015-11-18 09:32:52 -08:00
# if defined(__sparc) && defined(SOLARIS)
// define Solaris Sparc M7 ADI SEGV signals
# if !defined(SEGV_ACCADI)
# define SEGV_ACCADI 3
# endif
{ SIGSEGV , SEGV_ACCADI , " SEGV_ACCADI " , " ADI not enabled for mapped object. " } ,
# if !defined(SEGV_ACCDERR)
# define SEGV_ACCDERR 4
# endif
{ SIGSEGV , SEGV_ACCDERR , " SEGV_ACCDERR " , " ADI disrupting exception. " } ,
# if !defined(SEGV_ACCPERR)
# define SEGV_ACCPERR 5
# endif
{ SIGSEGV , SEGV_ACCPERR , " SEGV_ACCPERR " , " ADI precise exception. " } ,
# endif // defined(__sparc) && defined(SOLARIS)
2013-07-26 00:59:18 +02:00
{ SIGBUS , BUS_ADRALN , " BUS_ADRALN " , " Invalid address alignment. " } ,
{ SIGBUS , BUS_ADRERR , " BUS_ADRERR " , " Nonexistent physical address. " } ,
{ SIGBUS , BUS_OBJERR , " BUS_OBJERR " , " Object-specific hardware error. " } ,
{ SIGTRAP , TRAP_BRKPT , " TRAP_BRKPT " , " Process breakpoint. " } ,
{ SIGTRAP , TRAP_TRACE , " TRAP_TRACE " , " Process trace trap. " } ,
{ SIGCHLD , CLD_EXITED , " CLD_EXITED " , " Child has exited. " } ,
{ SIGCHLD , CLD_KILLED , " CLD_KILLED " , " Child has terminated abnormally and did not create a core file. " } ,
{ SIGCHLD , CLD_DUMPED , " CLD_DUMPED " , " Child has terminated abnormally and created a core file. " } ,
{ SIGCHLD , CLD_TRAPPED , " CLD_TRAPPED " , " Traced child has trapped. " } ,
{ SIGCHLD , CLD_STOPPED , " CLD_STOPPED " , " Child has stopped. " } ,
{ SIGCHLD , CLD_CONTINUED , " CLD_CONTINUED " , " Stopped child has continued. " } ,
# ifdef SIGPOLL
{ SIGPOLL , POLL_OUT , " POLL_OUT " , " Output buffers available. " } ,
{ SIGPOLL , POLL_MSG , " POLL_MSG " , " Input message available. " } ,
{ SIGPOLL , POLL_ERR , " POLL_ERR " , " I/O error. " } ,
{ SIGPOLL , POLL_PRI , " POLL_PRI " , " High priority input available. " } ,
{ SIGPOLL , POLL_HUP , " POLL_HUP " , " Device disconnected. [Option End] " } ,
# endif
{ - 1 , - 1 , NULL , NULL }
} ;
// Codes valid in any signal context.
const struct {
int code ; const char * s_code ; const char * s_desc ;
} t2 [ ] = {
{ SI_USER , " SI_USER " , " Signal sent by kill(). " } ,
{ SI_QUEUE , " SI_QUEUE " , " Signal sent by the sigqueue(). " } ,
{ SI_TIMER , " SI_TIMER " , " Signal generated by expiration of a timer set by timer_settime(). " } ,
{ SI_ASYNCIO , " SI_ASYNCIO " , " Signal generated by completion of an asynchronous I/O request. " } ,
{ SI_MESGQ , " SI_MESGQ " , " Signal generated by arrival of a message on an empty message queue. " } ,
// Linux specific
# ifdef SI_TKILL
{ SI_TKILL , " SI_TKILL " , " Signal sent by tkill (pthread_kill) " } ,
# endif
# ifdef SI_DETHREAD
{ SI_DETHREAD , " SI_DETHREAD " , " Signal sent by execve() killing subsidiary threads " } ,
# endif
# ifdef SI_KERNEL
{ SI_KERNEL , " SI_KERNEL " , " Signal sent by kernel. " } ,
# endif
# ifdef SI_SIGIO
{ SI_SIGIO , " SI_SIGIO " , " Signal sent by queued SIGIO " } ,
# endif
# ifdef AIX
{ SI_UNDEFINED , " SI_UNDEFINED " , " siginfo contains partial information " } ,
{ SI_EMPTY , " SI_EMPTY " , " siginfo contains no useful information " } ,
# endif
# ifdef __sun
{ SI_NOINFO , " SI_NOINFO " , " No signal information " } ,
{ SI_RCTL , " SI_RCTL " , " kernel generated signal via rctl action " } ,
{ SI_LWP , " SI_LWP " , " Signal sent via lwp_kill " } ,
# endif
{ - 1 , NULL , NULL }
} ;
const char * s_code = NULL ;
const char * s_desc = NULL ;
for ( int i = 0 ; t1 [ i ] . sig ! = - 1 ; i + + ) {
if ( t1 [ i ] . sig = = si - > si_signo & & t1 [ i ] . code = = si - > si_code ) {
s_code = t1 [ i ] . s_code ;
s_desc = t1 [ i ] . s_desc ;
break ;
}
}
if ( s_code = = NULL ) {
for ( int i = 0 ; t2 [ i ] . s_code ! = NULL ; i + + ) {
if ( t2 [ i ] . code = = si - > si_code ) {
s_code = t2 [ i ] . s_code ;
s_desc = t2 [ i ] . s_desc ;
}
}
}
if ( s_code = = NULL ) {
out - > s_name = " unknown " ;
out - > s_desc = " unknown " ;
return false ;
}
out - > s_name = s_code ;
out - > s_desc = s_desc ;
return true ;
}
2019-03-08 11:23:30 +01:00
bool os : : signal_sent_by_kill ( const void * siginfo ) {
const siginfo_t * const si = ( const siginfo_t * ) siginfo ;
return si - > si_code = = SI_USER | | si - > si_code = = SI_QUEUE
# ifdef SI_TKILL
| | si - > si_code = = SI_TKILL
# endif
;
}
2015-12-09 14:56:02 +01:00
void os : : print_siginfo ( outputStream * os , const void * si0 ) {
const siginfo_t * const si = ( const siginfo_t * ) si0 ;
2013-07-26 00:59:18 +02:00
char buf [ 20 ] ;
2015-12-09 14:56:02 +01:00
os - > print ( " siginfo: " ) ;
2013-07-26 00:59:18 +02:00
if ( ! si ) {
2015-12-09 14:56:02 +01:00
os - > print ( " <null> " ) ;
2013-07-26 00:59:18 +02:00
return ;
}
const int sig = si - > si_signo ;
2015-12-09 14:56:02 +01:00
os - > print ( " si_signo: %d (%s) " , sig , os : : Posix : : get_signal_name ( sig , buf , sizeof ( buf ) ) ) ;
2013-07-26 00:59:18 +02:00
enum_sigcode_desc_t ed ;
2015-12-09 14:56:02 +01:00
get_signal_code_description ( si , & ed ) ;
os - > print ( " , si_code: %d (%s) " , si - > si_code , ed . s_name ) ;
2013-07-26 00:59:18 +02:00
if ( si - > si_errno ) {
os - > print ( " , si_errno: %d " , si - > si_errno ) ;
}
2015-12-09 14:56:02 +01:00
// Output additional information depending on the signal code.
2013-07-26 00:59:18 +02:00
2015-12-09 14:56:02 +01:00
// Note: Many implementations lump si_addr, si_pid, si_uid etc. together as unions,
// so it depends on the context which member to use. For synchronous error signals,
// we print si_addr, unless the signal was sent by another process or thread, in
// which case we print out pid or tid of the sender.
2019-03-08 11:23:30 +01:00
if ( signal_sent_by_kill ( si ) ) {
2015-12-09 14:56:02 +01:00
const pid_t pid = si - > si_pid ;
os - > print ( " , si_pid: %ld " , ( long ) pid ) ;
if ( IS_VALID_PID ( pid ) ) {
const pid_t me = getpid ( ) ;
if ( me = = pid ) {
os - > print ( " (current process) " ) ;
}
} else {
os - > print ( " (invalid) " ) ;
}
os - > print ( " , si_uid: %ld " , ( long ) si - > si_uid ) ;
if ( sig = = SIGCHLD ) {
os - > print ( " , si_status: %d " , si - > si_status ) ;
2013-07-26 00:59:18 +02:00
}
} else if ( sig = = SIGSEGV | | sig = = SIGBUS | | sig = = SIGILL | |
sig = = SIGTRAP | | sig = = SIGFPE ) {
2015-10-09 09:42:33 +02:00
os - > print ( " , si_addr: " PTR_FORMAT , p2i ( si - > si_addr ) ) ;
2013-07-26 00:59:18 +02:00
# ifdef SIGPOLL
} else if ( sig = = SIGPOLL ) {
2015-12-09 14:56:02 +01:00
os - > print ( " , si_band: %ld " , si - > si_band ) ;
2013-07-26 00:59:18 +02:00
# endif
}
2015-12-09 14:56:02 +01:00
2013-07-26 00:59:18 +02:00
}
2019-03-08 11:23:30 +01:00
bool os : : signal_thread ( Thread * thread , int sig , const char * reason ) {
OSThread * osthread = thread - > osthread ( ) ;
if ( osthread ) {
# if defined (SOLARIS)
// Note: we cannot use pthread_kill on Solaris - not because
// its missing, but because we do not have the pthread_t id.
int status = thr_kill ( osthread - > thread_id ( ) , sig ) ;
# else
int status = pthread_kill ( osthread - > pthread_id ( ) , sig ) ;
# endif
if ( status = = 0 ) {
Events : : log ( Thread : : current ( ) , " sent signal %d to Thread " INTPTR_FORMAT " because %s. " ,
sig , p2i ( thread ) , reason ) ;
return true ;
}
}
return false ;
}
2015-11-25 16:33:28 +01:00
int os : : Posix : : unblock_thread_signal_mask ( const sigset_t * set ) {
return pthread_sigmask ( SIG_UNBLOCK , set , NULL ) ;
}
2015-12-14 02:29:11 -05:00
address os : : Posix : : ucontext_get_pc ( const ucontext_t * ctx ) {
2016-07-13 12:23:05 +02:00
# if defined(AIX)
2015-11-25 16:33:28 +01:00
return Aix : : ucontext_get_pc ( ctx ) ;
2016-07-13 12:23:05 +02:00
# elif defined(BSD)
2015-11-25 16:33:28 +01:00
return Bsd : : ucontext_get_pc ( ctx ) ;
2016-07-13 12:23:05 +02:00
# elif defined(LINUX)
return Linux : : ucontext_get_pc ( ctx ) ;
# elif defined(SOLARIS)
return Solaris : : ucontext_get_pc ( ctx ) ;
2015-11-25 16:33:28 +01:00
# else
VMError : : report_and_die ( " unimplemented ucontext_get_pc " ) ;
# endif
}
void os : : Posix : : ucontext_set_pc ( ucontext_t * ctx , address pc ) {
2016-07-13 12:23:05 +02:00
# if defined(AIX)
2015-11-25 16:33:28 +01:00
Aix : : ucontext_set_pc ( ctx , pc ) ;
2016-07-13 12:23:05 +02:00
# elif defined(BSD)
2015-11-25 16:33:28 +01:00
Bsd : : ucontext_set_pc ( ctx , pc ) ;
2016-07-13 12:23:05 +02:00
# elif defined(LINUX)
Linux : : ucontext_set_pc ( ctx , pc ) ;
# elif defined(SOLARIS)
Solaris : : ucontext_set_pc ( ctx , pc ) ;
2015-11-25 16:33:28 +01:00
# else
VMError : : report_and_die ( " unimplemented ucontext_get_pc " ) ;
# endif
}
2016-02-24 18:06:34 +01:00
char * os : : Posix : : describe_pthread_attr ( char * buf , size_t buflen , const pthread_attr_t * attr ) {
size_t stack_size = 0 ;
size_t guard_size = 0 ;
int detachstate = 0 ;
pthread_attr_getstacksize ( attr , & stack_size ) ;
pthread_attr_getguardsize ( attr , & guard_size ) ;
2016-11-08 16:30:36 +01:00
// Work around linux NPTL implementation error, see also os::create_thread() in os_linux.cpp.
LINUX_ONLY ( stack_size - = guard_size ) ;
2016-02-24 18:06:34 +01:00
pthread_attr_getdetachstate ( attr , & detachstate ) ;
jio_snprintf ( buf , buflen , " stacksize: " SIZE_FORMAT " k, guardsize: " SIZE_FORMAT " k, %s " ,
stack_size / 1024 , guard_size / 1024 ,
( detachstate = = PTHREAD_CREATE_DETACHED ? " detached " : " joinable " ) ) ;
return buf ;
}
2017-03-13 20:23:11 +01:00
char * os : : Posix : : realpath ( const char * filename , char * outbuf , size_t outbuflen ) {
if ( filename = = NULL | | outbuf = = NULL | | outbuflen < 1 ) {
assert ( false , " os::Posix::realpath: invalid arguments. " ) ;
errno = EINVAL ;
return NULL ;
}
char * result = NULL ;
// This assumes platform realpath() is implemented according to POSIX.1-2008.
// POSIX.1-2008 allows to specify NULL for the output buffer, in which case
// output buffer is dynamically allocated and must be ::free()'d by the caller.
char * p = : : realpath ( filename , NULL ) ;
if ( p ! = NULL ) {
if ( strlen ( p ) < outbuflen ) {
strcpy ( outbuf , p ) ;
result = outbuf ;
} else {
errno = ENAMETOOLONG ;
}
: : free ( p ) ; // *not* os::free
} else {
// Fallback for platforms struggling with modern Posix standards (AIX 5.3, 6.1). If realpath
// returns EINVAL, this may indicate that realpath is not POSIX.1-2008 compatible and
// that it complains about the NULL we handed down as user buffer.
// In this case, use the user provided buffer but at least check whether realpath caused
// a memory overwrite.
if ( errno = = EINVAL ) {
outbuf [ outbuflen - 1 ] = ' \0 ' ;
p = : : realpath ( filename , outbuf ) ;
if ( p ! = NULL ) {
guarantee ( outbuf [ outbuflen - 1 ] = = ' \0 ' , " realpath buffer overwrite detected. " ) ;
result = p ;
}
}
}
return result ;
}
2018-06-19 09:34:41 +02:00
int os : : stat ( const char * path , struct stat * sbuf ) {
return : : stat ( path , sbuf ) ;
}
char * os : : native_path ( char * path ) {
return path ;
}
2017-03-13 20:23:11 +01:00
2019-06-28 09:49:10 -07:00
bool os : : same_files ( const char * file1 , const char * file2 ) {
if ( strcmp ( file1 , file2 ) = = 0 ) {
return true ;
}
bool is_same = false ;
struct stat st1 ;
struct stat st2 ;
if ( os : : stat ( file1 , & st1 ) < 0 ) {
return false ;
}
if ( os : : stat ( file2 , & st2 ) < 0 ) {
return false ;
}
if ( st1 . st_dev = = st2 . st_dev & & st1 . st_ino = = st2 . st_ino ) {
// same files
is_same = true ;
}
return is_same ;
}
2016-09-09 11:14:57 -07:00
// Check minimum allowable stack sizes for thread creation and to initialize
// the java system classes, including StackOverflowError - depends on page
2016-12-19 15:48:57 -08:00
// size.
// The space needed for frames during startup is platform dependent. It
// depends on word size, platform calling conventions, C frame layout and
// interpreter/C1/C2 design decisions. Therefore this is given in a
// platform (os/cpu) dependent constant.
// To this, space for guard mechanisms is added, which depends on the
// page size which again depends on the concrete system the VM is running
// on. Space for libc guard pages is not included in this size.
2016-09-09 11:14:57 -07:00
jint os : : Posix : : set_minimum_stack_sizes ( ) {
2017-03-23 11:10:55 -07:00
size_t os_min_stack_allowed = SOLARIS_ONLY ( thr_min_stack ( ) ) NOT_SOLARIS ( PTHREAD_STACK_MIN ) ;
2016-12-19 15:48:57 -08:00
_java_thread_min_stack_allowed = _java_thread_min_stack_allowed +
JavaThread : : stack_guard_zone_size ( ) +
JavaThread : : stack_shadow_zone_size ( ) ;
2016-09-09 11:14:57 -07:00
2017-07-04 15:58:10 +02:00
_java_thread_min_stack_allowed = align_up ( _java_thread_min_stack_allowed , vm_page_size ( ) ) ;
2017-03-23 11:10:55 -07:00
_java_thread_min_stack_allowed = MAX2 ( _java_thread_min_stack_allowed , os_min_stack_allowed ) ;
2016-09-09 11:14:57 -07:00
size_t stack_size_in_bytes = ThreadStackSize * K ;
if ( stack_size_in_bytes ! = 0 & &
stack_size_in_bytes < _java_thread_min_stack_allowed ) {
// The '-Xss' and '-XX:ThreadStackSize=N' options both set
// ThreadStackSize so we go with "Java thread stack size" instead
// of "ThreadStackSize" to be more friendly.
tty - > print_cr ( " \n The Java thread stack size specified is too small. "
" Specify at least " SIZE_FORMAT " k " ,
_java_thread_min_stack_allowed / K ) ;
return JNI_ERR ;
}
// Make the stack size a multiple of the page size so that
// the yellow/red zones can be guarded.
2017-04-13 09:57:51 +02:00
JavaThread : : set_stack_size_at_create ( align_up ( stack_size_in_bytes , vm_page_size ( ) ) ) ;
2016-12-19 15:48:57 -08:00
// Reminder: a compiler thread is a Java thread.
_compiler_thread_min_stack_allowed = _compiler_thread_min_stack_allowed +
JavaThread : : stack_guard_zone_size ( ) +
JavaThread : : stack_shadow_zone_size ( ) ;
2016-09-09 11:14:57 -07:00
2017-07-04 15:58:10 +02:00
_compiler_thread_min_stack_allowed = align_up ( _compiler_thread_min_stack_allowed , vm_page_size ( ) ) ;
2017-03-23 11:10:55 -07:00
_compiler_thread_min_stack_allowed = MAX2 ( _compiler_thread_min_stack_allowed , os_min_stack_allowed ) ;
2016-09-09 11:14:57 -07:00
stack_size_in_bytes = CompilerThreadStackSize * K ;
if ( stack_size_in_bytes ! = 0 & &
stack_size_in_bytes < _compiler_thread_min_stack_allowed ) {
tty - > print_cr ( " \n The CompilerThreadStackSize specified is too small. "
" Specify at least " SIZE_FORMAT " k " ,
_compiler_thread_min_stack_allowed / K ) ;
return JNI_ERR ;
}
2017-07-04 15:58:10 +02:00
_vm_internal_thread_min_stack_allowed = align_up ( _vm_internal_thread_min_stack_allowed , vm_page_size ( ) ) ;
2017-03-23 11:10:55 -07:00
_vm_internal_thread_min_stack_allowed = MAX2 ( _vm_internal_thread_min_stack_allowed , os_min_stack_allowed ) ;
2016-09-09 11:14:57 -07:00
stack_size_in_bytes = VMThreadStackSize * K ;
if ( stack_size_in_bytes ! = 0 & &
stack_size_in_bytes < _vm_internal_thread_min_stack_allowed ) {
tty - > print_cr ( " \n The VMThreadStackSize specified is too small. "
" Specify at least " SIZE_FORMAT " k " ,
_vm_internal_thread_min_stack_allowed / K ) ;
return JNI_ERR ;
}
return JNI_OK ;
}
// Called when creating the thread. The minimum stack sizes have already been calculated
size_t os : : Posix : : get_initial_stack_size ( ThreadType thr_type , size_t req_stack_size ) {
size_t stack_size ;
if ( req_stack_size = = 0 ) {
stack_size = default_stack_size ( thr_type ) ;
} else {
stack_size = req_stack_size ;
}
switch ( thr_type ) {
case os : : java_thread :
// Java threads use ThreadStackSize which default value can be
// changed with the flag -Xss
if ( req_stack_size = = 0 & & JavaThread : : stack_size_at_create ( ) > 0 ) {
// no requested size and we have a more specific default value
stack_size = JavaThread : : stack_size_at_create ( ) ;
}
stack_size = MAX2 ( stack_size ,
_java_thread_min_stack_allowed ) ;
break ;
case os : : compiler_thread :
if ( req_stack_size = = 0 & & CompilerThreadStackSize > 0 ) {
// no requested size and we have a more specific default value
stack_size = ( size_t ) ( CompilerThreadStackSize * K ) ;
}
stack_size = MAX2 ( stack_size ,
_compiler_thread_min_stack_allowed ) ;
break ;
case os : : vm_thread :
case os : : pgc_thread :
case os : : cgc_thread :
case os : : watcher_thread :
default : // presume the unknown thr_type is a VM internal
if ( req_stack_size = = 0 & & VMThreadStackSize > 0 ) {
// no requested size and we have a more specific default value
stack_size = ( size_t ) ( VMThreadStackSize * K ) ;
}
stack_size = MAX2 ( stack_size ,
_vm_internal_thread_min_stack_allowed ) ;
break ;
}
2017-03-23 11:10:55 -07:00
// pthread_attr_setstacksize() may require that the size be rounded up to the OS page size.
// Be careful not to round up to 0. Align down in that case.
if ( stack_size < = SIZE_MAX - vm_page_size ( ) ) {
2017-07-04 15:58:10 +02:00
stack_size = align_up ( stack_size , vm_page_size ( ) ) ;
2017-03-23 11:10:55 -07:00
} else {
2017-07-04 15:58:10 +02:00
stack_size = align_down ( stack_size , vm_page_size ( ) ) ;
2017-03-23 11:10:55 -07:00
}
2016-09-09 11:14:57 -07:00
return stack_size ;
}
2015-11-25 16:33:28 +01:00
2018-05-31 14:09:04 -07:00
bool os : : Posix : : is_root ( uid_t uid ) {
return ROOT_UID = = uid ;
}
bool os : : Posix : : matches_effective_uid_or_root ( uid_t uid ) {
return is_root ( uid ) | | geteuid ( ) = = uid ;
}
bool os : : Posix : : matches_effective_uid_and_gid_or_root ( uid_t uid , gid_t gid ) {
return is_root ( uid ) | | ( geteuid ( ) = = uid & & getegid ( ) = = gid ) ;
}
2017-07-07 23:11:33 +02:00
Thread * os : : ThreadCrashProtection : : _protected_thread = NULL ;
os : : ThreadCrashProtection * os : : ThreadCrashProtection : : _crash_protection = NULL ;
volatile intptr_t os : : ThreadCrashProtection : : _crash_mux = 0 ;
os : : ThreadCrashProtection : : ThreadCrashProtection ( ) {
2013-07-17 13:48:15 +02:00
}
/*
* See the caveats for this class in os_posix . hpp
* Protects the callback call so that SIGSEGV / SIGBUS jumps back into this
* method and returns false . If none of the signals are raised , returns true .
* The callback is supposed to provide the method that should be protected .
*/
2017-07-07 23:11:33 +02:00
bool os : : ThreadCrashProtection : : call ( os : : CrashProtectionCallback & cb ) {
2013-08-29 11:05:55 +02:00
sigset_t saved_sig_mask ;
2017-07-07 23:11:33 +02:00
Thread : : muxAcquire ( & _crash_mux , " CrashProtection " ) ;
_protected_thread = Thread : : current_or_null ( ) ;
assert ( _protected_thread ! = NULL , " Cannot crash protect a NULL thread " ) ;
2013-07-17 13:48:15 +02:00
2013-08-29 11:05:55 +02:00
// we cannot rely on sigsetjmp/siglongjmp to save/restore the signal mask
// since on at least some systems (OS X) siglongjmp will restore the mask
// for the process, not the thread
pthread_sigmask ( 0 , NULL , & saved_sig_mask ) ;
if ( sigsetjmp ( _jmpbuf , 0 ) = = 0 ) {
2013-07-17 13:48:15 +02:00
// make sure we can see in the signal handler that we have crash protection
// installed
2017-07-07 23:11:33 +02:00
_crash_protection = this ;
2013-07-17 13:48:15 +02:00
cb . call ( ) ;
// and clear the crash protection
2017-07-07 23:11:33 +02:00
_crash_protection = NULL ;
_protected_thread = NULL ;
Thread : : muxRelease ( & _crash_mux ) ;
2013-07-17 13:48:15 +02:00
return true ;
}
// this happens when we siglongjmp() back
2013-08-29 11:05:55 +02:00
pthread_sigmask ( SIG_SETMASK , & saved_sig_mask , NULL ) ;
2017-07-07 23:11:33 +02:00
_crash_protection = NULL ;
_protected_thread = NULL ;
Thread : : muxRelease ( & _crash_mux ) ;
2013-07-17 13:48:15 +02:00
return false ;
}
2017-07-07 23:11:33 +02:00
void os : : ThreadCrashProtection : : restore ( ) {
assert ( _crash_protection ! = NULL , " must have crash protection " ) ;
2013-07-17 13:48:15 +02:00
siglongjmp ( _jmpbuf , 1 ) ;
}
2017-07-07 23:11:33 +02:00
void os : : ThreadCrashProtection : : check_crash_protection ( int sig ,
2013-07-17 13:48:15 +02:00
Thread * thread ) {
if ( thread ! = NULL & &
2017-07-07 23:11:33 +02:00
thread = = _protected_thread & &
_crash_protection ! = NULL ) {
2013-07-17 13:48:15 +02:00
if ( sig = = SIGSEGV | | sig = = SIGBUS ) {
2017-07-07 23:11:33 +02:00
_crash_protection - > restore ( ) ;
2013-07-17 13:48:15 +02:00
}
}
}
2015-01-19 11:06:08 +01:00
2019-01-23 21:17:51 -05:00
// Shared clock/time and other supporting routines for pthread_mutex/cond
// initialization. This is enabled on Solaris but only some of the clock/time
// functionality is actually used there.
2017-05-30 17:14:52 -04:00
// Shared condattr object for use with relative timed-waits. Will be associated
// with CLOCK_MONOTONIC if available to avoid issues with time-of-day changes,
// but otherwise whatever default is used by the platform - generally the
// time-of-day clock.
static pthread_condattr_t _condAttr [ 1 ] ;
// Shared mutexattr to explicitly set the type to PTHREAD_MUTEX_NORMAL as not
// all systems (e.g. FreeBSD) map the default to "normal".
static pthread_mutexattr_t _mutexAttr [ 1 ] ;
// common basic initialization that is always supported
static void pthread_init_common ( void ) {
int status ;
if ( ( status = pthread_condattr_init ( _condAttr ) ) ! = 0 ) {
fatal ( " pthread_condattr_init: %s " , os : : strerror ( status ) ) ;
}
if ( ( status = pthread_mutexattr_init ( _mutexAttr ) ) ! = 0 ) {
fatal ( " pthread_mutexattr_init: %s " , os : : strerror ( status ) ) ;
}
if ( ( status = pthread_mutexattr_settype ( _mutexAttr , PTHREAD_MUTEX_NORMAL ) ) ! = 0 ) {
fatal ( " pthread_mutexattr_settype: %s " , os : : strerror ( status ) ) ;
}
2019-08-14 00:18:00 -04:00
// Solaris has it's own PlatformMutex, distinct from the one for POSIX.
NOT_SOLARIS ( os : : PlatformMutex : : init ( ) ; )
2017-05-30 17:14:52 -04:00
}
2019-03-13 00:48:52 -04:00
# ifndef SOLARIS
sigset_t sigs ;
struct sigaction sigact [ NSIG ] ;
struct sigaction * os : : Posix : : get_preinstalled_handler ( int sig ) {
if ( sigismember ( & sigs , sig ) ) {
return & sigact [ sig ] ;
}
return NULL ;
}
void os : : Posix : : save_preinstalled_handler ( int sig , struct sigaction & oldAct ) {
assert ( sig > 0 & & sig < NSIG , " vm signal out of expected range " ) ;
sigact [ sig ] = oldAct ;
sigaddset ( & sigs , sig ) ;
}
# endif
2017-05-30 17:14:52 -04:00
// Not all POSIX types and API's are available on all notionally "posix"
// platforms. If we have build-time support then we will check for actual
// runtime support via dlopen/dlsym lookup. This allows for running on an
// older OS version compared to the build platform. But if there is no
// build time support then there cannot be any runtime support as we do not
// know what the runtime types would be (for example clockid_t might be an
// int or int64_t).
//
# ifdef SUPPORTS_CLOCK_MONOTONIC
// This means we have clockid_t, clock_gettime et al and CLOCK_MONOTONIC
2019-02-05 20:18:00 -05:00
int ( * os : : Posix : : _clock_gettime ) ( clockid_t , struct timespec * ) = NULL ;
int ( * os : : Posix : : _clock_getres ) ( clockid_t , struct timespec * ) = NULL ;
2019-01-23 21:17:51 -05:00
static int ( * _pthread_condattr_setclock ) ( pthread_condattr_t * , clockid_t ) = NULL ;
2017-05-30 17:14:52 -04:00
2019-01-23 21:17:51 -05:00
static bool _use_clock_monotonic_condattr = false ;
2017-05-30 17:14:52 -04:00
// Determine what POSIX API's are present and do appropriate
// configuration.
void os : : Posix : : init ( void ) {
// NOTE: no logging available when this is called. Put logging
// statements in init_2().
// 1. Check for CLOCK_MONOTONIC support.
void * handle = NULL ;
// For linux we need librt, for other OS we can find
// this function in regular libc.
# ifdef NEEDS_LIBRT
// We do dlopen's in this particular order due to bug in linux
// dynamic loader (see 6348968) leading to crash on exit.
handle = dlopen ( " librt.so.1 " , RTLD_LAZY ) ;
if ( handle = = NULL ) {
handle = dlopen ( " librt.so " , RTLD_LAZY ) ;
}
# endif
if ( handle = = NULL ) {
handle = RTLD_DEFAULT ;
}
int ( * clock_getres_func ) ( clockid_t , struct timespec * ) =
( int ( * ) ( clockid_t , struct timespec * ) ) dlsym ( handle , " clock_getres " ) ;
int ( * clock_gettime_func ) ( clockid_t , struct timespec * ) =
( int ( * ) ( clockid_t , struct timespec * ) ) dlsym ( handle , " clock_gettime " ) ;
if ( clock_getres_func ! = NULL & & clock_gettime_func ! = NULL ) {
// We assume that if both clock_gettime and clock_getres support
// CLOCK_MONOTONIC then the OS provides true high-res monotonic clock.
struct timespec res ;
struct timespec tp ;
if ( clock_getres_func ( CLOCK_MONOTONIC , & res ) = = 0 & &
clock_gettime_func ( CLOCK_MONOTONIC , & tp ) = = 0 ) {
// Yes, monotonic clock is supported.
_clock_gettime = clock_gettime_func ;
2018-10-02 17:12:13 -04:00
_clock_getres = clock_getres_func ;
2017-05-30 17:14:52 -04:00
} else {
# ifdef NEEDS_LIBRT
// Close librt if there is no monotonic clock.
if ( handle ! = RTLD_DEFAULT ) {
dlclose ( handle ) ;
}
# endif
}
}
// 2. Check for pthread_condattr_setclock support.
// libpthread is already loaded.
int ( * condattr_setclock_func ) ( pthread_condattr_t * , clockid_t ) =
( int ( * ) ( pthread_condattr_t * , clockid_t ) ) dlsym ( RTLD_DEFAULT ,
" pthread_condattr_setclock " ) ;
if ( condattr_setclock_func ! = NULL ) {
_pthread_condattr_setclock = condattr_setclock_func ;
}
// Now do general initialization.
pthread_init_common ( ) ;
2019-01-23 21:17:51 -05:00
# ifndef SOLARIS
2017-05-30 17:14:52 -04:00
int status ;
if ( _pthread_condattr_setclock ! = NULL & & _clock_gettime ! = NULL ) {
if ( ( status = _pthread_condattr_setclock ( _condAttr , CLOCK_MONOTONIC ) ) ! = 0 ) {
if ( status = = EINVAL ) {
_use_clock_monotonic_condattr = false ;
warning ( " Unable to use monotonic clock with relative timed-waits " \
" - changes to the time-of-day clock may have adverse affects " ) ;
} else {
fatal ( " pthread_condattr_setclock: %s " , os : : strerror ( status ) ) ;
}
} else {
_use_clock_monotonic_condattr = true ;
}
}
2019-01-23 21:17:51 -05:00
# endif // !SOLARIS
2017-05-30 17:14:52 -04:00
}
void os : : Posix : : init_2 ( void ) {
2019-01-23 21:17:51 -05:00
# ifndef SOLARIS
2017-05-30 17:14:52 -04:00
log_info ( os ) ( " Use of CLOCK_MONOTONIC is%s supported " ,
( _clock_gettime ! = NULL ? " " : " not " ) ) ;
log_info ( os ) ( " Use of pthread_condattr_setclock is%s supported " ,
( _pthread_condattr_setclock ! = NULL ? " " : " not " ) ) ;
log_info ( os ) ( " Relative timed-wait using pthread_cond_timedwait is associated with %s " ,
_use_clock_monotonic_condattr ? " CLOCK_MONOTONIC " : " the default clock " ) ;
2019-03-13 00:48:52 -04:00
sigemptyset ( & sigs ) ;
2019-01-23 21:17:51 -05:00
# endif // !SOLARIS
2017-05-30 17:14:52 -04:00
}
# else // !SUPPORTS_CLOCK_MONOTONIC
void os : : Posix : : init ( void ) {
pthread_init_common ( ) ;
}
void os : : Posix : : init_2 ( void ) {
2019-01-23 21:17:51 -05:00
# ifndef SOLARIS
2017-05-30 17:14:52 -04:00
log_info ( os ) ( " Use of CLOCK_MONOTONIC is not supported " ) ;
log_info ( os ) ( " Use of pthread_condattr_setclock is not supported " ) ;
log_info ( os ) ( " Relative timed-wait using pthread_cond_timedwait is associated with the default clock " ) ;
2019-03-13 00:48:52 -04:00
sigemptyset ( & sigs ) ;
2019-01-23 21:17:51 -05:00
# endif // !SOLARIS
2017-05-30 17:14:52 -04:00
}
# endif // SUPPORTS_CLOCK_MONOTONIC
// Utility to convert the given timeout to an absolute timespec
2019-01-23 21:17:51 -05:00
// (based on the appropriate clock) to use with pthread_cond_timewait,
// and sem_timedwait().
2017-05-30 17:14:52 -04:00
// The clock queried here must be the clock used to manage the
2019-01-23 21:17:51 -05:00
// timeout of the condition variable or semaphore.
2017-05-30 17:14:52 -04:00
//
// The passed in timeout value is either a relative time in nanoseconds
// or an absolute time in milliseconds. A relative timeout will be
2019-01-23 21:17:51 -05:00
// associated with CLOCK_MONOTONIC if available, unless the real-time clock
// is explicitly requested; otherwise, or if absolute,
2017-05-30 17:14:52 -04:00
// the default time-of-day clock will be used.
// Given time is a 64-bit value and the time_t used in the timespec is
// sometimes a signed-32-bit value we have to watch for overflow if times
// way in the future are given. Further on Solaris versions
// prior to 10 there is a restriction (see cond_timedwait) that the specified
// number of seconds, in abstime, is less than current_time + 100000000.
// As it will be over 20 years before "now + 100000000" will overflow we can
// ignore overflow and just impose a hard-limit on seconds using the value
// of "now + 100000000". This places a limit on the timeout of about 3.17
// years from "now".
//
# define MAX_SECS 100000000
// Calculate a new absolute time that is "timeout" nanoseconds from "now".
// "unit" indicates the unit of "now_part_sec" (may be nanos or micros depending
2019-01-23 21:17:51 -05:00
// on which clock API is being used).
2017-05-30 17:14:52 -04:00
static void calc_rel_time ( timespec * abstime , jlong timeout , jlong now_sec ,
jlong now_part_sec , jlong unit ) {
time_t max_secs = now_sec + MAX_SECS ;
jlong seconds = timeout / NANOUNITS ;
timeout % = NANOUNITS ; // remaining nanos
if ( seconds > = MAX_SECS ) {
// More seconds than we can add, so pin to max_secs.
abstime - > tv_sec = max_secs ;
abstime - > tv_nsec = 0 ;
} else {
abstime - > tv_sec = now_sec + seconds ;
long nanos = ( now_part_sec * ( NANOUNITS / unit ) ) + timeout ;
if ( nanos > = NANOUNITS ) { // overflow
abstime - > tv_sec + = 1 ;
nanos - = NANOUNITS ;
}
abstime - > tv_nsec = nanos ;
}
}
// Unpack the given deadline in milliseconds since the epoch, into the given timespec.
// The current time in seconds is also passed in to enforce an upper bound as discussed above.
2019-01-23 21:17:51 -05:00
// This is only used with gettimeofday, when clock_gettime is not available.
2017-05-30 17:14:52 -04:00
static void unpack_abs_time ( timespec * abstime , jlong deadline , jlong now_sec ) {
time_t max_secs = now_sec + MAX_SECS ;
jlong seconds = deadline / MILLIUNITS ;
jlong millis = deadline % MILLIUNITS ;
if ( seconds > = max_secs ) {
// Absolute seconds exceeds allowed max, so pin to max_secs.
abstime - > tv_sec = max_secs ;
abstime - > tv_nsec = 0 ;
} else {
abstime - > tv_sec = seconds ;
abstime - > tv_nsec = millis * ( NANOUNITS / MILLIUNITS ) ;
}
}
2019-01-23 21:17:51 -05:00
static jlong millis_to_nanos ( jlong millis ) {
// We have to watch for overflow when converting millis to nanos,
// but if millis is that large then we will end up limiting to
// MAX_SECS anyway, so just do that here.
if ( millis / MILLIUNITS > MAX_SECS ) {
millis = jlong ( MAX_SECS ) * MILLIUNITS ;
}
return millis * ( NANOUNITS / MILLIUNITS ) ;
}
static void to_abstime ( timespec * abstime , jlong timeout ,
bool isAbsolute , bool isRealtime ) {
2017-05-30 17:14:52 -04:00
DEBUG_ONLY ( int max_secs = MAX_SECS ; )
if ( timeout < 0 ) {
timeout = 0 ;
}
# ifdef SUPPORTS_CLOCK_MONOTONIC
2019-01-23 21:17:51 -05:00
clockid_t clock = CLOCK_MONOTONIC ;
// need to ensure we have a runtime check for clock_gettime support
2019-02-05 20:18:00 -05:00
if ( ! isAbsolute & & os : : Posix : : supports_monotonic_clock ( ) ) {
2019-01-23 21:17:51 -05:00
if ( ! _use_clock_monotonic_condattr | | isRealtime ) {
clock = CLOCK_REALTIME ;
}
2017-05-30 17:14:52 -04:00
struct timespec now ;
2019-02-05 20:18:00 -05:00
int status = os : : Posix : : clock_gettime ( clock , & now ) ;
2017-05-30 17:14:52 -04:00
assert_status ( status = = 0 , status , " clock_gettime " ) ;
calc_rel_time ( abstime , timeout , now . tv_sec , now . tv_nsec , NANOUNITS ) ;
DEBUG_ONLY ( max_secs + = now . tv_sec ; )
} else {
# else
{ // Match the block scope.
# endif // SUPPORTS_CLOCK_MONOTONIC
// Time-of-day clock is all we can reliably use.
struct timeval now ;
int status = gettimeofday ( & now , NULL ) ;
assert_status ( status = = 0 , errno , " gettimeofday " ) ;
if ( isAbsolute ) {
unpack_abs_time ( abstime , timeout , now . tv_sec ) ;
} else {
calc_rel_time ( abstime , timeout , now . tv_sec , now . tv_usec , MICROUNITS ) ;
}
DEBUG_ONLY ( max_secs + = now . tv_sec ; )
}
assert ( abstime - > tv_sec > = 0 , " tv_sec < 0 " ) ;
assert ( abstime - > tv_sec < = max_secs , " tv_sec > max_secs " ) ;
assert ( abstime - > tv_nsec > = 0 , " tv_nsec < 0 " ) ;
assert ( abstime - > tv_nsec < NANOUNITS , " tv_nsec >= NANOUNITS " ) ;
}
2019-01-23 21:17:51 -05:00
// Create an absolute time 'millis' milliseconds in the future, using the
// real-time (time-of-day) clock. Used by PosixSemaphore.
void os : : Posix : : to_RTC_abstime ( timespec * abstime , int64_t millis ) {
to_abstime ( abstime , millis_to_nanos ( millis ) ,
false /* not absolute */ ,
true /* use real-time clock */ ) ;
}
// Shared pthread_mutex/cond based PlatformEvent implementation.
// Not currently usable by Solaris.
# ifndef SOLARIS
2017-05-30 17:14:52 -04:00
// PlatformEvent
//
// Assumption:
// Only one parker can exist on an event, which is why we allocate
// them per-thread. Multiple unparkers can coexist.
//
// _event serves as a restricted-range semaphore.
// -1 : thread is blocked, i.e. there is a waiter
// 0 : neutral: thread is running or ready,
// could have been signaled after a wait started
// 1 : signaled - thread is running or ready
//
// Having three states allows for some detection of bad usage - see
// comments on unpark().
2019-01-23 21:17:51 -05:00
os : : PlatformEvent : : PlatformEvent ( ) {
int status = pthread_cond_init ( _cond , _condAttr ) ;
assert_status ( status = = 0 , status , " cond_init " ) ;
status = pthread_mutex_init ( _mutex , _mutexAttr ) ;
assert_status ( status = = 0 , status , " mutex_init " ) ;
_event = 0 ;
_nParked = 0 ;
}
2017-05-30 17:14:52 -04:00
void os : : PlatformEvent : : park ( ) { // AKA "down()"
// Transitions for _event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _event to 0 before returning
// Invariant: Only the thread associated with the PlatformEvent
// may call park().
assert ( _nParked = = 0 , " invariant " ) ;
int v ;
// atomically decrement _event
for ( ; ; ) {
v = _event ;
if ( Atomic : : cmpxchg ( v - 1 , & _event , v ) = = v ) break ;
}
guarantee ( v > = 0 , " invariant " ) ;
if ( v = = 0 ) { // Do this the hard way by blocking ...
int status = pthread_mutex_lock ( _mutex ) ;
assert_status ( status = = 0 , status , " mutex_lock " ) ;
guarantee ( _nParked = = 0 , " invariant " ) ;
+ + _nParked ;
while ( _event < 0 ) {
// OS-level "spurious wakeups" are ignored
status = pthread_cond_wait ( _cond , _mutex ) ;
assert_status ( status = = 0 , status , " cond_wait " ) ;
}
- - _nParked ;
_event = 0 ;
status = pthread_mutex_unlock ( _mutex ) ;
assert_status ( status = = 0 , status , " mutex_unlock " ) ;
// Paranoia to ensure our locked and lock-free paths interact
// correctly with each other.
OrderAccess : : fence ( ) ;
}
guarantee ( _event > = 0 , " invariant " ) ;
}
int os : : PlatformEvent : : park ( jlong millis ) {
// Transitions for _event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _event to 0 before returning
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
assert ( _nParked = = 0 , " invariant " ) ;
int v ;
// atomically decrement _event
for ( ; ; ) {
v = _event ;
if ( Atomic : : cmpxchg ( v - 1 , & _event , v ) = = v ) break ;
}
guarantee ( v > = 0 , " invariant " ) ;
if ( v = = 0 ) { // Do this the hard way by blocking ...
struct timespec abst ;
2019-01-23 21:17:51 -05:00
to_abstime ( & abst , millis_to_nanos ( millis ) , false , false ) ;
2017-05-30 17:14:52 -04:00
int ret = OS_TIMEOUT ;
int status = pthread_mutex_lock ( _mutex ) ;
assert_status ( status = = 0 , status , " mutex_lock " ) ;
guarantee ( _nParked = = 0 , " invariant " ) ;
+ + _nParked ;
while ( _event < 0 ) {
status = pthread_cond_timedwait ( _cond , _mutex , & abst ) ;
assert_status ( status = = 0 | | status = = ETIMEDOUT ,
status , " cond_timedwait " ) ;
// OS-level "spurious wakeups" are ignored unless the archaic
// FilterSpuriousWakeups is set false. That flag should be obsoleted.
if ( ! FilterSpuriousWakeups ) break ;
if ( status = = ETIMEDOUT ) break ;
}
- - _nParked ;
if ( _event > = 0 ) {
ret = OS_OK ;
}
_event = 0 ;
status = pthread_mutex_unlock ( _mutex ) ;
assert_status ( status = = 0 , status , " mutex_unlock " ) ;
// Paranoia to ensure our locked and lock-free paths interact
// correctly with each other.
OrderAccess : : fence ( ) ;
return ret ;
}
return OS_OK ;
}
void os : : PlatformEvent : : unpark ( ) {
// Transitions for _event:
// 0 => 1 : just return
// 1 => 1 : just return
// -1 => either 0 or 1; must signal target thread
// That is, we can safely transition _event from -1 to either
// 0 or 1.
// See also: "Semaphores in Plan 9" by Mullender & Cox
//
// Note: Forcing a transition from "-1" to "1" on an unpark() means
// that it will take two back-to-back park() calls for the owning
// thread to block. This has the benefit of forcing a spurious return
// from the first park() call after an unpark() call which will help
// shake out uses of park() and unpark() without checking state conditions
// properly. This spurious return doesn't manifest itself in any user code
// but only in the correctly written condition checking loops of ObjectMonitor,
2019-09-11 22:09:05 -04:00
// Mutex/Monitor, Thread::muxAcquire and JavaThread::sleep
2017-05-30 17:14:52 -04:00
2019-11-25 12:32:40 +01:00
if ( Atomic : : xchg ( & _event , 1 ) > = 0 ) return ;
2017-05-30 17:14:52 -04:00
int status = pthread_mutex_lock ( _mutex ) ;
assert_status ( status = = 0 , status , " mutex_lock " ) ;
int anyWaiters = _nParked ;
assert ( anyWaiters = = 0 | | anyWaiters = = 1 , " invariant " ) ;
status = pthread_mutex_unlock ( _mutex ) ;
assert_status ( status = = 0 , status , " mutex_unlock " ) ;
// Note that we signal() *after* dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim
// will simply re-test the condition and re-park itself.
// This provides particular benefit if the underlying platform does not
// provide wait morphing.
if ( anyWaiters ! = 0 ) {
status = pthread_cond_signal ( _cond ) ;
assert_status ( status = = 0 , status , " cond_signal " ) ;
}
}
// JSR166 support
os : : PlatformParker : : PlatformParker ( ) {
int status ;
status = pthread_cond_init ( & _cond [ REL_INDEX ] , _condAttr ) ;
assert_status ( status = = 0 , status , " cond_init rel " ) ;
status = pthread_cond_init ( & _cond [ ABS_INDEX ] , NULL ) ;
assert_status ( status = = 0 , status , " cond_init abs " ) ;
status = pthread_mutex_init ( _mutex , _mutexAttr ) ;
assert_status ( status = = 0 , status , " mutex_init " ) ;
_cur_index = - 1 ; // mark as unused
}
// Parker::park decrements count if > 0, else does a condvar wait. Unpark
// sets count to 1 and signals condvar. Only one thread ever waits
// on the condvar. Contention seen when trying to park implies that someone
// is unparking you, so don't wait. And spurious returns are fine, so there
// is no need to track notifications.
void Parker : : park ( bool isAbsolute , jlong time ) {
// Optional fast-path check:
// Return immediately if a permit is available.
// We depend on Atomic::xchg() having full barrier semantics
// since we are doing a lock-free update to _counter.
2019-11-25 12:32:40 +01:00
if ( Atomic : : xchg ( & _counter , 0 ) > 0 ) return ;
2017-05-30 17:14:52 -04:00
Thread * thread = Thread : : current ( ) ;
assert ( thread - > is_Java_thread ( ) , " Must be JavaThread " ) ;
JavaThread * jt = ( JavaThread * ) thread ;
// Optional optimization -- avoid state transitions if there's
// an interrupt pending.
2019-09-17 19:09:37 -04:00
if ( jt - > is_interrupted ( false ) ) {
2017-05-30 17:14:52 -04:00
return ;
}
// Next, demultiplex/decode time arguments
struct timespec absTime ;
if ( time < 0 | | ( isAbsolute & & time = = 0 ) ) { // don't wait at all
return ;
}
if ( time > 0 ) {
2019-01-23 21:17:51 -05:00
to_abstime ( & absTime , time , isAbsolute , false ) ;
2017-05-30 17:14:52 -04:00
}
// Enter safepoint region
// Beware of deadlocks such as 6317397.
// The per-thread Parker:: mutex is a classic leaf-lock.
// In particular a thread must never block on the Threads_lock while
// holding the Parker:: mutex. If safepoints are pending both the
// the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
ThreadBlockInVM tbivm ( jt ) ;
2019-11-14 22:36:40 -05:00
// Can't access interrupt state now that we are _thread_blocked. If we've
// been interrupted since we checked above then _counter will be > 0.
2017-05-30 17:14:52 -04:00
// Don't wait if cannot get lock since interference arises from
2019-11-14 22:36:40 -05:00
// unparking.
if ( pthread_mutex_trylock ( _mutex ) ! = 0 ) {
2017-05-30 17:14:52 -04:00
return ;
}
int status ;
if ( _counter > 0 ) { // no wait needed
_counter = 0 ;
status = pthread_mutex_unlock ( _mutex ) ;
assert_status ( status = = 0 , status , " invariant " ) ;
// Paranoia to ensure our locked and lock-free paths interact
// correctly with each other and Java-level accesses.
OrderAccess : : fence ( ) ;
return ;
}
OSThreadWaitState osts ( thread - > osthread ( ) , false /* not Object.wait() */ ) ;
jt - > set_suspend_equivalent ( ) ;
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
assert ( _cur_index = = - 1 , " invariant " ) ;
if ( time = = 0 ) {
_cur_index = REL_INDEX ; // arbitrary choice when not timed
status = pthread_cond_wait ( & _cond [ _cur_index ] , _mutex ) ;
assert_status ( status = = 0 , status , " cond_timedwait " ) ;
}
else {
_cur_index = isAbsolute ? ABS_INDEX : REL_INDEX ;
status = pthread_cond_timedwait ( & _cond [ _cur_index ] , _mutex , & absTime ) ;
assert_status ( status = = 0 | | status = = ETIMEDOUT ,
status , " cond_timedwait " ) ;
}
_cur_index = - 1 ;
_counter = 0 ;
status = pthread_mutex_unlock ( _mutex ) ;
assert_status ( status = = 0 , status , " invariant " ) ;
// Paranoia to ensure our locked and lock-free paths interact
// correctly with each other and Java-level accesses.
OrderAccess : : fence ( ) ;
// If externally suspended while waiting, re-suspend
if ( jt - > handle_special_suspend_equivalent_condition ( ) ) {
jt - > java_suspend_self ( ) ;
}
}
void Parker : : unpark ( ) {
int status = pthread_mutex_lock ( _mutex ) ;
assert_status ( status = = 0 , status , " invariant " ) ;
const int s = _counter ;
_counter = 1 ;
// must capture correct index before unlocking
int index = _cur_index ;
status = pthread_mutex_unlock ( _mutex ) ;
assert_status ( status = = 0 , status , " invariant " ) ;
// Note that we signal() *after* dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim
// will simply re-test the condition and re-park itself.
// This provides particular benefit if the underlying platform does not
// provide wait morphing.
if ( s < 1 & & index ! = - 1 ) {
// thread is definitely parked
status = pthread_cond_signal ( & _cond [ index ] ) ;
assert_status ( status = = 0 , status , " invariant " ) ;
}
}
2019-08-14 00:18:00 -04:00
// Platform Mutex/Monitor implementation
2019-02-05 15:12:13 -05:00
2019-08-14 00:18:00 -04:00
# if PLATFORM_MONITOR_IMPL_INDIRECT
os : : PlatformMutex : : Mutex : : Mutex ( ) : _next ( NULL ) {
int status = pthread_mutex_init ( & _mutex , _mutexAttr ) ;
2019-02-05 15:12:13 -05:00
assert_status ( status = = 0 , status , " mutex_init " ) ;
}
2019-08-14 00:18:00 -04:00
os : : PlatformMutex : : Mutex : : ~ Mutex ( ) {
int status = pthread_mutex_destroy ( & _mutex ) ;
2019-02-05 15:12:13 -05:00
assert_status ( status = = 0 , status , " mutex_destroy " ) ;
}
2019-08-14 00:18:00 -04:00
pthread_mutex_t os : : PlatformMutex : : _freelist_lock ;
os : : PlatformMutex : : Mutex * os : : PlatformMutex : : _mutex_freelist = NULL ;
2019-03-19 14:32:41 -04:00
2019-08-14 00:18:00 -04:00
void os : : PlatformMutex : : init ( ) {
2019-03-19 14:32:41 -04:00
int status = pthread_mutex_init ( & _freelist_lock , _mutexAttr ) ;
assert_status ( status = = 0 , status , " freelist lock init " ) ;
}
2019-08-14 00:18:00 -04:00
struct os : : PlatformMutex : : WithFreeListLocked : public StackObj {
2019-03-19 14:32:41 -04:00
WithFreeListLocked ( ) {
int status = pthread_mutex_lock ( & _freelist_lock ) ;
assert_status ( status = = 0 , status , " freelist lock " ) ;
}
~ WithFreeListLocked ( ) {
int status = pthread_mutex_unlock ( & _freelist_lock ) ;
assert_status ( status = = 0 , status , " freelist unlock " ) ;
}
} ;
2019-08-14 00:18:00 -04:00
os : : PlatformMutex : : PlatformMutex ( ) {
{
WithFreeListLocked wfl ;
_impl = _mutex_freelist ;
if ( _impl ! = NULL ) {
_mutex_freelist = _impl - > _next ;
_impl - > _next = NULL ;
return ;
}
}
_impl = new Mutex ( ) ;
}
os : : PlatformMutex : : ~ PlatformMutex ( ) {
WithFreeListLocked wfl ;
assert ( _impl - > _next = = NULL , " invariant " ) ;
_impl - > _next = _mutex_freelist ;
_mutex_freelist = _impl ;
}
os : : PlatformMonitor : : Cond : : Cond ( ) : _next ( NULL ) {
int status = pthread_cond_init ( & _cond , _condAttr ) ;
assert_status ( status = = 0 , status , " cond_init " ) ;
}
os : : PlatformMonitor : : Cond : : ~ Cond ( ) {
int status = pthread_cond_destroy ( & _cond ) ;
assert_status ( status = = 0 , status , " cond_destroy " ) ;
}
os : : PlatformMonitor : : Cond * os : : PlatformMonitor : : _cond_freelist = NULL ;
2019-03-19 14:32:41 -04:00
os : : PlatformMonitor : : PlatformMonitor ( ) {
{
WithFreeListLocked wfl ;
2019-08-14 00:18:00 -04:00
_impl = _cond_freelist ;
2019-03-19 14:32:41 -04:00
if ( _impl ! = NULL ) {
2019-08-14 00:18:00 -04:00
_cond_freelist = _impl - > _next ;
2019-03-19 14:32:41 -04:00
_impl - > _next = NULL ;
return ;
}
}
2019-08-14 00:18:00 -04:00
_impl = new Cond ( ) ;
2019-03-19 14:32:41 -04:00
}
os : : PlatformMonitor : : ~ PlatformMonitor ( ) {
WithFreeListLocked wfl ;
assert ( _impl - > _next = = NULL , " invariant " ) ;
2019-08-14 00:18:00 -04:00
_impl - > _next = _cond_freelist ;
_cond_freelist = _impl ;
}
# else
os : : PlatformMutex : : PlatformMutex ( ) {
int status = pthread_mutex_init ( & _mutex , _mutexAttr ) ;
assert_status ( status = = 0 , status , " mutex_init " ) ;
}
os : : PlatformMutex : : ~ PlatformMutex ( ) {
int status = pthread_mutex_destroy ( & _mutex ) ;
assert_status ( status = = 0 , status , " mutex_destroy " ) ;
}
os : : PlatformMonitor : : PlatformMonitor ( ) {
int status = pthread_cond_init ( & _cond , _condAttr ) ;
assert_status ( status = = 0 , status , " cond_init " ) ;
}
os : : PlatformMonitor : : ~ PlatformMonitor ( ) {
int status = pthread_cond_destroy ( & _cond ) ;
assert_status ( status = = 0 , status , " cond_destroy " ) ;
2019-03-19 14:32:41 -04:00
}
# endif // PLATFORM_MONITOR_IMPL_INDIRECT
2019-02-05 15:12:13 -05:00
// Must already be locked
int os : : PlatformMonitor : : wait ( jlong millis ) {
assert ( millis > = 0 , " negative timeout " ) ;
if ( millis > 0 ) {
struct timespec abst ;
// We have to watch for overflow when converting millis to nanos,
// but if millis is that large then we will end up limiting to
// MAX_SECS anyway, so just do that here.
if ( millis / MILLIUNITS > MAX_SECS ) {
millis = jlong ( MAX_SECS ) * MILLIUNITS ;
}
to_abstime ( & abst , millis * ( NANOUNITS / MILLIUNITS ) , false , false ) ;
int ret = OS_TIMEOUT ;
2019-03-19 14:32:41 -04:00
int status = pthread_cond_timedwait ( cond ( ) , mutex ( ) , & abst ) ;
2019-02-05 15:12:13 -05:00
assert_status ( status = = 0 | | status = = ETIMEDOUT ,
status , " cond_timedwait " ) ;
if ( status = = 0 ) {
ret = OS_OK ;
}
return ret ;
} else {
2019-03-19 14:32:41 -04:00
int status = pthread_cond_wait ( cond ( ) , mutex ( ) ) ;
2019-02-05 15:12:13 -05:00
assert_status ( status = = 0 , status , " cond_wait " ) ;
return OS_OK ;
}
}
2017-05-30 17:14:52 -04:00
# endif // !SOLARIS