DEV Community

Ömer Gülen
Ömer Gülen

Posted on

2

How to add system call (syscall) that prints elapsed time of a process with given PID to the kernel and test it?

In my previous tutorial 👇

I described how to add syscall to the kernel, compile it and test it in detail. As promised, I now would like to describe how to create a syscall that prints out the elapsed time of a process with a given process id(PID).

This task was my Operating Systems Programming Assignment.

In this tutorial, unlike the previous tutorial I will not go over into every detail, but point out the different parts of the process.

After changing my current directory into kernel source files, I create another folder for my new function. You don't need to do it, but I prefer it this way.

mkdir petime && cd petime
Enter fullscreen mode Exit fullscreen mode

I will call my function petime short for process elapsed time.

After I've created a C file which my code goes into.

vim petime.c
Enter fullscreen mode Exit fullscreen mode

In my C code, I used SYSCALL_DEFINE1 Macro from <linux/syscalls.h>. Because I needed to pass one integer argument to the function.

Also, you can use it for different argument counts. While argument count is X, the syntax will be like SYSCALL_DEFINEX.

Example:

// For 2 parameters
SYSCALL_DEFINE2(function_name, int, first_int, int, second_int){
  // code goes here
}

// For 1 parameter
SYSCALL_DEFINE1(function_name, int, first_int){
  // code goes here
}

// For no-parameters
SYSCALL_DEFINE0(function_name){
  // code goes here
}
Enter fullscreen mode Exit fullscreen mode

In addition to this Macro, I used the task_struct struct to get the process' start time and time elapsed since the boot with ktime_get_ns() function.

My C file which contains my syscall:

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/syscalls.h>

// Used this macro to be able to pass variables to the syscall
// It takes one integer, PID.
SYSCALL_DEFINE1(sys_petime, int, pid)
{
  // Using task_struct struct from sched.h, which has task's (process)
  // various data mostly about scheduling.
  struct task_struct *task;
  u64 start_time, elapsed;

  // Get process with PID.
  task = pid_task(find_vpid(pid), PIDTYPE_PID);
  // If process is not found.
  if (task == NULL)
  {
    // Print the error to the kernel buffer
    printk(KERN_INFO "Cannot find a process with that PID: %d\n", pid);
  }
  else
  {
    // Taken from "taskstats.c" source code (line 240-241).
    // Used the logic behind calculating the delta time in that source.
    // Get current nanoseconds since boot
    start_time = ktime_get_ns();
    // Difference
    elapsed = start_time - task->real_start_time;
    // Print result to the kernel buffer
    printk(KERN_INFO "PID: %d has ELAPSED %llu nanoseconds.", pid, elapsed);
  }

  // If nothing goes wrong, return 0 as successful
  return 0;
}
Enter fullscreen mode Exit fullscreen mode

ktime_get_ns() is like timestamp but it doesn't count from 1 Jan 1970 instead it counts nanoseconds since the Operating System boots.

task->real_start_time is the boot based start time of the process in nanoseconds.

So as a result, the difference of total elapsed time since boot and the boot based start time of a process gives the elapsed time of a process.

Then, I've created Makefile file of my syscall:

vim Makefile
Enter fullscreen mode Exit fullscreen mode

and inserted the default-ish configuration:

obj-y := petime.o
Enter fullscreen mode Exit fullscreen mode

Now, I need to let my general Makefile know about my new folder and function.

Go back to the kernel source folder and edit Makefile:

cd .. && vim Makefile
Enter fullscreen mode Exit fullscreen mode

Find the line with the core-y, it should be similar to this:

core-y      += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ hello/
Enter fullscreen mode Exit fullscreen mode

hello/ is the folder from our previous tutorial.

I've added my new folder petime to the end of this line. Result should be looking like this:

core-y      += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ hello/ petime/
Enter fullscreen mode Exit fullscreen mode

After saving the Makefile, we need to add our new syscall to the syscalls tables.

I will describe the tutorial according to 64-bit Operating System, if you want to do it on 32-bit OS, you can go back to my previous tutorial find the details of the following steps for 32-bit OS.

For 64-bit OS, I add my syscall to the end of my file(table):

549 64  petime  __64_sys_sys_petime
Enter fullscreen mode Exit fullscreen mode

I've put sys 2 times, like _sys_sys_ because my function name was already sys_petime but you need to prepend __64_sys_ of the function name in this table, so result becomes __64_sys_sys_petime.

Then, we need to add our function signature to the syscalls header file syscalls.h.

vim include/linux/syscalls.h
Enter fullscreen mode Exit fullscreen mode

Then, add the following line to the end of the document before the #endif statement:

asmlinkage long sys_petime(int);
Enter fullscreen mode Exit fullscreen mode

Now, we can compile it the same as our Hello World example.

After the, compilation we can test it with the following C code:

#include <stdio.h>
#include <linux/kernel.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  // Get args from terminal and call petime (get elapsed time) with that PID.
  long int helloCheck = syscall(549, atoi(argv[1]));
  printf("System call sys_petime returned %ld\n", helloCheck);
  return 0;
}
Enter fullscreen mode Exit fullscreen mode

And the result is such that:
Terminal output of syscall

Please comment below your questions and feedback.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (2)

Collapse
 
stalim profile image
Stalim Rivero

I got this error:

arch/x86/entry/syscall_64.o:(.rodata+0x1120): undefined reference to `__64_sys_sys_petime'
Makefile:1080: recipe for target 'vmlinux' failed

Collapse
 
nguyenquangduc2000 profile image
Nguyen Quang Duc

change this in include/linux/syscalls.h
asmlinkage long sys_petime(int);
to:
asmlinkage long __64_sys_sys_petime(int);

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay