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