diff --git a/configure.ac b/configure.ac index e98fe4a06..f354a2dcb 100644 --- a/configure.ac +++ b/configure.ac @@ -659,6 +659,27 @@ case "$enable_capabilities" in esac +AC_ARG_ENABLE([syscall], + [AS_HELP_STRING([--enable-syscall], + [enable 'syscall' monitoring. @<:@default=check@:>@])], + [], + [enable_syscall=check] +) + +if test "x$enable_syscall" = xcheck; then + if "$cross_compiling" != no; then + enable_syscall=yes + elif test -f /proc/self/syscall && test -s /proc/self/syscall; then + enable_syscall=yes + else + enable_syscall=no + fi +fi +if test "x$enable_syscall" = xyes; then + AC_DEFINE([HAVE_SYSCALL], [1], [Define if syscall monitoring enabled.]) +fi + + AC_ARG_ENABLE([delayacct], [AS_HELP_STRING([--enable-delayacct], [enable Linux delay accounting support; requires pkg-config, libnl-3 and libnl-genl-3 @<:@default=check@:>@])], @@ -859,6 +880,7 @@ AC_MSG_RESULT([ (Linux) delay accounting: $enable_delayacct (Linux) sensors: $enable_sensors (Linux) capabilities: $enable_capabilities + (Linux) syscall: $enable_syscall unicode: $enable_unicode affinity: $enable_affinity unwind: $enable_unwind diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c index e70d7d0c9..667cae879 100644 --- a/linux/LinuxProcess.c +++ b/linux/LinuxProcess.c @@ -112,6 +112,9 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { #endif [GPU_TIME] = { .name = "GPU_TIME", .title = "GPU_TIME ", .description = "Total GPU time", .flags = PROCESS_FLAG_LINUX_GPU, .defaultSortDesc = true, }, [GPU_PERCENT] = { .name = "GPU_PERCENT", .title = " GPU% ", .description = "Percentage of the GPU time the process used in the last sampling", .flags = PROCESS_FLAG_LINUX_GPU, .defaultSortDesc = true, }, +#ifdef HAVE_SYSCALL + [SYSCALL] = { .name = "SYSCALL", .title = "SYSCALL", .description = "Current syscall of the process", .flags = PROCESS_FLAG_LINUX_SYSCALL, .autoWidth = true, }, +#endif }; Process* LinuxProcess_new(const Machine* host) { @@ -362,6 +365,24 @@ static void LinuxProcess_rowWriteField(const Row* super, RichString* str, Proces xSnprintf(buffer, n, "N/A "); } break; + #ifdef HAVE_SYSCALL + case SYSCALL: { + switch (lp->syscall_state) { + case SYSCALL_STATE_CALLING: + xSnprintf(buffer, n, "%*d ", Row_fieldWidths[SYSCALL], lp->syscall_num); + break; + case SYSCALL_STATE_RUNNING: + attr = CRT_colors[PROCESS_RUN_STATE]; + xSnprintf(buffer, n, "%-*s ", Row_fieldWidths[SYSCALL], "running"); + break; + default: + attr = CRT_colors[PROCESS_SHADOW]; + xSnprintf(buffer, n, "%-*s ", Row_fieldWidths[SYSCALL], "N/A"); + } + RichString_appendWide(str, attr, buffer); + return; + } + #endif default: Process_writeField(this, str, field); return; @@ -466,6 +487,15 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce return SPACESHIP_NUMBER(p1->gpu_time, p2->gpu_time); case ISCONTAINER: return SPACESHIP_NUMBER(v1->isRunningInContainer, v2->isRunningInContainer); + #ifdef HAVE_SYSCALL + case SYSCALL: { + int r = SPACESHIP_NUMBER(p1->syscall_state, p2->syscall_state); + if (r) + return r; + + return SPACESHIP_NUMBER(p1->syscall_num, p2->syscall_num); + } + #endif default: return Process_compareByKey_Base(v1, v2, key); } diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h index fafd7d004..1bcb0fb28 100644 --- a/linux/LinuxProcess.h +++ b/linux/LinuxProcess.h @@ -31,6 +31,13 @@ in the source distribution for its full text. #define PROCESS_FLAG_LINUX_AUTOGROUP 0x00080000 #define PROCESS_FLAG_LINUX_GPU 0x00100000 #define PROCESS_FLAG_LINUX_CONTAINER 0x00200000 +#define PROCESS_FLAG_LINUX_SYSCALL 0x00400000 + +typedef enum SyscallState_ { + SYSCALL_STATE_RUNNING, + SYSCALL_STATE_CALLING, + SYSCALL_STATE_NA, +} SyscallState; typedef struct LinuxProcess_ { Process super; @@ -118,6 +125,11 @@ typedef struct LinuxProcess_ { /* Autogroup scheduling (CFS) information */ long int autogroup_id; int autogroup_nice; + +#ifdef HAVE_SYSCALL + SyscallState syscall_state; + int syscall_num; +#endif } LinuxProcess; extern int pageSize; diff --git a/linux/LinuxProcessTable.c b/linux/LinuxProcessTable.c index 708e70478..3ea0f8318 100644 --- a/linux/LinuxProcessTable.c +++ b/linux/LinuxProcessTable.c @@ -1098,6 +1098,38 @@ static void LinuxProcessTable_readCwd(LinuxProcess* process, openat_arg_t procFd free_and_xStrdup(&process->super.procCwd, pathBuffer); } +/* + * Read /proc//syscall (thread-specific data) + */ +#ifdef HAVE_SYSCALL +static void LinuxProcessTable_readSyscall(LinuxProcess* process, openat_arg_t procFd) { + char buffer[1024]; + + ssize_t r = xReadfileat(procFd, "syscall", buffer, sizeof(buffer)); + if (r <= 0) { + goto failed; + } + + char* numPtr = buffer; + process->syscall_num = fast_strtoull_dec(&numPtr, r); + if (*numPtr == ' ') { + process->syscall_state = SYSCALL_STATE_CALLING; + Row_updateFieldWidth(SYSCALL, snprintf(NULL, 0, "%d", process->syscall_num)); + return; + } + + if (String_startsWith(buffer, "running")) { + process->syscall_state = SYSCALL_STATE_RUNNING; + Row_updateFieldWidth(SYSCALL, strlen("running")); + return; + } + +failed: + process->syscall_state = SYSCALL_STATE_NA; + Row_updateFieldWidth(SYSCALL, strlen("N/A")); +} +#endif /* HAVE_SYSCALL */ + /* * Read /proc//exe (process-shared data) */ @@ -1694,6 +1726,12 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar LinuxProcessTable_readCwd(lp, procFd, mainTask); } + #ifdef HAVE_SYSCALL + if (ss->flags & PROCESS_FLAG_LINUX_SYSCALL) { + LinuxProcessTable_readSyscall(lp, procFd); + } + #endif + if ((ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP) && this->haveAutogroup) { LinuxProcessTable_readAutogroup(lp, procFd, mainTask); } diff --git a/linux/ProcessField.h b/linux/ProcessField.h index 47c4199fe..5c2d09ed5 100644 --- a/linux/ProcessField.h +++ b/linux/ProcessField.h @@ -51,6 +51,7 @@ in the source distribution for its full text. GPU_TIME = 132, \ GPU_PERCENT = 133, \ ISCONTAINER = 134, \ + SYSCALL = 135, \ // End of list