Skip to content

Commit

Permalink
Merge pull request #7214 from singh264/omr_issues_7201
Browse files Browse the repository at this point in the history
Get the process start time
  • Loading branch information
babsingh committed Jan 11, 2024
2 parents 3e1bb69 + 4cf8368 commit 9d24613
Show file tree
Hide file tree
Showing 11 changed files with 424 additions and 147 deletions.
78 changes: 78 additions & 0 deletions fvtest/porttest/si.cpp
Expand Up @@ -52,6 +52,12 @@
#endif /* defined(J9ZOS390) */
#include <sys/resource.h> /* For RLIM_INFINITY */
#endif /* !defined(OMR_OS_WINDOWS) */
#if defined(OMR_OS_WINDOWS)
#include <windows.h>
#else /* defined(OMR_OS_WINDOWS) */
#include <sys/wait.h>
#include <unistd.h>
#endif /* defined(OMR_OS_WINDOWS) */

#if defined(J9ZOS390) && !defined(OMR_EBCDIC)
#include "atoe.h"
Expand Down Expand Up @@ -3119,3 +3125,75 @@ TEST(PortSysinfoTest, GetProcessorDescription)
ASSERT_TRUE(feature == TRUE || feature == FALSE);
}
}

/* The method omrsysinfo_get_process_start_time is not implemented on z/TPF. */
#if !defined(OMRZTPF)
/**
* Test: GetProcessorStartTimeOfNonExistingProcessTest.
* Description: Verify that getting the process start time for a non-existing process (UINTPTR_MAX) results in 0 nanoseconds.
* Passing Condition: The expected process start time is 0 nanoseconds, and the actual process start time matches this value.
*/
TEST(PortSysinfoTest, GetProcessorStartTimeOfNonExistingProcessTest)
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
/*
* If a pid of UINTPTR_MAX exists in the future then the test will need to be modified.
* UINTPTR_MAX represents the maximum unsigned integer value, which can be a 32-bit or a 64-bit depending on the system.
* On unix systems, a pid is represented by pid_t, which can be a 32-bit or a 64-bit signed integer.
* On windows systems, a pid is represented by DWORD, which is a 32-bit unsigned integer, and
* the maximum value of DWORD is not a valid pid as it is reserved for use by the ASFW_ANY parameter.
*/
uintptr_t pid = UINTPTR_MAX;
uint64_t expectedProcessStartTimeInNanoseconds = 0;
uint64_t actualProcessStartTimeInNanoseconds = 0;
int32_t rc = omrsysinfo_get_process_start_time(pid, &actualProcessStartTimeInNanoseconds);
ASSERT_LT(rc, 0);
ASSERT_EQ(expectedProcessStartTimeInNanoseconds, actualProcessStartTimeInNanoseconds);
}

/**
* Test: GetProcessorStartTimeOfExistingProcessTest.
* Description: Verify that getting the process start time for an existing process results in a valid timestamp.
* Passing Condition: The process start time is greater than the test start time and less than the current time at the end of the test.
*/
TEST(PortSysinfoTest, GetProcessorStartTimeOfExistingProcessTest)
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
uintptr_t pid = UINTPTR_MAX;
uintptr_t success = 0;
uint64_t testStartTimeInNanoseconds = omrtime_current_time_nanos(&success);
uint64_t processStartTimeInNanoseconds = 0;
int32_t rc = 0;
#if defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390)
int status = 0;
sleep(3);
pid = fork();
ASSERT_NE(pid, -1);
/* The if block will only be invoked by the child process. */
if (0 == pid) {
sleep(10);
/* A call to exit allows the child process to stop and avoids a timeout on x86-64 macOS. */
exit(0);
}
rc = omrsysinfo_get_process_start_time(pid, &processStartTimeInNanoseconds);
waitpid(pid, &status, 0);
#elif defined(OMR_OS_WINDOWS) /* defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390) */
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL ret = FALSE;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
ret = CreateProcess(NULL, "cmd.exe /c timeout /t 10", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
ASSERT_EQ(ret, TRUE);
pid = (uintptr_t)GetProcessId(pi.hProcess);
rc = omrsysinfo_get_process_start_time(pid, &processStartTimeInNanoseconds);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif /* defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390) */
ASSERT_EQ(rc, 0);
ASSERT_GT(processStartTimeInNanoseconds, testStartTimeInNanoseconds);
ASSERT_LT(processStartTimeInNanoseconds, omrtime_current_time_nanos(&success));
}
#endif /* !defined(OMRZTPF) */
3 changes: 3 additions & 0 deletions include_core/omrport.h
Expand Up @@ -2459,6 +2459,8 @@ typedef struct OMRPortLibrary {
int32_t (*sysinfo_cgroup_subsystem_iterator_next)(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state, struct OMRCgroupMetricElement *metricElement);
/** see @ref omrsysinfo.c::omrsysinfo_cgroup_subsystem_iterator_destroy "omrsysinfo_cgroup_subsystem_iterator_destroy"*/
void (*sysinfo_cgroup_subsystem_iterator_destroy)(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state);
/** see @ref omrsysinfo.c::omrsysinfo_get_process_start_time "omrsysinfo_get_process_start_time"*/
int32_t (*sysinfo_get_process_start_time)(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds);
/** see @ref omrport.c::omrport_init_library "omrport_init_library"*/
int32_t (*port_init_library)(struct OMRPortLibrary *portLibrary, uintptr_t size) ;
/** see @ref omrport.c::omrport_startup_library "omrport_startup_library"*/
Expand Down Expand Up @@ -3102,6 +3104,7 @@ extern J9_CFUNC int32_t omrport_getVersion(struct OMRPortLibrary *portLibrary);
#define omrsysinfo_cgroup_subsystem_iterator_metricKey(param1, param2) privateOmrPortLibrary->sysinfo_cgroup_subsystem_iterator_metricKey(privateOmrPortLibrary, param1, param2)
#define omrsysinfo_cgroup_subsystem_iterator_next(param1, param2) privateOmrPortLibrary->sysinfo_cgroup_subsystem_iterator_next(privateOmrPortLibrary, param1, param2)
#define omrsysinfo_cgroup_subsystem_iterator_destroy(param1) privateOmrPortLibrary->sysinfo_cgroup_subsystem_iterator_destroy(privateOmrPortLibrary, param1)
#define omrsysinfo_get_process_start_time(param1, param2) privateOmrPortLibrary->sysinfo_get_process_start_time(privateOmrPortLibrary, param1, param2)
#define omrintrospect_startup() privateOmrPortLibrary->introspect_startup(privateOmrPortLibrary)
#define omrintrospect_shutdown() privateOmrPortLibrary->introspect_shutdown(privateOmrPortLibrary)
#define omrintrospect_set_suspend_signal_offset(param1) privateOmrPortLibrary->introspect_set_suspend_signal_offset(privateOmrPortLibrary, param1)
Expand Down
2 changes: 2 additions & 0 deletions include_core/omrporterror.h
Expand Up @@ -421,6 +421,8 @@
#define OMRPORT_ERROR_SYSINFO_CGROUP_NULL_PARAM (OMRPORT_ERROR_SYSINFO_BASE-30)
#define OMRPORT_ERROR_SYSINFO_ERROR_SWAPPINESS_OPEN_FAILED (OMRPORT_ERROR_SYSINFO_BASE-31)
#define OMRPORT_ERROR_SYSINFO_ERROR_READING_SWAPPINESS (OMRPORT_ERROR_SYSINFO_BASE-32)
#define OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS (OMRPORT_ERROR_SYSINFO_BASE-33)
#define OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME (OMRPORT_ERROR_SYSINFO_BASE-34)

/**
* @name Port library initialization return codes
Expand Down
1 change: 1 addition & 0 deletions port/common/omrport.c
Expand Up @@ -335,6 +335,7 @@ static OMRPortLibrary MainPortLibraryTable = {
omrsysinfo_cgroup_subsystem_iterator_metricKey, /* sysinfo_cgroup_subsystem_iterator_metricKey */
omrsysinfo_cgroup_subsystem_iterator_next, /* sysinfo_cgroup_subsystem_iterator_next */
omrsysinfo_cgroup_subsystem_iterator_destroy, /* sysinfo_cgroup_subsystem_iterator_destroy */
omrsysinfo_get_process_start_time, /* sysinfo_get_process_start_time */
omrport_init_library, /* port_init_library */
omrport_startup_library, /* port_startup_library */
omrport_create_library, /* port_create_library */
Expand Down
3 changes: 3 additions & 0 deletions port/common/omrport.tdf
Expand Up @@ -1630,3 +1630,6 @@ TraceEvent=Trc_PRT_sl_open_shared_library_noload Group=sl Overhead=1 Level=3 NoE
TraceException=Trc_PRT_retrieveLinuxMemoryStats_failedOpeningSwappinessFs Group=sysinfo Overhead=1 Level=1 NoEnv Template="retrieveLinuxMemoryStats: Failed to open /proc/sys/vm/swappiness. Error code = %d."
TraceException=Trc_PRT_retrieveLinuxMemoryStats_failedReadingSwappiness Group=sysinfo Overhead=1 Level=1 NoEnv Template="retrieveLinuxMemoryStats: Failed to read /proc/sys/vm/swappiness. Error code = %d."
TraceException=Trc_PRT_retrieveLinuxMemoryStats_unexpectedSwappinessFormat Group=sysinfo Overhead=1 Level=1 NoEnv Template="retrieveLinuxMemoryStats: Expected %d items to read, but read %d items."

TraceEntry=Trc_PRT_sysinfo_get_process_start_time_enter Group=sysinfo Overhead=1 Level=1 NoEnv Template="Enter omrsysinfo_get_process_start_time, pid=%llu."
TraceExit=Trc_PRT_sysinfo_get_process_start_time_exit Group=sysinfo Overhead=1 Level=1 NoEnv Template="Exit omrsysinfo_get_process_start_time, pid=%llu, processStartTimeInNanoseconds=%llu, rc=%d."
13 changes: 13 additions & 0 deletions port/common/omrsysinfo.c
Expand Up @@ -1178,3 +1178,16 @@ omrsysinfo_cgroup_subsystem_iterator_destroy(struct OMRPortLibrary *portLibrary,
{
return;
}

/**
* Get the process start time in ns precision epoch time.
* @param[in] portLibrary The port library
* @param[in] pid The process ID
* @param[in/out] processStartTimeInNanoseconds The pointer to uint64_t that stores the process start time in ns precision epoch time
* @return 0 on success, error code on failure
*/
int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds)
{
return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;
}
2 changes: 2 additions & 0 deletions port/omrportpriv.h
Expand Up @@ -661,6 +661,8 @@ extern J9_CFUNC int32_t
omrsysinfo_cgroup_subsystem_iterator_next(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state, struct OMRCgroupMetricElement *metricElement);
extern J9_CFUNC void
omrsysinfo_cgroup_subsystem_iterator_destroy(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state);
extern J9_CFUNC int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds);

/* J9SourceJ9Signal*/
extern J9_CFUNC int32_t
Expand Down
104 changes: 104 additions & 0 deletions port/unix/omrsysinfo.c
Expand Up @@ -80,6 +80,7 @@


#if defined(J9ZOS390)
#include "omrgetthent.h"
#include "omrsimap.h"
#endif /* defined(J9ZOS390) */

Expand All @@ -95,6 +96,7 @@

#if defined(AIXPPC)
#include <fcntl.h>
#include <procinfo.h>
#include <sys/procfs.h>
#include <sys/systemcfg.h>
#endif /* defined(AIXPPC) */
Expand Down Expand Up @@ -195,6 +197,14 @@ uintptr_t Get_Number_Of_CPUs();
#define JIFFIES 100
#define USECS_PER_SEC 1000000
#define TICKS_TO_USEC ((uint64_t)(USECS_PER_SEC/JIFFIES))
#define OMRPORT_SYSINFO_PROC_DIR_BUFFER_SIZE 256
#define OMRPORT_SYSINFO_NUM_SYSCTL_ARGS 4
#define OMRPORT_SYSINFO_NANOSECONDS_PER_MICROSECOND 1000ULL
#if defined(_LP64)
#define GETTHENT BPX4GTH
#else /* defined(_LP64) */
#define GETTHENT BPX1GTH
#endif /* defined(_LP64) */

static uintptr_t copyEnvToBuffer(struct OMRPortLibrary *portLibrary, void *args);
static uintptr_t copyEnvToBufferSignalHandler(struct OMRPortLibrary *portLib, uint32_t gpType, void *gpInfo, void *unUsed);
Expand Down Expand Up @@ -598,6 +608,19 @@ static intptr_t searchSystemPath(struct OMRPortLibrary *portLibrary, char *filen
#if defined(J9ZOS390)
static void setOSFeature(struct OMROSDesc *desc, uint32_t feature);
static intptr_t getZOSDescription(struct OMRPortLibrary *portLibrary, struct OMROSDesc *desc);
#if defined(_LP64)
#pragma linkage(BPX4GTH,OS)
#else /* defined(_LP64) */
#pragma linkage(BPX1GTH,OS)
#endif /* defined(_LP64) */
void GETTHENT(
unsigned int *inputSize,
unsigned char **input,
unsigned int *outputSize,
unsigned char **output,
unsigned int *ret,
unsigned int *retCode,
unsigned int *reasonCode);
#endif /* defined(J9ZOS390) */

#if !defined(RS6000) && !defined(J9ZOS390) && !defined(OSX) && !defined(OMRZTPF)
Expand Down Expand Up @@ -7354,3 +7377,84 @@ get_Dispatch_IstreamCount(void) {
return (uintptr_t)numberOfIStreams;
}
#endif /* defined(OMRZTPF) */

int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds)
{
int32_t rc = 0;
uint64_t computedProcessStartTimeInNanoseconds = 0;
Trc_PRT_sysinfo_get_process_start_time_enter((unsigned long long)pid);
if (0 != omrsysinfo_process_exists(portLibrary, pid)) {
#if defined(LINUX)
char procDir[OMRPORT_SYSINFO_PROC_DIR_BUFFER_SIZE] = {0};
struct stat st;
snprintf(procDir, sizeof(procDir), "/proc/%" PRIuPTR, pid);
if (-1 == stat(procDir, &st)) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
}
computedProcessStartTimeInNanoseconds = (uint64_t)st.st_mtime * OMRPORT_TIME_DELTA_IN_NANOSECONDS + st.st_mtim.tv_nsec;
#elif defined(OSX) /* defined(LINUX) */
int mib[OMRPORT_SYSINFO_NUM_SYSCTL_ARGS] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
size_t len = sizeof(struct kinfo_proc);
struct kinfo_proc procInfo;
if (-1 == sysctl(mib, OMRPORT_SYSINFO_NUM_SYSCTL_ARGS, &procInfo, &len, NULL, 0)) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
}
if (0 == len) {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
goto done;
}
computedProcessStartTimeInNanoseconds =
((uint64_t)procInfo.kp_proc.p_starttime.tv_sec * OMRPORT_TIME_DELTA_IN_NANOSECONDS) +
((uint64_t)procInfo.kp_proc.p_starttime.tv_usec * OMRPORT_SYSINFO_NANOSECONDS_PER_MICROSECOND);
#elif defined(AIXPPC) /* defined(OSX) */
pid_t convertedPid = (pid_t)pid;
struct procsinfo procInfos[] = {0};
int ret = getprocs(procInfos, sizeof(procInfos[0]), NULL, 0, &convertedPid, sizeof(procInfos) / sizeof(procInfos[0]));
if (-1 == ret) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
} else if (0 == ret) {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
goto done;
}
computedProcessStartTimeInNanoseconds = (uint64_t)(procInfos[0].pi_start) * OMRPORT_TIME_DELTA_IN_NANOSECONDS;
#elif defined(J9ZOS390) /* defined(AIXPPC) */
pgtha pgtha;
ProcessData processData;
pgthc *currentProcessInfo = NULL;
uint32_t dataOffset = 0;
uint32_t inputSize = sizeof(pgtha);
unsigned char *input = (unsigned char *)&pgtha;
uint32_t outputSize = sizeof(ProcessData);
unsigned char *output = (unsigned char *)&processData;
uint32_t ret = 0;
uint32_t retCode = 0;
uint32_t reasonCode = 0;
memset(input, 0, sizeof(pgtha));
memset(output, 0, sizeof(processData));
pgtha.pid = pid;
pgtha.accesspid = PGTHA_ACCESS_CURRENT;
pgtha.flag1 = PGTHA_FLAG_PROCESS_DATA;
GETTHENT(&inputSize, &input, &outputSize, &output, &ret, &retCode, &reasonCode);
if (-1 == ret) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
}
dataOffset = *((unsigned int *)processData.pgthb.offc);
dataOffset = (dataOffset & I_32_MAX) >> 8;
currentProcessInfo = (pgthc *)(((char *)&processData) + dataOffset);
computedProcessStartTimeInNanoseconds = (uint64_t)currentProcessInfo->starttime * OMRPORT_TIME_DELTA_IN_NANOSECONDS;
#else /* defined(J9ZOS390) */
rc = OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;
#endif /* defined(LINUX) */
} else {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
}
done:
*processStartTimeInNanoseconds = computedProcessStartTimeInNanoseconds;
Trc_PRT_sysinfo_get_process_start_time_exit((unsigned long long)pid, (unsigned long long)computedProcessStartTimeInNanoseconds, rc);
return rc;
}
35 changes: 35 additions & 0 deletions port/win32/omrsysinfo.c
Expand Up @@ -46,6 +46,10 @@
#include "ut_omrport.h"
#include "omrsysinfo_helpers.h"

#define OMRPORT_SYSINFO_WINDOWS_TICK 10000000ULL
#define OMRPORT_SYSINFO_SEC_TO_UNIX_EPOCH 11644473600ULL
#define OMRPORT_SYSINFO_NS100_PER_SEC 10000000ULL

static int32_t copyEnvToBuffer(struct OMRPortLibrary *portLibrary, void *args);

typedef struct CopyEnvToBufferArgs {
Expand Down Expand Up @@ -1990,3 +1994,34 @@ omrsysinfo_cgroup_subsystem_iterator_destroy(struct OMRPortLibrary *portLibrary,
return;
}

int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds)
{
int32_t rc = 0;
uint64_t computedProcessStartTimeInNanoseconds = 0;
Trc_PRT_sysinfo_get_process_start_time_enter((unsigned long long)pid);
if (0 != omrsysinfo_process_exists(portLibrary, pid)) {
double seconds = 0;
FILETIME createTime, exitTime, kernelTime, userTime;
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
if (NULL == process) {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
goto done;
}
if (!GetProcessTimes(process, &createTime, &exitTime, &kernelTime, &userTime)) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto cleanup;
}
seconds = (double)(*(LONGLONG *)&(createTime)) / OMRPORT_SYSINFO_WINDOWS_TICK;
computedProcessStartTimeInNanoseconds = (uint64_t)((seconds - OMRPORT_SYSINFO_SEC_TO_UNIX_EPOCH) * OMRPORT_SYSINFO_NS100_PER_SEC);
computedProcessStartTimeInNanoseconds *= 100;
cleanup:
CloseHandle(process);
} else {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
}
done:
*processStartTimeInNanoseconds = computedProcessStartTimeInNanoseconds;
Trc_PRT_sysinfo_get_process_start_time_exit((unsigned long long)pid, (unsigned long long)computedProcessStartTimeInNanoseconds, rc);
return rc;
}

0 comments on commit 9d24613

Please sign in to comment.