Getting the process id of a current process without unistd.h
I’m working on a deadlock detection algorithm and I’m only given kernel level libraries, i.e. #include
2 Answers 2
I did some quick research and I found the answer. Thanks so much for your direction. The quick code I used was:
printf("My current process id/pid is %d\n", current->pid);
Note that although this may have been the case in 2009, with modern Linux PID namespaces, the answer may be more complex.
This question makes little sense.
Are you writing kernel-based code? In which case you can get the pid of the current task by using the «current» macro which points to the current task’s task struct (which contains a member with the pid). That would only work if your kernel code is running in a context where a «current task» makes sense (i.e. not an interrupt, tasklet etc).
If you’re writing userspace code, there should be no reason you can’t call getpid, which is a library call from the C library defined in unistd.h (or something it includes), which makes the system call. If there is such a reason, please explain it.
Making a system call in Linux isn’t particularly difficult, but does involve architecture-specific code that you don’t want to write.
Hi, thanks for getting back to me so quickly. It is kernel-based code. Can you elaborate more on the current macro and how it’s used? You are correct in saying that it’s not userspace code and I can’t access unistd.h.
Linux kernel data structures (Part 1) — the current macro
Note: I have used linux kernels 2.4.18 and 2.6.0 for this tutorial.
The Linux kernel uses this macro to find the current process. The current macro is defined in include/asm-i386/current.h (line 13) in both 2.6.0 and 2.4.18 kernels. This macro calls another function get_current() . The difference is that, in Linux 2.4.18 get_current() (line 6 – 11, include/asmi386/current.h) is itself used to find the address of the current process but in Linux 2.6.0 get_current() in turn calls another function current_thread_info() defined in include/asm-i386/thread_info.h (lines 81 – 86).
For 2.4.18, struct task_struct* get_current() contains:
struct task_struct *current; __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); return current;
For 2.6.0, struct thread_info* current_thread_info() contains:
struct thread_info *ti; __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~8191UL)); return ti;
Note: The use of 8191. I’ll explain that in detail below.
In 2.6.0, on return from current_thread_info() , get_current() simply returns the value of the task pointer by doing the following (line 10, include/asm-i386/current.h):
return current_thread_info()->task;
For both kernels, the main functions do the following:
The value of the kernel stack pointer is somewhere within the task_union (or thread_union for 2.6.0); (will talk about them later) 8191 decimal is 0001 1111 1111 1111 binary. Inverting that gives 1110 0000 0000 0000. This effectively strips off the low-order 13 bits of the stack pointer value, aligning it at the beginning of the task_union (or thread_union for 2.6.0). This is also the beginning of the task_struct (for 2.4.18) and thread_info (for 2.6.0).
What are task_union (2.4.18) and thread_union (2.6.0)?
They are unions that share space with an array of unsigned long. Both these structures are defined in include/linux/sched.h. Definition is below.
507: #ifndef INIT_TASK_SIZE 508: # define INIT_TASK_SIZE 2048*sizeof(long) 509: #endif 510: 511: union task_union < 512: struct task_struct task; 513: unsigned long stack[INIT_TASK_SIZE/sizeof(long)]; 514: >;
536: #ifndef INIT_THREAD_SIZE 537: # define INIT_THREAD_SIZE 2048*sizeof(long) 538: #endif 539: 540: union thread_union < 541: struct thread_info thread_info; 542: unsigned long stack[INIT_THREAD_SIZE/sizeof(long)]; 543: >;
Did this tutorial help a little? How about buy me a cup of coffee?
Please feel free to use the comments form below if you have any questions or need more explanation on anything. I do not guarantee a response.
IMPORTANT: You must thoroughy test any instructions on a production-like test environment first before trying anything on production systems. And, make sure it is tested for security, privacy, and safety. See our terms here.
Linux World
Linux maintains a the structure of the kind «task_struct» for every process that runs in the system. This structure defined in «linux/sched.h».
It maintains various data of a process like the process id, name, memory related information etc.
While writing a module if we want to get information about the current process that is running in the kernel, we need to read the «task_struct» of the
corresponding process. The kernel provides a easy way to do this by providing a macro by the name «current», which always returns a pointer to the «task_struct» of the current executing process.
The implementation of the current pointer can change from one architecture to other, in the standard x86 architecture the pointer is read from the process stack Each process has a structure of the kind thread_info which is always stored at the end of the stack. The thread_info in turn has a pointer to the «task_struct» of the process. As the location of the thread_info is fixed in the stack, we can access it easily using the stack pointer and the stack size.
For eg: if the stack size is 8KB the 13 Least significant bits can be masked to get a pointer to the thread_info structure. The pointer to the «task_stuct» is obtained by dereferencing the member «task» of the structure which is the pointer to «task_struct».
Example for using the current pointer.
Let us try to write a module that created a proc entry «process_data» and when read, it returns the information of the current process by making use of the macro current.
To learn about proc entry creation you can refer to Creating proc entry
To be able to access «current» we will need to include the file «linux/sched.h» . In the function read_proc we print the «name» and «process id» of the
current process using «current->comm» and «current->pid» respectively. Other fields of the structure task_struct can also we referred to in the similar way.
***************************current_proc.c**************************************
#include
#include
#include
#include
int read_proc(char *buf,char **start,off_t offset,int count,int *eof,void *data )
int len=0;
len = sprintf(buf,»\n Name :%s \n Process id: %d\n «,current->comm,current->pid);
printk(KERN_INFO «Inside the proc entry»);
return len;
>
void create_new_proc_entry()
create_proc_read_entry(«process_data»,0,NULL,read_proc,NULL);
create_new_proc_entry();
return 0;
>
void char_arr_cleanup(void) printk(KERN_INFO » Inside cleanup_module\n»);
remove_proc_entry(«process_data»,NULL);
>
MODULE_LICENSE(«GPL»);
module_init(char_arr_init);
module_exit(char_arr_cleanup);
********************************************************************************************
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
*******************************************************************************
Run the following commands to see the output
$ make
$ sudo insmod current_proc.ko
$ cat /proc/process_data
Note: The output will always give process name as «cat» as that is what we are using to read the proc entry.
«current» in Linux kernel code
As I was going through the below chunk of Linux char driver code, I found the structure pointer current in printk . I want to know what structure the current is pointing to and its complete elements. What purpose does this structure serve?
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos) < printk(KERN_DEBUG "process %i (%s) going to sleep\n", current->pid, current->comm); wait_event_interruptible(wq, flag != 0); flag = 0; printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); return 0; >
2 Answers 2
It is a pointer to the current process ie, the process which has issued the system call.
The Current Process
Although kernel modules don’t execute sequentially as applications do, most actions performed by the kernel are related to a specific process. Kernel code can know the current process driving it by accessing the global item current, a pointer to struct task_struct, which as of version 2.4 of the kernel is declared in , included by . The current pointer refers to the user process currently executing. During the execution of a system call, such as open or read, the current process is the one that invoked the call. Kernel code can use process-specific information by using current, if it needs to do so. An example of this technique is presented in «Access Control on a Device File», in Chapter 5, «Enhanced Char Driver Operations».
Actually, current is not properly a global variable any more, like it was in the first Linux kernels. The developers optimized access to the structure describing the current process by hiding it in the stack page. You can look at the details of current in . While the code you’ll look at might seem hairy, we must keep in mind that Linux is an SMP-compliant system, and a global variable simply won’t work when you are dealing with multiple CPUs. The details of the implementation remain hidden to other kernel subsystems though, and a device driver can just include and refer to the current process.
From a module’s point of view, current is just like the external reference printk. A module can refer to current wherever it sees fit. For example, the following statement prints the process ID and the command name of the current process by accessing certain fields in struct task_struct:
printk("The process is \"%s\" (pid %i)\n", current->comm, current->pid);
The command name stored in current->comm is the base name of the program file that is being executed by the current process.
Here is the complete structure the «current» is pointing to
task_struct Each task_struct data structure describes a process or task in the system. struct task_struct < /* these are hardcoded - don't touch */ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ long counter; long priority; unsigned long signal; unsigned long blocked; /* bitmap of masked signals */ unsigned long flags; /* per process flags, defined below */ int errno; long debugreg[8]; /* Hardware debugging registers */ struct exec_domain *exec_domain; /* various fields */ struct linux_binfmt *binfmt; struct task_struct *next_task, *prev_task; struct task_struct *next_run, *prev_run; unsigned long saved_kernel_stack; unsigned long kernel_stack_page; int exit_code, exit_signal; /* . */ unsigned long personality; int dumpable:1; int did_exec:1; int pid; int pgrp; int tty_old_pgrp; int session; /* boolean value for session group leader */ int leader; int groups[NGROUPS]; /* * pointers to (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with * p->p_pptr->pid) */ struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; struct wait_queue *wait_chldexit; unsigned short uid,euid,suid,fsuid; unsigned short gid,egid,sgid,fsgid; unsigned long timeout, policy, rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; struct timer_list real_timer; long utime, stime, cutime, cstime, start_time; /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; int swappable:1; unsigned long swap_address; unsigned long old_maj_flt; /* old value of maj_flt */ unsigned long dec_flt; /* page fault count of the last time */ unsigned long swap_cnt; /* number of pages to swap on next pass */ /* limits */ struct rlimit rlim[RLIM_NLIMITS]; unsigned short used_math; char comm[16]; /* file system info */ int link_count; struct tty_struct *tty; /* NULL if no tty */ /* ipc stuff */ struct sem_undo *semundo; struct sem_queue *semsleeping; /* ldt for this task - used by Wine. If NULL, default_ldt is used */ struct desc_struct *ldt; /* tss for this task */ struct thread_struct tss; /* filesystem information */ struct fs_struct *fs; /* open file information */ struct files_struct *files; /* memory management info */ struct mm_struct *mm; /* signal handlers */ struct signal_struct *sig; #ifdef __SMP__ int processor; int last_processor; int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock. */ #endif >;
Linked
Related
Hot Network Questions
Subscribe to RSS
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.14.43533
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.