|
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.
For 2.4.18:
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: };
For 2.6.0:
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: }; Please feel free to use the comments form below if you have any questions or need more explanation on anything.
|
Comments (write a comment):
0 comments so far. Be the first one to leave a comment on this article.