Skip to content

Conversation

@harship04
Copy link

@harship04 harship04 commented Mar 7, 2025

Use /proc filesystem to extract command line.
Use cmdline for user space processes and comm for others.

@babsingh
Copy link
Contributor

babsingh commented Mar 7, 2025

@keithc-ca could you please help in reviewing this PR?

Comment on lines 7574 to 7586
DIR *dir = opendir("/proc");
if (!dir) {
int32_t rc = findError(errno);
portLibrary->error_set_last_error(portLibrary, errno, rc);
Trc_PRT_sysinfo_get_open_file_count_failedOpeningProcFS(rc);
return -1;
}
struct dirent *entry;
char cmdline_path[PATH_MAX];
char comm_path[PATH_MAX];
char command[PATH_MAX];
size_t bytes_read;
while ((entry = readdir(dir)) != NULL) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not strictly legal C code: declarations must be at the beginning of a block.

Please first update this so the additions follow the coding standard. Some examples of things that don't follow those guidelines:

  • comparisons (== and != where the constant is not on the left
  • conditions with embedded assignments
  • uninitialized local variables (e.g. entry, bytes_read above)
  • code should be indented one tab per level (not 8 spaces)
  • missing comments on #else and #endif

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made the changes given by you and updated PR

@harship04 harship04 force-pushed the systemprocess-x64 branch 2 times, most recently from e45d7db to ea48042 Compare March 11, 2025 11:23
omrsysinfo_get_load_average, /* sysinfo_get_load_average */
omrsysinfo_get_CPU_utilization, /* sysinfo_get_CPU_utilization */
omrsysinfo_get_CPU_load, /* sysinfo_get_CPU_load */
omrsysinfo_get_processes, /*sysinfo_get_processes */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after /*.

uintptr_t
omrsysinfo_get_processes(struct OMRPortLibrary *portLibrary, OMRProcessInfoCallback callback, void *userData)
{
return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please indent with a tab instead of spaces.

Comment on lines 81 to 82
#include <ctype.h>
#include <stdint.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ctype.h is not needed (we can use just strtoull() without isdigit())
  • stdint.h is already included via inttypes.h

omrsysinfo_get_processes(struct OMRPortLibrary *portLibrary, OMRProcessInfoCallback callback, void *userData)
{
#if defined(LINUX)
DIR *dir = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest moving this declaration to the point of initialization (after line 7581):

	DIR *dir = opendir("/proc");

Comment on lines 7576 to 7577
char cmdline_path[PATH_MAX];
char comm_path[PATH_MAX];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest we only need one of these buffers at a time (write the first path, try to read that file and only write the second path if necessary).

portLibrary->file_close(portLibrary, file);
}
/* If cmdline is empty, try reading from comm */
if (0 == bytes_read) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must check for negative values:

		if (bytes_read <= 0) {

Likewise on line 7615.

command[i] = ' ';
}
}
/* Call the callback function with the process ID and command */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

command should be NUL-terminated here:

		command[bytes_read] = '\0';

}
}
/* Call the callback function with the process ID and command */
callback_result = callback((uintptr_t)strtoull(entry->d_name, NULL, 10), command, userData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use pid computed above:

		callback_result = callback(pid, command, userData);

@harship04 harship04 force-pushed the systemprocess-x64 branch 3 times, most recently from 8dcf87f to a947338 Compare March 14, 2025 14:37

TraceException=Trc_PRT_sysinfo_get_tmp_failed_str_covert Group=sysinfo Overhead=1 Level=1 NoEnv Template="omrsysinfo_get_tmp: omrstr_convert() failed to convert unicode to modified utf8 with error code=%d"

TraceException=Trc_PRT_sysinfo_get_processes_failedOpeningProcFS Group=sysinfo Overhead=1 Level=1 NoEnv Template="omrsysinfo_get_processes failed opening /proc = %d."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New tracepoints must be added to the end of the file; see https://github.com/eclipse-openj9/openj9/blob/master/doc/diagnostics/AddingTracepoints.md.

omrsysinfo_get_processes(struct OMRPortLibrary *portLibrary, OMRProcessInfoCallback callback, void *userData)
{
#if defined(LINUX)
struct dirent *entry = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locals should be declared in the smallest block possible; entry should be declared where it is initialized (on line 7588).
Only these need to be declared here:

	uintptr_t callback_result = 0;
	DIR *dir = opendir("/proc");

continue;
}
/* Convert name to pid, skipping non-numeric entries. */
char *end = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not strictly legal in C to declare a local here.

if (NULL == dir) {
int32_t rc = findError(errno);
portLibrary->error_set_last_error(portLibrary, errno, rc);
Trc_PRT_sysinfo_get_processes_failedOpeningProcFS(rc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No trailing spaces, please (here and line 7629).

portLibrary->str_printf(portLibrary, path, sizeof(path), "/proc/%s/cmdline", entry->d_name);
file = portLibrary->file_open(portLibrary, path, EsOpenRead, 0);
if (0 != file) {
bytes_read = portLibrary->file_read(portLibrary, file, command, sizeof(command) - 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may truncate commands which can be much longer than PATH_MAX (think megabytes).

@harship04 harship04 force-pushed the systemprocess-x64 branch 2 times, most recently from 62cef76 to 2626483 Compare March 14, 2025 20:17
Comment on lines 7572 to 7574
#define ARG_MAX 2097152
char path[PATH_MAX];
char command[ARG_MAX];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not impose a fixed limit on the size of a command line. Greater than 4MB is unreasonable for a single stack frame.

@keithc-ca
Copy link
Contributor

This should not make reference to JFR; yes, it might be one of the first consumers of this new API, but this project aims to be language neutral.

@harship04 harship04 force-pushed the systemprocess-x64 branch 3 times, most recently from 498f43a to 0d65739 Compare March 19, 2025 10:09
/* Try reading /proc/[pid]/cmdline. */
portLibrary->str_printf(portLibrary, path, sizeof(path), "/proc/%s/cmdline", entry->d_name);
file = portLibrary->file_open(portLibrary, path, EsOpenRead, 0);
if (0 != file) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test should be file >= 0 (a negative value signals failure, 0 is a valid file descriptor); same for line 7640.

Comment on lines 7613 to 7636
for (;;) {
bytes_read = portLibrary->file_read(portLibrary, file, command, buffer_size - 1);
if (bytes_read < 0) {
break;
}
if (bytes_read == buffer_size - 1) {
/* Buffer may be too small, increase and retry. */
new_size = buffer_size * 2;
new_command = (char *)portLibrary->mem_reallocate_memory(
portLibrary,
command,
new_size, OMR_GET_CALLSITE(), OMRMEM_CATEGORY_PORT_LIBRARY);
if (NULL == new_command) {
break; /* Stop resizing if allocation fails. */
}
command = new_command;
buffer_size = new_size;
continue;
}
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be extracted into a new function which can be reused on line 7641.
Note that the second and subsequent reads should not write to the beginning of command.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked kernel header file and The result shows that TASK_COMM_LEN is defined as 16 in the kernel header file

278:#define TASK_COMM_LEN 16
1050: char comm[TASK_COMM_LEN];
1941: BUILD_BUG_ON(sizeof(buf) != TASK_COMM_LEN);
comm is a fixed-size buffer of 16 characters, so it doesn’t need resizing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any value in making assumptions about the size of /proc/N/comm.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the reference I used: https://man7.org/linux/man-pages/man5/proc_pid_comm.5.html which specifies the command argument length as 16 characters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain why a function that can handle arbitrarily long cmdline should not also be used for comm.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have initialised buffer size of command in the beginning as 4096
cmdline argument length can be more than 4 KB so for that first I am trying to read command line and if the buffer is too small then I am resizing by doubling the buffer size until command line fits the buffer
but for comm argument fixed size is 16 characters so it doesn't need resizing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't suggesting it would need resizing. I am asking why it should be treated differently than reading cmdline, or equivalently, why should the code assume that comm is shorter?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /proc/[pid]/comm and /proc/[pid]/cmdline fields are treated differently because they serve distinct purposes. comm stores the process name with a fixed 16-character limit, while cmdline contains the full command-line arguments and can be much longer. first information is extracted from cmdline , but it is only available for user-space processes. If cmdline is unavailable, comm is used as a fallback to obtain the executable name.
if you have any other approach I would look into it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested that the code "should be extracted into a new function which can be reused". Doing so avoids making any assumption about the size of the string in comm.

return (uintptr_t)(intptr_t)rc;
}
/* Allocate initial buffer. */
char *command = (char *)portLibrary->mem_allocate_memory(portLibrary, buffer_size, OMR_GET_CALLSITE(), OMRMEM_CATEGORY_PORT_LIBRARY);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not legal C code; variables must be declared at the beginning of a block.

@keithc-ca
Copy link
Contributor

Please correct the spelling of "API" in the commit summary line and update the title here (also removing "jfr:").
Lines in the body of the commit message should be no more than 72 characters long.

@harship04 harship04 changed the title jfr: Add an api for system processes Add an API for system processes Mar 20, 2025
@harship04 harship04 force-pushed the systemprocess-x64 branch from ff79304 to 978eec4 Compare April 1, 2025 09:39
intptr_t bytes_read = 0;
char *new_data = NULL;
for (;;) {
bytes_read = portLibrary->file_read(portLibrary, file, *data + total_bytes_read, buffer_size - 1 - total_bytes_read);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bytes_read should be declared here, the length argument should not include - 1 and the line should be split:

		intptr_t bytes_read = portLibrary->file_read(
				portLibrary,
				file,
				*data + total_bytes_read,
				buffer_size - total_bytes_read);

}
total_bytes_read += bytes_read;
/* Break if the buffer is large enough; otherwise, grow the buffer. */
if (total_bytes_read < buffer_size - 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not subtract 1:

		if (total_bytes_read < buffer_size) {

}
/* Buffer may be too small, increase and retry. */
buffer_size *= 2;
new_data = (char *)portLibrary->mem_reallocate_memory(portLibrary, *data, buffer_size, OMR_GET_CALLSITE(), OMRMEM_CATEGORY_PORT_LIBRARY);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split:

		new_data = (char *)portLibrary->mem_reallocate_memory(
				portLibrary,
				*data,
				buffer_size,
				OMR_GET_CALLSITE(),
				OMRMEM_CATEGORY_PORT_LIBRARY);

*data = new_data;
*size = buffer_size;
}
(*data)[total_bytes_read] = '\0';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant - the caller will store the NUL.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed all the subtraction logic (-1) but placed one in the beginning of the read_fully function, to make sure that there is at least one byte left for inserting the NULL character by the caller, in the edge case where the number of bytes read is exactly equal the size of the buffer. hope you are fine with that?

omrsysinfo_get_processes(struct OMRPortLibrary *portLibrary, OMRProcessInfoCallback callback, void *userData)
{
#if defined(LINUX)
#define INITIAL_BUFFER_SIZE 4096
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this macro - it is only used once.

return (uintptr_t)(intptr_t)rc;
}
/* Allocate initial buffer. */
command = (char *)portLibrary->mem_allocate_memory(portLibrary, buffer_size, OMR_GET_CALLSITE(), OMRMEM_CATEGORY_PORT_LIBRARY);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be split:

	command = (char *)portLibrary->mem_allocate_memory(
			portLibrary,
			buffer_size,
			OMR_GET_CALLSITE(),
			OMRMEM_CATEGORY_PORT_LIBRARY);

bytes_read = read_fully(portLibrary, file, &command, &buffer_size);
portLibrary->file_close(portLibrary, file);
}
/* If cmdline is empty, try reading from comm. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should be more similar to the one on line 7643:

		/* If cmdline is empty, try reading /proc/[pid]/comm. */

@harship04 harship04 force-pushed the systemprocess-x64 branch from 978eec4 to ef21a27 Compare April 2, 2025 11:26
Comment on lines 7568 to 7569
/* leave a byte for the caller in case it wants to NULL terminate it. */
uintptr_t buffer_size = *size - 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subtracting one here is inappropriate; line 7578 guarantees that when this function succeeds, there is room for a NUL to be appended.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@harship04 harship04 force-pushed the systemprocess-x64 branch from ef21a27 to 8297bb4 Compare April 2, 2025 18:10
@keithc-ca
Copy link
Contributor

Used cmdline

The description and the commit message should say "Use cmdline" (the same tense should be used consistently).

@harship04 harship04 requested a review from keithc-ca April 3, 2025 04:39
@keithc-ca
Copy link
Contributor

Used cmdline

The description and the commit message should say "Use cmdline" (the same tense should be used consistently).

This has not been addressed.

@harship04 harship04 force-pushed the systemprocess-x64 branch from 8297bb4 to 10f4e51 Compare April 3, 2025 16:32
@babsingh
Copy link
Contributor

babsingh commented Apr 8, 2025

jenkins build all

@babsingh
Copy link
Contributor

babsingh commented Apr 8, 2025

https://ci.eclipse.org/omr/job/PullRequest-win_x86-64/4320/consoleFull

@harship04 There are compilation errors on Windows. Let me know once they are fixed, and I will relaunch the PR builds.

01:10:49      53>omrport.lib(omrport.obj) : error LNK2001: unresolved external symbol omrsysinfo_get_processes [C:\omr\workspace\PullRequest-win_x86-64\Build\build\fvtest\porttest\omrporttest.vcxproj]
01:10:49      53>C:\omr\workspace\PullRequest-win_x86-64\Build\build\Debug\omrporttest.exe : fatal error LNK1120: 1 unresolved externals [C:\omr\workspace\PullRequest-win_x86-64\Build\build\fvtest\porttest\omrporttest.vcxproj]

@harship04
Copy link
Author

@keithc-ca
The metadata for the SystemProcess event in JFR specifies the pid field as a string, but in the OMR callback, the pid is represented and handled as an integer. Should the change be made in OMR to return the PID as a string, or would it be better to convert the integer to a string within OpenJ9 instead

@keithc-ca
Copy link
Contributor

I think it would be

better to convert the integer to a string within OpenJ9

@harship04
Copy link
Author

@babsingh

https://ci.eclipse.org/omr/job/PullRequest-win_x86-64/4320/consoleFull

@harship04 There are compilation errors on Windows. Let me know once they are fixed, and I will relaunch the PR builds.

01:10:49      53>omrport.lib(omrport.obj) : error LNK2001: unresolved external symbol omrsysinfo_get_processes [C:\omr\workspace\PullRequest-win_x86-64\Build\build\fvtest\porttest\omrporttest.vcxproj]
01:10:49      53>C:\omr\workspace\PullRequest-win_x86-64\Build\build\Debug\omrporttest.exe : fatal error LNK1120: 1 unresolved externals [C:\omr\workspace\PullRequest-win_x86-64\Build\build\fvtest\porttest\omrporttest.vcxproj]

@babsingh , made the changes could you please trigger the Jenkins build

@babsingh
Copy link
Contributor

jenkins build all

Use /proc filesystem to extract command line.
Use cmdline for user space processes and comm for others.
@babsingh
Copy link
Contributor

jenkins build all

@babsingh babsingh merged commit e2016b1 into eclipse-omr:master Apr 11, 2025
12 of 13 checks passed
babsingh added a commit that referenced this pull request Jul 7, 2025
Apply camelCase naming to variables for PRs #7681 and #7772
babsingh added a commit that referenced this pull request Jul 9, 2025
Apply coding standards fix to function readFully for PR #7681
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants