Skip to content

Commit bb103d7

Browse files
committed
8298730: Refactor subsystem_file_line_contents and add docs and tests
Reviewed-by: phh Backport-of: 500c3c17379fe0a62d42ba31bdcdb584b1823f60
1 parent c98e598 commit bb103d7

File tree

7 files changed

+278
-61
lines changed

7 files changed

+278
-61
lines changed

src/hotspot/os/linux/cgroupSubsystem_linux.hpp

Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -78,71 +78,83 @@ class CgroupController: public CHeapObj<mtInternal> {
7878

7979
PRAGMA_DIAG_PUSH
8080
PRAGMA_FORMAT_NONLITERAL_IGNORED
81+
// Parses a subsystem's file, looking for a matching line.
82+
// If key is null, then the first line will be matched with scan_fmt.
83+
// If key isn't null, then each line will be matched, looking for something that matches "$key $scan_fmt".
84+
// The matching value will be assigned to returnval.
85+
// scan_fmt uses scanf() syntax.
86+
// Return value: 0 on match, OSCONTAINER_ERROR on error.
8187
template <typename T> int subsystem_file_line_contents(CgroupController* c,
8288
const char *filename,
83-
const char *matchline,
89+
const char *key,
8490
const char *scan_fmt,
8591
T returnval) {
86-
FILE *fp = NULL;
87-
char *p;
88-
char file[MAXPATHLEN+1];
89-
char buf[MAXPATHLEN+1];
90-
char discard[MAXPATHLEN+1];
91-
bool found_match = false;
92+
if (c == nullptr) {
93+
log_debug(os, container)("subsystem_file_line_contents: CgroupController* is nullptr");
94+
return OSCONTAINER_ERROR;
95+
}
96+
if (c->subsystem_path() == nullptr) {
97+
log_debug(os, container)("subsystem_file_line_contents: subsystem path is nullptr");
98+
return OSCONTAINER_ERROR;
99+
}
100+
101+
stringStream file_path;
102+
file_path.print_raw(c->subsystem_path());
103+
file_path.print_raw(filename);
92104

93-
if (c == NULL) {
94-
log_debug(os, container)("subsystem_file_line_contents: CgroupController* is NULL");
105+
if (file_path.size() > (MAXPATHLEN-1)) {
106+
log_debug(os, container)("File path too long %s, %s", file_path.base(), filename);
95107
return OSCONTAINER_ERROR;
96108
}
97-
if (c->subsystem_path() == NULL) {
98-
log_debug(os, container)("subsystem_file_line_contents: subsystem path is NULL");
109+
const char* absolute_path = file_path.freeze();
110+
log_trace(os, container)("Path to %s is %s", filename, absolute_path);
111+
112+
FILE* fp = fopen(absolute_path, "r");
113+
if (fp == nullptr) {
114+
log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno));
99115
return OSCONTAINER_ERROR;
100116
}
101117

102-
strncpy(file, c->subsystem_path(), MAXPATHLEN);
103-
file[MAXPATHLEN-1] = '\0';
104-
int filelen = strlen(file);
105-
if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) {
106-
log_debug(os, container)("File path too long %s, %s", file, filename);
118+
const int buf_len = MAXPATHLEN+1;
119+
char buf[buf_len];
120+
char* line = fgets(buf, buf_len, fp);
121+
if (line == nullptr) {
122+
log_debug(os, container)("Empty file %s", absolute_path);
123+
fclose(fp);
107124
return OSCONTAINER_ERROR;
108125
}
109-
strncat(file, filename, MAXPATHLEN-filelen);
110-
log_trace(os, container)("Path to %s is %s", filename, file);
111-
fp = fopen(file, "r");
112-
if (fp != NULL) {
113-
int err = 0;
114-
while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) {
115-
found_match = false;
116-
if (matchline == NULL) {
117-
// single-line file case
118-
int matched = sscanf(p, scan_fmt, returnval);
119-
found_match = (matched == 1);
120-
} else {
121-
// multi-line file case
122-
if (strstr(p, matchline) != NULL) {
123-
// discard matchline string prefix
124-
int matched = sscanf(p, scan_fmt, discard, returnval);
125-
found_match = (matched == 2);
126-
} else {
127-
continue; // substring not found
126+
127+
bool found_match = false;
128+
if (key == nullptr) {
129+
// File consists of a single line according to caller, with only a value
130+
int matched = sscanf(line, scan_fmt, returnval);
131+
found_match = matched == 1;
132+
} else {
133+
// File consists of multiple lines in a "key value"
134+
// fashion, we have to find the key.
135+
const int key_len = strlen(key);
136+
for (; line != nullptr; line = fgets(buf, buf_len, fp)) {
137+
char* key_substr = strstr(line, key);
138+
char after_key = line[key_len];
139+
if (key_substr == line
140+
&& isspace(after_key) != 0
141+
&& after_key != '\n') {
142+
// Skip key, skip space
143+
const char* value_substr = line + key_len + 1;
144+
int matched = sscanf(value_substr, scan_fmt, returnval);
145+
found_match = matched == 1;
146+
if (found_match) {
147+
break;
128148
}
129149
}
130-
if (found_match) {
131-
fclose(fp);
132-
return 0;
133-
} else {
134-
err = 1;
135-
log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
136-
}
137150
}
138-
if (err == 0) {
139-
log_debug(os, container)("Empty file %s", file);
140-
}
141-
} else {
142-
log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno));
143151
}
144-
if (fp != NULL)
145-
fclose(fp);
152+
fclose(fp);
153+
if (found_match) {
154+
return 0;
155+
}
156+
log_debug(os, container)("Type %s (key == %s) not found in file %s", scan_fmt,
157+
(key == nullptr ? "null" : key), absolute_path);
146158
return OSCONTAINER_ERROR;
147159
}
148160
PRAGMA_DIAG_POP

src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,8 @@ jlong CgroupV1Subsystem::read_memory_limit_in_bytes() {
9696
log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited");
9797
CgroupV1MemoryController* mem_controller = reinterpret_cast<CgroupV1MemoryController*>(_memory->controller());
9898
if (mem_controller->is_hierarchical()) {
99-
const char* matchline = "hierarchical_memory_limit";
100-
const char* format = "%s " JULONG_FORMAT;
101-
GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline,
102-
"Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit)
99+
GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", "hierarchical_memory_limit",
100+
"Hierarchical Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, hier_memlimit)
103101
if (hier_memlimit >= os::Linux::physical_memory()) {
104102
log_trace(os, container)("Hierarchical Memory Limit is: Unlimited");
105103
} else {
@@ -123,17 +121,16 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() {
123121
CgroupV1MemoryController* mem_controller = reinterpret_cast<CgroupV1MemoryController*>(_memory->controller());
124122
if (mem_controller->is_hierarchical()) {
125123
const char* matchline = "hierarchical_memsw_limit";
126-
const char* format = "%s " JULONG_FORMAT;
127124
GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline,
128-
"Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memswlimit)
125+
"Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, JULONG_FORMAT, hier_memswlimit)
129126
if (hier_memswlimit >= host_total_memsw) {
130127
log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
131128
} else {
132129
jlong swappiness = read_mem_swappiness();
133130
if (swappiness == 0) {
134131
const char* matchmemline = "hierarchical_memory_limit";
135132
GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchmemline,
136-
"Hierarchical Memory Limit is : " JULONG_FORMAT, format, hier_memlimit)
133+
"Hierarchical Memory Limit is : " JULONG_FORMAT, JULONG_FORMAT, hier_memlimit)
137134
log_trace(os, container)("Memory and Swap Limit has been reset to " JULONG_FORMAT " because swappiness is 0", hier_memlimit);
138135
return (jlong)hier_memlimit;
139136
}
@@ -286,7 +283,7 @@ int CgroupV1Subsystem::cpu_shares() {
286283

287284
char* CgroupV1Subsystem::pids_max_val() {
288285
GET_CONTAINER_INFO_CPTR(cptr, _pids, "/pids.max",
289-
"Maximum number of tasks is: %s", "%s %*d", pidsmax, 1024);
286+
"Maximum number of tasks is: %s", "%1023s", pidsmax, 1024);
290287
return os::strdup(pidsmax);
291288
}
292289

src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) {
224224

225225
char* CgroupV2Subsystem::pids_max_val() {
226226
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/pids.max",
227-
"Maximum number of tasks is: %s", "%1023s %*d", pidsmax, 1024);
227+
"Maximum number of tasks is: %s", "%1023s", pidsmax, 1024);
228228
return os::strdup(pidsmax);
229229
}
230230

src/hotspot/share/utilities/ostream.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ void stringStream::grow(size_t new_capacity) {
354354
}
355355

356356
void stringStream::write(const char* s, size_t len) {
357+
assert(_is_frozen == false, "Modification forbidden");
357358
assert(_capacity >= _written + 1, "Sanity");
358359
if (len == 0) {
359360
return;
@@ -393,6 +394,7 @@ void stringStream::zero_terminate() {
393394
}
394395

395396
void stringStream::reset() {
397+
assert(_is_frozen == false, "Modification forbidden");
396398
_written = 0; _precount = 0; _position = 0;
397399
_newlines = 0;
398400
zero_terminate();

src/hotspot/share/utilities/ostream.hpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "memory/allocation.hpp"
2929
#include "runtime/timer.hpp"
3030
#include "utilities/globalDefinitions.hpp"
31+
#include "utilities/macros.hpp"
3132

3233
DEBUG_ONLY(class ResourceMark;)
3334

@@ -191,6 +192,7 @@ class ttyUnlocker: StackObj {
191192
// for writing to strings; buffer will expand automatically.
192193
// Buffer will always be zero-terminated.
193194
class stringStream : public outputStream {
195+
DEBUG_ONLY(bool _is_frozen = false);
194196
char* _buffer;
195197
size_t _written; // Number of characters written, excluding termin. zero
196198
size_t _capacity;
@@ -215,9 +217,18 @@ class stringStream : public outputStream {
215217
// Return number of characters written into buffer, excluding terminating zero and
216218
// subject to truncation in static buffer mode.
217219
size_t size() const { return _written; }
220+
// Returns internal buffer containing the accumulated string.
221+
// Returned buffer is only guaranteed to be valid as long as stream is not modified
218222
const char* base() const { return _buffer; }
223+
// Freezes stringStream (no further modifications possible) and returns pointer to it.
224+
// No-op if stream is frozen already.
225+
// Returns the internal buffer containing the accumulated string.
226+
const char* freeze() NOT_DEBUG(const) {
227+
DEBUG_ONLY(_is_frozen = true);
228+
return _buffer;
229+
};
219230
void reset();
220-
// copy to a resource, or C-heap, array as requested
231+
// Copy to a resource, or C-heap, array as requested
221232
char* as_string(bool c_heap = false) const;
222233
};
223234

0 commit comments

Comments
 (0)