diff --git a/src/gc/unix/cgroup.cpp b/src/gc/unix/cgroup.cpp index 589219064496..7cdea080c57e 100644 --- a/src/gc/unix/cgroup.cpp +++ b/src/gc/unix/cgroup.cpp @@ -21,73 +21,103 @@ Module Name: #include #include -#define MAX_PATH 1024 #define SIZE_T_MAX (~(size_t)0) #define PROC_MOUNTINFO_FILENAME "/proc/self/mountinfo" #define PROC_CGROUP_FILENAME "/proc/self/cgroup" #define PROC_STATM_FILENAME "/proc/self/statm" #define MEM_LIMIT_FILENAME "/memory.limit_in_bytes" -#define _countof(_array) (sizeof(_array)/sizeof(_array[0])) class CGroup { - char m_memory_cgroup_path[MAX_PATH]; + char* m_memory_cgroup_path; public: CGroup() { - if (!FindMemoryHierarchyMount(m_memory_cgroup_path, MAX_PATH)) - { - m_memory_cgroup_path[0] = '\0'; - return; - } - char cgroup_path_relative_to_mount[MAX_PATH]; - if (!FindCGroupPathForMemorySubsystem(cgroup_path_relative_to_mount, MAX_PATH)) - { - m_memory_cgroup_path[0] = '\0'; - return; - } - strncat(m_memory_cgroup_path, cgroup_path_relative_to_mount, - MAX_PATH-strlen(m_memory_cgroup_path)-1); + m_memory_cgroup_path = nullptr; + char* memoryHierarchyMount = nullptr; + char *cgroup_path_relative_to_mount = nullptr; + size_t len; + memoryHierarchyMount = FindMemoryHierarchyMount(); + if (memoryHierarchyMount == nullptr) + goto done; + + cgroup_path_relative_to_mount = FindCGroupPathForMemorySubsystem(); + if (cgroup_path_relative_to_mount == nullptr) + goto done; + + len = strlen(memoryHierarchyMount); + len += strlen(cgroup_path_relative_to_mount); + m_memory_cgroup_path = (char*)malloc(len+1); + if (m_memory_cgroup_path == nullptr) + goto done; + + strcpy(m_memory_cgroup_path, memoryHierarchyMount); + strcat(m_memory_cgroup_path, cgroup_path_relative_to_mount); + + done: + free(memoryHierarchyMount); + free(cgroup_path_relative_to_mount); } - + + ~CGroup() + { + free(m_memory_cgroup_path); + } + bool GetPhysicalMemoryLimit(size_t *val) { - char mem_limit_filename[MAX_PATH]; - - if (m_memory_cgroup_path[0] == 0) - return false; - + char *mem_limit_filename = nullptr; + bool result = false; + + if (m_memory_cgroup_path == nullptr) + return result; + + size_t len = strlen(m_memory_cgroup_path); + len += strlen(MEM_LIMIT_FILENAME); + mem_limit_filename = (char*)malloc(len+1); + if (mem_limit_filename == nullptr) + return result; + strcpy(mem_limit_filename, m_memory_cgroup_path); - strncat(mem_limit_filename, MEM_LIMIT_FILENAME, - MAX_PATH-strlen(mem_limit_filename)-1); - return ReadMemoryValueFromFile(mem_limit_filename, val); + strcat(mem_limit_filename, MEM_LIMIT_FILENAME); + result = ReadMemoryValueFromFile(mem_limit_filename, val); + free(mem_limit_filename); + return result; } private: - bool FindMemoryHierarchyMount(char* mountpath, size_t mountpathsize) + char* FindMemoryHierarchyMount() { - bool retval = false; char *line = nullptr; - size_t lineLen = 0; + size_t lineLen = 0, maxLineLen = 0; + char *filesystemType = nullptr; + char *options = nullptr; + char* mountpath = nullptr; + FILE *mountinfofile = fopen(PROC_MOUNTINFO_FILENAME, "r"); if (mountinfofile == NULL) goto done; - while (!retval && getline(&line, &lineLen, mountinfofile) != -1) + while (getline(&line, &lineLen, mountinfofile) != -1) { - char filesystemType[100]; - char options[MAX_PATH]; - char format[50]; - + if (filesystemType == nullptr || lineLen > maxLineLen) + { + free(filesystemType); + free(options); + filesystemType = (char*)malloc(lineLen+1); + if (filesystemType == nullptr) + goto done; + options = (char*)malloc(lineLen+1); + if (options == nullptr) + goto done; + maxLineLen = lineLen; + } + char* separatorChar = strchr(line, '-'); - sprintf(format, "- %%%lus %%*s %%%lus", - _countof(filesystemType)-1, - _countof(options)-1); - // See man page of proc to get format for /proc/self/mountinfo file int sscanfRet = sscanf(separatorChar, - format, + "- %s %*s %s", filesystemType, options); if (sscanfRet != 2) @@ -104,54 +134,66 @@ class CGroup { if (strncmp("memory", strTok, 6) == 0) { - sprintf(format, "%%*d %%*d %%*s %%*s %%%lus ", - mountpathsize-1); + mountpath = (char*)malloc(lineLen+1); + if (mountpath == nullptr) + goto done; sscanfRet = sscanf(line, - format, + "%*d %*d %*s %*s %s ", mountpath); if (sscanfRet != 1) { + free(mountpath); + mountpath = nullptr; assert(!"Failed to parse mount info file contents with sscanf."); - goto done; } - retval = true; - break; + goto done; } strTok = strtok_r(NULL, ",", &context); } } } done: + free(filesystemType); + free(options); if (line) free(line); if (mountinfofile) fclose(mountinfofile); - return retval; + return mountpath; } - bool FindCGroupPathForMemorySubsystem(char* cgrouppath, size_t cgrouppathsize) + char* FindCGroupPathForMemorySubsystem() { - bool retval = false; char *line = nullptr; size_t lineLen = 0; + size_t maxLineLen = 0; + char *subsystem_list = nullptr; + char *cgroup_path = nullptr; + bool result = false; + FILE *cgroupfile = fopen(PROC_CGROUP_FILENAME, "r"); if (cgroupfile == NULL) goto done; - while (!retval && getline(&line, &lineLen, cgroupfile) != -1) + while (!result && getline(&line, &lineLen, cgroupfile) != -1) { - char subsystem_list[100]; - char cgroup_path[MAX_PATH]; - char format[50]; - - sprintf(format, "%%*[^:]:%%%lu[^:]:%%%lus", - _countof(subsystem_list)-1, - _countof(cgroup_path)-1); + if (subsystem_list == nullptr || lineLen > maxLineLen) + { + free(subsystem_list); + free(cgroup_path); + subsystem_list = (char*)malloc(lineLen+1); + if (subsystem_list == nullptr) + goto done; + cgroup_path = (char*)malloc(lineLen+1); + if (cgroup_path == nullptr) + goto done; + maxLineLen = lineLen; + } // See man page of proc to get format for /proc/self/cgroup file int sscanfRet = sscanf(line, - format, + "%*[^:]:%[^:]:%s", subsystem_list, cgroup_path); if (sscanfRet != 2) @@ -166,19 +208,24 @@ class CGroup { if (strncmp("memory", strTok, 6) == 0) { - strcpy(cgrouppath, cgroup_path); - retval = true; + result = true; break; } strTok = strtok_r(NULL, ",", &context); } } done: + free(subsystem_list); + if (!result) + { + free(cgroup_path); + cgroup_path = nullptr; + } if (line) free(line); if (cgroupfile) fclose(cgroupfile); - return retval; + return cgroup_path; } bool ReadMemoryValueFromFile(const char* filename, size_t* val) diff --git a/src/pal/src/misc/cgroup.cpp b/src/pal/src/misc/cgroup.cpp index 8414e6b304a1..c5385f152b9e 100644 --- a/src/pal/src/misc/cgroup.cpp +++ b/src/pal/src/misc/cgroup.cpp @@ -25,57 +25,94 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC); class CGroup { - char m_memory_cgroup_path[MAX_PATH]; + char *m_memory_cgroup_path; public: CGroup() { - if (!FindMemoryHierarchyMount(m_memory_cgroup_path, MAX_PATH)) - { - m_memory_cgroup_path[0] = '\0'; - return; - } - char cgroup_path_relative_to_mount[MAX_PATH]; - if (!FindCGroupPathForMemorySubsystem(cgroup_path_relative_to_mount, MAX_PATH)) - { - m_memory_cgroup_path[0] = '\0'; - return; - } - strcat_s(m_memory_cgroup_path, MAX_PATH, cgroup_path_relative_to_mount); + m_memory_cgroup_path = nullptr; + char* memoryHierarchyMount = nullptr; + char *cgroup_path_relative_to_mount = nullptr; + size_t len; + memoryHierarchyMount = FindMemoryHierarchyMount(); + if (memoryHierarchyMount == nullptr) + goto done; + + cgroup_path_relative_to_mount = FindCGroupPathForMemorySubsystem(); + if (cgroup_path_relative_to_mount == nullptr) + goto done; + + len = strlen(memoryHierarchyMount); + len += strlen(cgroup_path_relative_to_mount); + m_memory_cgroup_path = (char*)PAL_malloc(len+1); + if (m_memory_cgroup_path == nullptr) + goto done; + + strcpy_s(m_memory_cgroup_path, len+1, memoryHierarchyMount); + strcat_s(m_memory_cgroup_path, len+1, cgroup_path_relative_to_mount); + + done: + PAL_free(memoryHierarchyMount); + PAL_free(cgroup_path_relative_to_mount); + } + ~CGroup() + { + PAL_free(m_memory_cgroup_path); } bool GetPhysicalMemoryLimit(size_t *val) { - char mem_limit_filename[MAX_PATH]; + char *mem_limit_filename = nullptr; + bool result = false; - if (m_memory_cgroup_path[0] == 0) - return false; + if (m_memory_cgroup_path == nullptr) + return result; + + size_t len = strlen(m_memory_cgroup_path); + len += strlen(MEM_LIMIT_FILENAME); + mem_limit_filename = (char*)PAL_malloc(len+1); + if (mem_limit_filename == nullptr) + return result; - strcpy_s(mem_limit_filename, MAX_PATH, m_memory_cgroup_path); - strcat_s(mem_limit_filename, MAX_PATH, MEM_LIMIT_FILENAME); - return ReadMemoryValueFromFile(mem_limit_filename, val); + strcpy_s(mem_limit_filename, len+1, m_memory_cgroup_path); + strcat_s(mem_limit_filename, len+1, MEM_LIMIT_FILENAME); + result = ReadMemoryValueFromFile(mem_limit_filename, val); + PAL_free(mem_limit_filename); + return result; } private: - bool FindMemoryHierarchyMount(char* mountpath, size_t mountpathsize) + char* FindMemoryHierarchyMount() { - bool retval = false; char *line = nullptr; - size_t lineLen = 0; + size_t lineLen = 0, maxLineLen = 0; + char *filesystemType = nullptr; + char *options = nullptr; + char* mountpath = nullptr; + FILE *mountinfofile = fopen(PROC_MOUNTINFO_FILENAME, "r"); if (mountinfofile == NULL) goto done; - while (!retval && getline(&line, &lineLen, mountinfofile) != -1) + while (getline(&line, &lineLen, mountinfofile) != -1) { - char filesystemType[100]; - char options[MAX_PATH]; - + if (filesystemType == nullptr || lineLen > maxLineLen) + { + PAL_free(filesystemType); + PAL_free(options); + filesystemType = (char*)PAL_malloc(lineLen+1); + if (filesystemType == nullptr) + goto done; + options = (char*)PAL_malloc(lineLen+1); + if (options == nullptr) + goto done; + maxLineLen = lineLen; + } char* separatorChar = strchr(line, '-'); // See man page of proc to get format for /proc/self/mountinfo file int sscanfRet = sscanf_s(separatorChar, "- %s %*s %s", - filesystemType, (unsigned)_countof(filesystemType), - options, (unsigned)_countof(options)); + filesystemType, lineLen+1, + options, lineLen+1); if (sscanfRet != 2) { _ASSERTE(!"Failed to parse mount info file contents with sscanf_s."); @@ -90,48 +127,68 @@ class CGroup { if (strncmp("memory", strTok, 6) == 0) { + mountpath = (char*)PAL_malloc(lineLen+1); + if (mountpath == nullptr) + goto done; + sscanfRet = sscanf_s(line, "%*d %*d %*s %*s %s ", - mountpath, mountpathsize); + mountpath, lineLen+1); if (sscanfRet != 1) { + PAL_free(mountpath); + mountpath = nullptr; _ASSERTE(!"Failed to parse mount info file contents with sscanf_s."); - goto done; } - retval = true; - break; + goto done; } strTok = strtok_s(NULL, ",", &context); } } } done: + PAL_free(filesystemType); + PAL_free(options); if (line) free(line); if (mountinfofile) fclose(mountinfofile); - return retval; + return mountpath; } - bool FindCGroupPathForMemorySubsystem(char* cgrouppath, size_t cgrouppathsize) + char* FindCGroupPathForMemorySubsystem() { - bool retval = false; char *line = nullptr; size_t lineLen = 0; + size_t maxLineLen = 0; + char *subsystem_list = nullptr; + char *cgroup_path = nullptr; + bool result = false; + FILE *cgroupfile = fopen(PROC_CGROUP_FILENAME, "r"); if (cgroupfile == NULL) goto done; - while (!retval && getline(&line, &lineLen, cgroupfile) != -1) + while (!result && getline(&line, &lineLen, cgroupfile) != -1) { - char subsystem_list[100]; - char cgroup_path[MAX_PATH]; + if (subsystem_list == nullptr || lineLen > maxLineLen) + { + PAL_free(subsystem_list); + PAL_free(cgroup_path); + subsystem_list = (char*)PAL_malloc(lineLen+1); + if (subsystem_list == nullptr) + goto done; + cgroup_path = (char*)PAL_malloc(lineLen+1); + if (cgroup_path == nullptr) + goto done; + maxLineLen = lineLen; + } // See man page of proc to get format for /proc/self/cgroup file int sscanfRet = sscanf_s(line, "%*[^:]:%[^:]:%s", - subsystem_list, (unsigned)_countof(subsystem_list), - cgroup_path, (unsigned)_countof(cgroup_path)); + subsystem_list, lineLen+1, + cgroup_path, lineLen+1); if (sscanfRet != 2) { _ASSERTE(!"Failed to parse cgroup info file contents with sscanf_s."); @@ -144,19 +201,24 @@ class CGroup { if (strncmp("memory", strTok, 6) == 0) { - strcpy_s(cgrouppath, cgrouppathsize, cgroup_path); - retval = true; + result = true; break; } strTok = strtok_s(NULL, ",", &context); } } done: + PAL_free(subsystem_list); + if (!result) + { + PAL_free(cgroup_path); + cgroup_path = nullptr; + } if (line) free(line); if (cgroupfile) fclose(cgroupfile); - return retval; + return cgroup_path; } bool ReadMemoryValueFromFile(const char* filename, size_t* val) @@ -257,7 +319,7 @@ PAL_GetWorkingSetSize(size_t* val) if (file != NULL && getline(&line, &linelen, file) != -1) { int x = sscanf_s(line, "%*s %llu %*s %*s %*s %*s %*s", val); - if(x==1) + if(x == 1) { *val = *val * VIRTUAL_PAGE_SIZE; result = true; diff --git a/src/pal/tests/palsuite/miscellaneous/CGroup/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/CGroup/test1/test.cpp index 26d54f77b35d..44b970a233e8 100644 --- a/src/pal/tests/palsuite/miscellaneous/CGroup/test1/test.cpp +++ b/src/pal/tests/palsuite/miscellaneous/CGroup/test1/test.cpp @@ -12,19 +12,20 @@ ** Steps to run this test on ubuntu: ** 1. sudo apt-get install cgroup-bin ** 2. sudo vi /etc/default/grub -** Add cgroup_enable=memory to GRUB_CMDLINE_LINUX_DEFAULT +** Add cgroup_enable=memory swapaccount=1 to GRUB_CMDLINE_LINUX_DEFAULT ** 3. sudo update-grub ** 4. reboot -** 5. sudo cgcreate -g cpu,memory:/mygroup -a : -t : +** 5. sudo cgcreate -g cpu,memory:/myGroup -a : -t : ** 6. echo 4M > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes -** 7. cgexe -g memory:/mygroup --sticky +** 7. echo 4M > /sys/fs/cgroup/memory/mygroup/memory.memsw.limit_in_bytes +** 8. cgexe -g memory:/mygroup --sticky **=========================================================*/ #include int __cdecl main(int argc,char *argv[]) { - + /* * Initialize the PAL and return FAILURE if this fails */