diff --git a/fvtest/porttest/si.cpp b/fvtest/porttest/si.cpp index d36f78f7977..5c3533932ad 100644 --- a/fvtest/porttest/si.cpp +++ b/fvtest/porttest/si.cpp @@ -2109,51 +2109,35 @@ TEST(PortSysinfoTest, sysinfo_cgroup_get_memlimit) OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary()); const char *testName = "omrsysinfo_cgroup_get_memlimit"; uint64_t cgroupMemLimit = 0; - int32_t cgroupLimitEnabled = 0; int32_t rc = 0; + uint64_t enabledSubsystems = 0; reportTestEntry(OMRPORTLIB, testName); - /* Call omrsysinfo_cgroup_get_memlimit without enabling cgroup limits */ rc = omrsysinfo_cgroup_get_memlimit(&cgroupMemLimit); -#if defined(LINUX) - if (OMRPORT_ERROR_SYSINFO_CGROUP_LIMITS_DISABLED != rc) { - outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_memlimit returned %d, expected %d\n", rc, OMRPORT_ERROR_SYSINFO_CGROUP_LIMITS_DISABLED); - } -#else +#if !defined(LINUX) if (OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM != rc) { - outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_memlimit returned %d, exptected %d on platform that does not support cgroups\n", rc, OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM); + outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_memlimit returned %d, expected %d on platform that does not support cgroups\n", rc, OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM); } #endif - /* Call omrsysinfo_cgroup_get_memlimit after enabling cgroup limits */ - cgroupLimitEnabled = omrsysinfo_cgroup_enable_limits(); - - rc = omrsysinfo_cgroup_get_memlimit(&cgroupMemLimit); - -#if defined(LINUX) - if (0 == cgroupLimitEnabled) { - if (OMRPORT_ERROR_SYSINFO_CGROUP_LIMITS_DISABLED == rc) { - outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_memlimit returned %d when cgroup limits was enabled successfully\n", rc); + /* Compare sysinfo_get_physical_memory and sysinfo_cgroup_get_memlimit after enabling memory subsystem */ + enabledSubsystems = omrsysinfo_cgroup_enable_subsystems(OMR_CGROUP_SUBSYSTEM_MEMORY); + if (OMR_ARE_ALL_BITS_SET(enabledSubsystems, OMR_CGROUP_SUBSYSTEM_MEMORY)) { + rc = omrsysinfo_cgroup_get_memlimit(&cgroupMemLimit); + if (0 != rc) { + outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_memlimit failed with error code %d\n", rc); } else if (0 == rc) { uint64_t physicalMemLimit = 0; physicalMemLimit = omrsysinfo_get_physical_memory(); if (cgroupMemLimit != physicalMemLimit) { - outputErrorMessage(PORTTEST_ERROR_ARGS, "Expected omrsysinfo_cgroup_get_memlimit and omrsysinfo_get_physical_memory to return same value, but omrsysinfo_cgroup_get_memlimit returned %ld and omrsysinfo_get_physical_memory returned %ld\n"); + outputErrorMessage(PORTTEST_ERROR_ARGS, "Expected omrsysinfo_cgroup_get_memlimit and omrsysinfo_get_physical_memory to return same value, but omrsysinfo_cgroup_get_memlimit returned %ld and omrsysinfo_get_physical_memory returned %ld\n", cgroupMemLimit, physicalMemLimit); } } - } else { - if (OMRPORT_ERROR_SYSINFO_CGROUP_LIMITS_DISABLED != rc) { - outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_memlimit returned %d, expected %d\n", rc, OMRPORT_ERROR_SYSINFO_CGROUP_LIMITS_DISABLED); - } } -#else - if (OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM != rc) { - outputErrorMessage(PORTTEST_ERROR_ARGS, "omrsysinfo_cgroup_get_memlimit returned %d, exptected %d on platform that does not support cgroups\n", rc, OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM); - } -#endif + reportTestExit(OMRPORTLIB, testName); return; } diff --git a/include_core/omrport.h b/include_core/omrport.h index 48a83efe4b6..4898169d46b 100644 --- a/include_core/omrport.h +++ b/include_core/omrport.h @@ -1001,6 +1001,11 @@ typedef struct OMROSKernelInfo { uint32_t minorRevision; } OMROSKernelInfo; +/* bitwise flags indicating cgroup subsystems supported by portlibrary */ +#define OMR_CGROUP_SUBSYSTEM_CPU ((uint64_t)0x1) +#define OMR_CGROUP_SUBSYSTEM_MEMORY ((uint64_t)0x2) +#define OMR_CGROUP_SUBSYSTEM_ALL (OMR_CGROUP_SUBSYSTEM_CPU | OMR_CGROUP_SUBSYSTEM_MEMORY) + struct OMRPortLibrary; typedef struct J9Heap J9Heap; @@ -1438,12 +1443,18 @@ typedef struct OMRPortLibrary { BOOLEAN ( *sysinfo_os_has_feature)(struct OMRPortLibrary *portLibrary, struct OMROSDesc *desc, uint32_t feature) ; /** see @ref omrsysinfo.c::omrsysinfo_os_kernel_info "omrsysinfo_os_kernel_info"*/ BOOLEAN ( *sysinfo_os_kernel_info)(struct OMRPortLibrary *portLibrary, struct OMROSKernelInfo *kernelInfo) ; - /** see @ref omrsysinfo.c::omrsysinfo_cgroup_is_limits_supported "omrsysinfo_cgroup_is_limits_supported"*/ - int32_t ( *sysinfo_cgroup_is_limits_supported)(struct OMRPortLibrary *portLibrary); - /** see @ref omrsysinfo.c::omrsysinfo_cgroup_is_limits_enabled "omrsysinfo_cgroup_is_limits_enabled"*/ - BOOLEAN ( *sysinfo_cgroup_is_limits_enabled)(struct OMRPortLibrary *portLibrary); - /** see @ref omrsysinfo.c::omrsysinfo_cgroup_enable_limits "omrsysinfo_cgroup_enable_limits"*/ - int32_t ( *sysinfo_cgroup_enable_limits)(struct OMRPortLibrary *portLibrary); + /** see @ref omrsysinfo.c::omrsysinfo_cgroup_is_system_available "omrsysinfo_cgroup_is_system_available"*/ + BOOLEAN ( *sysinfo_cgroup_is_system_available)(struct OMRPortLibrary *portLibrary); + /** see @ref omrsysinfo.c::omrsysinfo_cgroup_get_available_subsystems "omrsysinfo_cgroup_get_available_subsystems"*/ + uint64_t ( *sysinfo_cgroup_get_available_subsystems)(struct OMRPortLibrary *portLibrary); + /** see @ref omrsysinfo.c::omrsysinfo_cgroup_are_subsystems_available "omrsysinfo_cgroup_are_subsystems_available"*/ + uint64_t ( *sysinfo_cgroup_are_subsystems_available)(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlags); + /** see @ref omrsysinfo.c::omrsysinfo_cgroup_get_enabled_subsystems "omrsysinfo_cgroup_get_enabled_subsystems"*/ + uint64_t ( *sysinfo_cgroup_get_enabled_subsystems)(struct OMRPortLibrary *portLibrary); + /** see @ref omrsysinfo_cgroup_enable_subsystems "omrsysinfo_cgroup_enable_subsystems"*/ + uint64_t ( *sysinfo_cgroup_enable_subsystems)(struct OMRPortLibrary *portLibrary, uint64_t requestedSubsystems); + /** see @ref omrsysinfo_cgroup_are_subsystems_enabled "omrsysinfo_cgroup_are_subsystems_enabled"*/ + uint64_t ( *sysinfo_cgroup_are_subsystems_enabled)(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlags); /** see @ref omrsysinfo.c::omrsysinfo_cgroup_get_memlimit "omrsysinfo_cgroup_get_memlimit"*/ int32_t (*sysinfo_cgroup_get_memlimit)(struct OMRPortLibrary *portLibrary, uint64_t *limit); /** see @ref omrport.c::omrport_init_library "omrport_init_library"*/ @@ -1886,9 +1897,12 @@ extern J9_CFUNC int32_t omrport_getVersion(struct OMRPortLibrary *portLibrary); #define omrsysinfo_get_os_description(param1) privateOmrPortLibrary->sysinfo_get_os_description(privateOmrPortLibrary, (param1)) #define omrsysinfo_os_has_feature(param1,param2) privateOmrPortLibrary->sysinfo_os_has_feature(privateOmrPortLibrary, (param1), (param2)) #define omrsysinfo_os_kernel_info(param1) privateOmrPortLibrary->sysinfo_os_kernel_info(privateOmrPortLibrary, (param1)) -#define omrsysinfo_cgroup_is_limits_supported() privateOmrPortLibrary->sysinfo_cgroup_is_limits_supported(privateOmrPortLibrary) -#define omrsysinfo_cgroup_is_limits_enabled() privateOmrPortLibrary->sysinfo_cgroup_is_limits_enabled(privateOmrPortLibrary) -#define omrsysinfo_cgroup_enable_limits() privateOmrPortLibrary->sysinfo_cgroup_enable_limits(privateOmrPortLibrary) +#define omrsysinfo_cgroup_is_system_available() privateOmrPortLibrary->sysinfo_cgroup_is_system_available(privateOmrPortLibrary) +#define omrsysinfo_cgroup_get_available_subsystems() privateOmrPortLibrary->sysinfo_cgroup_get_available_subsystems(privateOmrPortLibrary) +#define omrsysinfo_cgroup_are_subsystems_available(param1) privateOmrPortLibrary->sysinfo_cgroup_are_subsystems_available(privateOmrPortLibrary, param1) +#define omrsysinfo_cgroup_get_enabled_subsystems() privateOmrPortLibrary->sysinfo_cgroup_get_enabled_subsystems(privateOmrPortLibrary) +#define omrsysinfo_cgroup_enable_subsystems(param1) privateOmrPortLibrary->sysinfo_cgroup_enable_subsystems(privateOmrPortLibrary, param1) +#define omrsysinfo_cgroup_are_subsystems_enabled(param1) privateOmrPortLibrary->sysinfo_cgroup_are_subsystems_enabled(privateOmrPortLibrary, param1) #define omrsysinfo_cgroup_get_memlimit(param1) privateOmrPortLibrary->sysinfo_cgroup_get_memlimit(privateOmrPortLibrary, param1) #define omrintrospect_startup() privateOmrPortLibrary->introspect_startup(privateOmrPortLibrary) #define omrintrospect_shutdown() privateOmrPortLibrary->introspect_shutdown(privateOmrPortLibrary) diff --git a/include_core/omrporterror.h b/include_core/omrporterror.h index 82cf1fd64a2..4c664d78262 100644 --- a/include_core/omrporterror.h +++ b/include_core/omrporterror.h @@ -271,12 +271,11 @@ #define OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM (OMRPORT_ERROR_SYSINFO_BASE-17) #define OMRPORT_ERROR_SYSINFO_PROCESS_CGROUP_FILE_FOPEN_FAILED (OMRPORT_ERROR_SYSINFO_BASE-18) #define OMRPORT_ERROR_SYSINFO_PROCESS_CGROUP_FILE_READ_FAILED (OMRPORT_ERROR_SYSINFO_BASE-19) -#define OMRPORT_ERROR_SYSINFO_PROCESS_CGROUP_FILE_DUPLICATE_SUBSYSTEM_ENTRIES (OMRPORT_ERROR_SYSINFO_BASE-20) -#define OMRPORT_ERROR_SYSINFO_SYS_FS_CGROUP_STATFS_FAILED (OMRPORT_ERROR_SYSINFO_BASE-21) -#define OMRPORT_ERROR_SYSINFO_SYS_FS_CGROUP_TMPFS_NOT_MOUNTED (OMRPORT_ERROR_SYSINFO_BASE-22) -#define OMRPORT_ERROR_SYSINFO_CGROUP_LIMITS_DISABLED (OMRPORT_ERROR_SYSINFO_BASE-23) -#define OMRPORT_ERROR_SYSINFO_CGROUP_NAME_NOT_AVAILABLE (OMRPORT_ERROR_SYSINFO_BASE-24) -#define OMRPORT_ERROR_SYSINFO_CGROUP_MEMLIMIT_FILE_FOPEN_FAILED (OMRPORT_ERROR_SYSINFO_BASE-25) +#define OMRPORT_ERROR_SYSINFO_SYS_FS_CGROUP_STATFS_FAILED (OMRPORT_ERROR_SYSINFO_BASE-20) +#define OMRPORT_ERROR_SYSINFO_SYS_FS_CGROUP_TMPFS_NOT_MOUNTED (OMRPORT_ERROR_SYSINFO_BASE-21) +#define OMRPORT_ERROR_SYSINFO_CGROUP_SUBSYSTEM_UNAVAILABLE (OMRPORT_ERROR_SYSINFO_BASE-22) +#define OMRPORT_ERROR_SYSINFO_CGROUP_NAME_NOT_AVAILABLE (OMRPORT_ERROR_SYSINFO_BASE-23) +#define OMRPORT_ERROR_SYSINFO_CGROUP_MEMLIMIT_FILE_FOPEN_FAILED (OMRPORT_ERROR_SYSINFO_BASE-24) /** * @name Port library initialization return codes diff --git a/port/common/omrport.c b/port/common/omrport.c index b5f5657501e..64f5fcc2f74 100644 --- a/port/common/omrport.c +++ b/port/common/omrport.c @@ -251,9 +251,12 @@ static OMRPortLibrary MasterPortLibraryTable = { omrsysinfo_get_os_description, /* sysinfo_get_os_description */ omrsysinfo_os_has_feature, /* sysinfo_os_has_feature */ omrsysinfo_os_kernel_info, /* sysinfo_os_kernel_info */ - omrsysinfo_cgroup_is_limits_supported, /* sysinfo_cgroup_is_limits_supported */ - omrsysinfo_cgroup_is_limits_enabled, /* sysinfo_cgroup_is_limits_enabled */ - omrsysinfo_cgroup_enable_limits, /* sysinfo_cgroup_enable_limits */ + omrsysinfo_cgroup_is_system_available, /* sysinfo_cgroup_is_system_available */ + omrsysinfo_cgroup_get_available_subsystems, /* sysinfo_cgroup_get_available_subsystems */ + omrsysinfo_cgroup_are_subsystems_available, /* sysinfo_cgroup_are_subsystems_available */ + omrsysinfo_cgroup_get_enabled_subsystems, /* sysinfo_cgroup_get_enabled_subsystems */ + omrsysinfo_cgroup_enable_subsystems, /* sysinfo_cgroup_enable_subsystems */ + omrsysinfo_cgroup_are_subsystems_enabled, /* sysinfo_cgroup_are_subsystems_enabled */ omrsysinfo_cgroup_get_memlimit, /* sysinfo_cgroup_get_memlimit */ omrport_init_library, /* port_init_library */ omrport_startup_library, /* port_startup_library */ diff --git a/port/common/omrsysinfo.c b/port/common/omrsysinfo.c index a7335e4c5f3..aa4cbd516ea 100644 --- a/port/common/omrsysinfo.c +++ b/port/common/omrsysinfo.c @@ -808,42 +808,88 @@ omrsysinfo_os_kernel_info(struct OMRPortLibrary *portLibrary, struct OMROSKernel } /** - * Checks if the port library can use cgroup limits + * Checks if the platform supports cgroup system and the port library can use it * * @param[in] portLibrary pointer to OMRPortLibrary * - * @return 0 if the port library can use cgroup limits, otherwise negative error code + * @return TRUE if the the cgroup system is available, otherwise FALSE */ -int32_t -omrsysinfo_cgroup_is_limits_supported(struct OMRPortLibrary *portLibrary) +BOOLEAN +omrsysinfo_cgroup_is_system_available(struct OMRPortLibrary *portLibrary) { - return OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM; + return FALSE; } /** - * Returns TRUE if port library is using cgroup limits, FALSE otherwise + * Returns cgroup subsystems available for port library to use * * @param[in] portLibrary pointer to OMRPortLibrary * - * @return TRUE if port library has been enabled to use cgroup limits, FALSE otherwise + * @return bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* indicating the + * subsystems that are available */ -BOOLEAN -omrsysinfo_cgroup_is_limits_enabled(struct OMRPortLibrary *portLibrary) +uint64_t +omrsysinfo_cgroup_get_available_subsystems(struct OMRPortLibrary *portLibrary) +{ + return 0; +} + +/** + * Checks if the specified cgroup subsystems are available for port library to use. + * + * @param[in] portLibrary pointer to OMRPortLibrary + * @param[in] subsystemFlags bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* + * + * @return bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* indicating the + * subsystems that are available + */ +uint64_t +omrsysinfo_cgroup_are_subsystems_available(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlags) { return FALSE; } /** - * Enable port library to use cgroup limits + * Returns cgroup subsystems enabled for port library to use * - * @param[in] portLibrary pointer to OMRPortLibrary + * @param[in] portLibrary pointer to OMRPortLibrary * - * @return 0 if the port library can use cgroup limits, otherwise negative error code + * @return bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* indicating the + * subsystems that are enbaled */ -int32_t -omrsysinfo_cgroup_enable_limits(struct OMRPortLibrary *portLibrary) +uint64_t +omrsysinfo_cgroup_get_enabled_subsystems(struct OMRPortLibrary *portLibrary) { - return OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM; + return 0; +} + +/** + * Enable port library to use specified cgroup subsystems + * + * @param[in] portLibrary pointer to OMRPortLibrary + * @param[in] subsystems bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* + * indicating the subsystems to be enabled + * + * @return bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* indicating the subsystems that are enabled + */ +uint64_t +omrsysinfo_cgroup_enable_subsystems(struct OMRPortLibrary *portLibrary, uint64_t requestedSubsystems) +{ + return 0; +} + +/** + * Check which subsystems are enabled in port library + * + * @param[in] portLibrary pointer to OMRPortLibrary + * @param[in] subsystemsFlags bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* + * + * @return bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* indicating the subsystems that are enabled + */ +uint64_t +omrsysinfo_cgroup_are_subsystems_enabled(struct OMRPortLibrary *portLibrary, uint64_t subsystemsFlags) +{ + return 0; } /** diff --git a/port/omrportpriv.h b/port/omrportpriv.h index b21d371f9cd..42ea143a773 100644 --- a/port/omrportpriv.h +++ b/port/omrportpriv.h @@ -511,12 +511,18 @@ extern J9_CFUNC BOOLEAN omrsysinfo_os_has_feature(struct OMRPortLibrary *portLibrary, struct OMROSDesc *desc, uint32_t feature); extern J9_CFUNC BOOLEAN omrsysinfo_os_kernel_info(struct OMRPortLibrary *portLibrary, struct OMROSKernelInfo *kernelInfo); -extern J9_CFUNC int32_t -omrsysinfo_cgroup_is_limits_supported(struct OMRPortLibrary *portLibrary); extern J9_CFUNC BOOLEAN -omrsysinfo_cgroup_is_limits_enabled(struct OMRPortLibrary *portLibrary); -extern J9_CFUNC int32_t -omrsysinfo_cgroup_enable_limits(struct OMRPortLibrary *portLibrary); +omrsysinfo_cgroup_is_system_available(struct OMRPortLibrary *portLibrary); +extern J9_CFUNC uint64_t +omrsysinfo_cgroup_get_available_subsystems(struct OMRPortLibrary *portLibrary); +extern J9_CFUNC uint64_t +omrsysinfo_cgroup_are_subsystems_available(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlags); +extern J9_CFUNC uint64_t +omrsysinfo_cgroup_get_enabled_subsystems(struct OMRPortLibrary *portLibrary); +extern J9_CFUNC uint64_t +omrsysinfo_cgroup_enable_subsystems(struct OMRPortLibrary *portLibrary, uint64_t requestedSubsystems); +extern J9_CFUNC uint64_t +omrsysinfo_cgroup_are_subsystems_enabled(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlags); extern J9_CFUNC int32_t omrsysinfo_cgroup_get_memlimit(struct OMRPortLibrary *portLibrary, uint64_t *limit); diff --git a/port/unix/omrsysinfo.c b/port/unix/omrsysinfo.c index 5697f652bda..d8bf9f542cc 100644 --- a/port/unix/omrsysinfo.c +++ b/port/unix/omrsysinfo.c @@ -256,7 +256,8 @@ struct { /* Currently 12 subsystems/resource controllers are defined. */ -typedef enum OMRCgroupSubsystems { +typedef enum OMRCgroupSubsystem { + INVALID_SUBSYSTEM = -1, BLKIO, CPU, CPUACCT, @@ -270,7 +271,7 @@ typedef enum OMRCgroupSubsystems { PERF_EVENT, PIDS, NUM_SUBSYSTEMS -} OMRCgroupSubsystems; +} OMRCgroupSubsystem; const char *subsystemNames[NUM_SUBSYSTEMS] = { "blkio", @@ -286,6 +287,18 @@ const char *subsystemNames[NUM_SUBSYSTEMS] = { "perf_event", "pids", }; + +struct { + const char *name; + uint64_t flag; +} supportedSubsystems[] = { + { "cpu", OMR_CGROUP_SUBSYSTEM_CPU }, + { "memory", OMR_CGROUP_SUBSYSTEM_MEMORY } +}; + +static uint32_t attachedPortLibraries; +static omrthread_monitor_t cgroupEntryListMonitor; + #endif /* defined(LINUX) */ static intptr_t cwdname(struct OMRPortLibrary *portLibrary, char **result); @@ -317,8 +330,9 @@ static uint16_t getPhysicalMemory(); static void freeCgroupEntries(struct OMRPortLibrary *portLibrary, OMRCgroupEntry *cgEntryList); static char * getCgroupNameForSubsystem(struct OMRPortLibrary *portLibrary, OMRCgroupEntry *cgEntryList, const char *subsystem); static int32_t addCgroupEntry(struct OMRPortLibrary *portLibrary, OMRCgroupEntry **cgEntryList, int32_t hierId, const char *subsystem, const char *cgroupName); -static int32_t readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgroupEntryList); -static int32_t readCgroupSubsystemFile(struct OMRPortLibrary *portLibrary, OMRCgroupSubsystems subsystem, const char *fileName, int32_t numItemsToRead, const char *format, ...); +static int32_t readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgroupEntryList, uint64_t *availableSubsystems); +static OMRCgroupSubsystem getCgroupSubsystemFromFlag(uint64_t subsystemFlag); +static int32_t readCgroupSubsystemFile(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlag, const char *fileName, int32_t numItemsToRead, const char *format, ...); #endif /* defined(LINUX) */ @@ -1530,14 +1544,15 @@ omrsysinfo_get_physical_memory(struct OMRPortLibrary *portLibrary) { uint64_t result = 0; - if (portLibrary->sysinfo_cgroup_is_limits_enabled(portLibrary)) { - int rc = 0; +#if defined(LINUX) + if (portLibrary->sysinfo_cgroup_are_subsystems_enabled(portLibrary, OMR_CGROUP_SUBSYSTEM_MEMORY)) { + int32_t rc = portLibrary->sysinfo_cgroup_get_memlimit(portLibrary, &result); - rc = portLibrary->sysinfo_cgroup_get_memlimit(portLibrary, &result); if (0 == rc) { return result; } } +#endif /* defined(LINUX) */ #if defined (RS6000) /* physmem is not a field in the system_configuration struct */ @@ -1639,8 +1654,15 @@ omrsysinfo_shutdown(struct OMRPortLibrary *portLibrary) PPG_si_executableName = NULL; } #if defined(LINUX) && !defined(OMRZTPF) + omrthread_monitor_enter(cgroupEntryListMonitor); freeCgroupEntries(portLibrary, PPG_cgroupEntryList); PPG_cgroupEntryList = NULL; + omrthread_monitor_exit(cgroupEntryListMonitor); + attachedPortLibraries -= 1; + if (0 == attachedPortLibraries) { + omrthread_monitor_destroy(cgroupEntryListMonitor); + cgroupEntryListMonitor = NULL; + } #endif /* defined(LINUX) */ } } @@ -1657,6 +1679,17 @@ omrsysinfo_startup(struct OMRPortLibrary *portLibrary) #if defined(LINUX) && !defined(OMRZTPF) PPG_cgroupEntryList = NULL; + /* To handle the case where multiple port libraries are started and shutdown, + * as done by some fvtests (eg fvtest/porttest/j9portTest.cpp) that create fake portlibrary + * to test its management and lifecycle, + * we need to ensure globals like cgroupEntryListMonitor are initialized and destroyed only once. + */ + if (0 == attachedPortLibraries) { + if (omrthread_monitor_init_with_name(&cgroupEntryListMonitor, 0, "cgroup entry list monitor")) { + return -1; + } + } + attachedPortLibraries += 1; #endif /* defined(LINUX) */ return 0; } @@ -3317,11 +3350,10 @@ getCgroupNameForSubsystem(struct OMRPortLibrary *portLibrary, OMRCgroupEntry *cg static int32_t addCgroupEntry(struct OMRPortLibrary *portLibrary, OMRCgroupEntry **cgEntryList, int32_t hierId, const char *subsystem, const char *cgroupName) { - OMRCgroupEntry *cgEntry = NULL; - int32_t cgEntrySize = sizeof(OMRCgroupEntry) + strlen(subsystem) + 1 + strlen(cgroupName) + 1; int32_t rc = 0; + int32_t cgEntrySize = sizeof(OMRCgroupEntry) + strlen(subsystem) + 1 + strlen(cgroupName) + 1; + OMRCgroupEntry *cgEntry = portLibrary->mem_allocate_memory(portLibrary, cgEntrySize, OMR_GET_CALLSITE(), OMRMEM_CATEGORY_PORT_LIBRARY); - cgEntry = portLibrary->mem_allocate_memory(portLibrary, cgEntrySize, OMR_GET_CALLSITE(), OMRMEM_CATEGORY_PORT_LIBRARY); if (NULL == cgEntry) { rc = portLibrary->error_set_last_error_with_message(portLibrary, OMRPORT_ERROR_SYSINFO_MEMORY_ALLOC_FAILED, "memory allocation for cgroup entry failed"); goto _end; @@ -3341,7 +3373,6 @@ addCgroupEntry(struct OMRPortLibrary *portLibrary, OMRCgroupEntry **cgEntryList, cgEntry->next = first->next; first->next = cgEntry; } - _end: return rc; } @@ -3354,12 +3385,14 @@ addCgroupEntry(struct OMRPortLibrary *portLibrary, OMRCgroupEntry **cgEntryList, * @param[in] pid process id * @param[out] cgroupEntryList pointer to OMRCgroupEntry *. On successful return, *cgroupEntry * points to a circular linked list. Each element of the list is populated based on the contents - * of /proc/<pid>/cgroup file. + * of /proc/<pid>/cgroup file. + * @param[out] availableSubsystems on successful return, contains bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* + * indicating the subsystems available for use * * returns 0 on success, negative code on error */ static int32_t -readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgroupEntryList) +readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgroupEntryList, uint64_t *availableSubsystems) { char cgroup[PATH_MAX]; uintptr_t requiredSize = 0; @@ -3367,6 +3400,7 @@ readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgr char subsystems[1024]; FILE *cgroupFile = NULL; OMRCgroupEntry *cgEntryList = NULL; + uint64_t available = 0; int32_t rc = 0; Assert_PRT_true(NULL != cgroupEntryList); @@ -3408,24 +3442,23 @@ readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgr } cursor = subsystems; do { - const char *cgName = NULL; + int32_t i = 0; separator = strchr(cursor, ','); if (NULL != separator) { *separator = '\0'; } - cgName = getCgroupNameForSubsystem(portLibrary, cgEntryList, cursor); - - if (NULL == cgName) { - rc = addCgroupEntry(portLibrary, &cgEntryList, hierId, cursor, cgroup); - if (0 != rc) { - goto _end; + for (i = 0; i < sizeof(supportedSubsystems) / sizeof(supportedSubsystems[0]); i++) { + if (OMR_ARE_NO_BITS_SET(available, supportedSubsystems[i].flag) + && !strcmp(cursor, supportedSubsystems[i].name) + ) { + rc = addCgroupEntry(portLibrary, &cgEntryList, hierId, cursor, cgroup); + if (0 != rc) { + goto _end; + } + available |= supportedSubsystems[i].flag; } - } else { - rc = portLibrary->error_set_last_error_with_message_format(portLibrary, OMRPORT_ERROR_SYSINFO_PROCESS_CGROUP_FILE_DUPLICATE_SUBSYSTEM_ENTRIES, "multiple entries for subsystem %s found in process cgroup file", cursor); - goto _end; - } if (NULL != separator) { cursor = separator + 1; @@ -3443,16 +3476,42 @@ readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgr cgEntryList = NULL; } else { *cgroupEntryList = cgEntryList; + if (NULL != availableSubsystems) { + *availableSubsystems = available; + } } return rc; } +/** + * Given a subsystem flag, returns enum for that subsystem + * + * @param[in] portLibrary pointer to OMRPortLibrary + * @param[in] subsystemFlag flag of type OMR_CGROUP_SUBSYSTEM_* + * + * @return value of type enum OMRCgroupSubsystem + */ +static OMRCgroupSubsystem +getCgroupSubsystemFromFlag(uint64_t subsystemFlag) +{ + switch(subsystemFlag) { + case OMR_CGROUP_SUBSYSTEM_CPU: + return CPU; + case OMR_CGROUP_SUBSYSTEM_MEMORY: + return MEMORY; + default: + Trc_PRT_Assert_ShouldNeverHappen(); + } + + return INVALID_SUBSYSTEM; +} + /** * Read a file under a subsystem in cgroup hierarchy based on the format specified * * @param[in] portLibrary pointer to OMRPortLibrary - * @param[in] subsystem cgroup subsystem + * @param[in] subsystemFlag flag bitwise-OR of flags of type OMR_CGROUP_SUBSYSTEMS_* representing the cgroup subsystem * @param[in] fileName name of the file under cgroup subsystem * @param[in] numItemsToRead number of items to be read from the file * @param[in] format format to be used for reading the file @@ -3460,7 +3519,7 @@ readCgroupFile(struct OMRPortLibrary *portLibrary, int pid, OMRCgroupEntry **cgr * @return 0 on successfully reading 'numItemsToRead' items from the file, negative error code on any error */ static int32_t -readCgroupSubsystemFile(struct OMRPortLibrary *portLibrary, OMRCgroupSubsystems subsystem, const char *fileName, int32_t numItemsToRead, const char *format, ...) +readCgroupSubsystemFile(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlag, const char *fileName, int32_t numItemsToRead, const char *format, ...) { char fileToRead[PATH_MAX]; char *fileNameBuf = fileToRead; @@ -3469,9 +3528,11 @@ readCgroupSubsystemFile(struct OMRPortLibrary *portLibrary, OMRCgroupSubsystems FILE *file = NULL; int32_t rc = 0; va_list args; + OMRCgroupSubsystem subsystem = getCgroupSubsystemFromFlag(subsystemFlag); + uint64_t availableSubsystem = portLibrary->sysinfo_cgroup_are_subsystems_available(portLibrary, subsystemFlag); - if (!portLibrary->sysinfo_cgroup_is_limits_enabled(portLibrary)) { - rc = portLibrary->error_set_last_error_with_message(portLibrary, OMRPORT_ERROR_SYSINFO_CGROUP_LIMITS_DISABLED, "cgroup limits is disabled"); + if (availableSubsystem != subsystemFlag) { + rc = portLibrary->error_set_last_error_with_message_format(portLibrary, OMRPORT_ERROR_SYSINFO_CGROUP_SUBSYSTEM_UNAVAILABLE, "cgroup subsystem %s is not available", subsystemNames[subsystem]); goto _end; } @@ -3521,14 +3582,16 @@ readCgroupSubsystemFile(struct OMRPortLibrary *portLibrary, OMRCgroupSubsystems #endif /* defined(LINUX) */ -int32_t -omrsysinfo_cgroup_is_limits_supported(struct OMRPortLibrary *portLibrary) +BOOLEAN +omrsysinfo_cgroup_is_system_available(struct OMRPortLibrary *portLibrary) { - int32_t rc = OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM; + BOOLEAN result = FALSE; #if defined(LINUX) && !defined(OMRZTPF) - struct statfs buf = {0}; + int32_t rc = OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM; if (NULL == PPG_cgroupEntryList) { + struct statfs buf = {0}; + /* If tmpfs is mounted on /sys/fs/cgroup, then it indicates cgroup v1 system is available */ rc = statfs(OMR_CGROUP_V1_MOUNT_POINT, &buf); if (0 != rc) { @@ -3539,38 +3602,81 @@ omrsysinfo_cgroup_is_limits_supported(struct OMRPortLibrary *portLibrary) goto _end; } - rc = readCgroupFile(portLibrary, getpid(), &PPG_cgroupEntryList); + omrthread_monitor_enter(cgroupEntryListMonitor); + if (NULL == PPG_cgroupEntryList) { + rc = readCgroupFile(portLibrary, getpid(), &PPG_cgroupEntryList, &PPG_cgroupSubsystemsAvailable); + } + omrthread_monitor_exit(cgroupEntryListMonitor); + if (0 != rc) { + goto _end; + } } else { rc = 0; } - _end: + if (0 == rc) { + result = TRUE; + } else { + PPG_cgroupSubsystemsAvailable = 0; + } #endif /* defined(LINUX) && !defined(OMRZTPF) */ - return rc; + return result; } -BOOLEAN -omrsysinfo_cgroup_is_limits_enabled(struct OMRPortLibrary *portLibrary) +uint64_t +omrsysinfo_cgroup_get_available_subsystems(struct OMRPortLibrary *portLibrary) { #if defined(LINUX) && !defined(OMRZTPF) - return PPG_cgroupLimitsEnabled; -#else /* defined(LINUX) && !defined(OMRZTPF) */ - return FALSE; -#endif /* defined(LINUX) */ + if (NULL == PPG_cgroupEntryList) { + portLibrary->sysinfo_cgroup_is_system_available(portLibrary); + } + return PPG_cgroupSubsystemsAvailable; +#else /* defined(LINUX) && !defined(OMRZTPF) */ + return 0; +#endif /* defined(LINUX) && !defined(OMRZTPF) */ } -int32_t -omrsysinfo_cgroup_enable_limits(struct OMRPortLibrary *portLibrary) +uint64_t +omrsysinfo_cgroup_are_subsystems_available(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlags) { - int32_t cgroupSupported = portLibrary->sysinfo_cgroup_is_limits_supported(portLibrary); #if defined(LINUX) && !defined(OMRZTPF) - if (0 == cgroupSupported) { - PPG_cgroupLimitsEnabled = TRUE; - } else { - PPG_cgroupLimitsEnabled = FALSE; - } -#endif /* defined(LINUX) && !defined(OMRZTPF) */ - return cgroupSupported; + uint64_t available = portLibrary->sysinfo_cgroup_get_available_subsystems(portLibrary); + return (available & subsystemFlags); +#else /* defined(LINUX) && !defined(OMRZTPF) */ + return 0; +#endif /* defined(LINUX) && !defined(OMRZTPF) */ +} + +uint64_t +omrsysinfo_cgroup_get_enabled_subsystems(struct OMRPortLibrary *portLibrary) +{ +#if defined(LINUX) && !defined(OMRZTPF) + return PPG_cgroupSubsystemsEnabled; +#else /* defined(LINUX) && !defined(OMRZTPF) */ + return 0; +#endif /* defined(LINUX) && !defined(OMRZTPF) */ +} + +uint64_t +omrsysinfo_cgroup_enable_subsystems(struct OMRPortLibrary *portLibrary, uint64_t requestedSubsystems) +{ +#if defined(LINUX) && !defined(OMRZTPF) + uint64_t available = portLibrary->sysinfo_cgroup_get_available_subsystems(portLibrary); + PPG_cgroupSubsystemsEnabled = available & requestedSubsystems; + return PPG_cgroupSubsystemsEnabled; +#else /* defined(LINUX) && !defined(OMRZTPF) */ + return 0; +#endif /* defined(LINUX) && !defined(OMRZTPF) */ +} + +uint64_t +omrsysinfo_cgroup_are_subsystems_enabled(struct OMRPortLibrary *portLibrary, uint64_t subsystemsFlags) +{ +#if defined(LINUX) && !defined(OMRZTPF) + return (PPG_cgroupSubsystemsEnabled & subsystemsFlags); +#else /* defined(LINUX) && !defined(OMRZTPF) */ + return 0; +#endif /* defined(LINUX) && !defined(OMRZTPF) */ } int32_t @@ -3584,7 +3690,7 @@ omrsysinfo_cgroup_get_memlimit(struct OMRPortLibrary *portLibrary, uint64_t *lim Assert_PRT_true(NULL != limit); - rc = readCgroupSubsystemFile(portLibrary, MEMORY, "memory.limit_in_bytes", numItemsToRead, "%lu", &cgroupMemLimit); + rc = readCgroupSubsystemFile(portLibrary, OMR_CGROUP_SUBSYSTEM_MEMORY, "memory.limit_in_bytes", numItemsToRead, "%lu", &cgroupMemLimit); if (0 != rc) { goto _end; diff --git a/port/unix_include/omrportpg.h b/port/unix_include/omrportpg.h index ff4a26f8e78..145e3634d06 100644 --- a/port/unix_include/omrportpg.h +++ b/port/unix_include/omrportpg.h @@ -79,7 +79,8 @@ typedef struct OMRPortPlatformGlobals { int32_t introspect_threadSuspendSignal; #endif /* defined(OMR_CONFIGURABLE_SUSPEND_SIGNAL) */ #if defined(LINUX) - BOOLEAN cgroupLimitsEnabled; /**< indicates if port library supports cgroup limits */ + uint64_t cgroupSubsystemsAvailable; /**< cgroup subsystems available for port library to use; it is valid only when cgroupEntryList is non-null */ + uint64_t cgroupSubsystemsEnabled; /**< cgroup subsystems enabled in port library; it is valid only when cgroupEntryList is non-null */ OMRCgroupEntry *cgroupEntryList; /**< head of the circular linked list, each element contains information about cgroup of the process for a subsystem */ #endif /* defined(LINUX) */ } OMRPortPlatformGlobals; @@ -120,7 +121,9 @@ typedef struct OMRPortPlatformGlobals { #endif #if defined(LINUX) -#define PPG_cgroupLimitsEnabled (portLibrary->portGlobals->platformGlobals.cgroupLimitsEnabled) +/* Note that PPG_cgroupSubsystemsAvailable and PPG_cgroupSubsystemsEnabled are valid only if PPG_cgroupEntryList is not NULL */ +#define PPG_cgroupSubsystemsAvailable (portLibrary->portGlobals->platformGlobals.cgroupSubsystemsAvailable) +#define PPG_cgroupSubsystemsEnabled (portLibrary->portGlobals->platformGlobals.cgroupSubsystemsEnabled) #define PPG_cgroupEntryList (portLibrary->portGlobals->platformGlobals.cgroupEntryList) #endif /* defined(LINUX) */ diff --git a/port/win32/omrsysinfo.c b/port/win32/omrsysinfo.c index 11d853689a9..ea812571365 100644 --- a/port/win32/omrsysinfo.c +++ b/port/win32/omrsysinfo.c @@ -1613,22 +1613,40 @@ omrsysinfo_os_kernel_info(struct OMRPortLibrary *portLibrary, struct OMROSKernel return FALSE; } -int32_t -omrsysinfo_cgroup_is_limits_supported(struct OMRPortLibrary *portLibrary) +BOOLEAN +omrsysinfo_cgroup_is_system_available(struct OMRPortLibrary *portLibrary) { - return OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM; + return FALSE; } -BOOLEAN -omrsysinfo_cgroup_is_limits_enabled(struct OMRPortLibrary *portLibrary) +uint64_t +omrsysinfo_cgroup_get_available_subsystems(struct OMRPortLibrary *portLibrary) { - return FALSE; + return 0; } -int32_t -omrsysinfo_cgroup_enable_limits(struct OMRPortLibrary *portLibrary) +uint64_t +omrsysinfo_cgroup_are_subsystems_available(struct OMRPortLibrary *portLibrary, uint64_t subsystemFlags) { - return OMRPORT_ERROR_SYSINFO_CGROUP_UNSUPPORTED_PLATFORM; + return 0; +} + +uint64_t +omrsysinfo_cgroup_get_enabled_subsystems(struct OMRPortLibrary *portLibrary) +{ + return 0; +} + +uint64_t +omrsysinfo_cgroup_enable_subsystems(struct OMRPortLibrary *portLibrary, uint64_t requestedSubsystems) +{ + return 0; +} + +uint64_t +omrsysinfo_cgroup_are_subsystems_enabled(struct OMRPortLibrary *portLibrary, uint64_t subsystemsFlags) +{ + return 0; } int32_t