questions about segment and its relationship with TLS/NPTL

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello everyone..

I try to observe how TLS and NPTL work on kernel side.  I use Redhat 9 
with stock kernel 2.4.20-19.9 and glibc-2.3.2-11.9.

I create a simple pthread test program which forks 2 threads and simply 
print "Hello world" message. At the end, I call pthread_join two times 
to cleanly terminate these two threads and finally terminate the main 
program.

Strace-ing on the program shows me these interesting outputs (i am sorry 
if the line wrapping screws code pasted below):

mmap2(NULL, 8388608, PROT_READ|PROT_WRITE|PROT_EXEC, 
MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0) = 0x40037000
brk(0)                                  = 0x8049824
brk(0x804a824)                          = 0x804a824
brk(0)                                  = 0x804a824
brk(0x804b000)                          = 0x804b000
mprotect(0x40037000, 4096, PROT_NONE)   = 0
clone(child_stack=0x408368d0,flags=CLONE_VM|CLONE_FS|CLONE_FILES|
CLONE_SIGHAND|CLONE_THREAD|CLONE_SETTLS|CLONE_PARENT_SETTID|
CLONE_CHILD_CLEARTID|CLONE_DETACHED, 
[4954],{entry_number:6,base_addr:0x40836cc0, 
limit:1048575,seg_32bit:1,contents:0, read_exec_only:0, 
limit_in_pages:1,seg_not_present:0, useable:1}) = 4954

On the other hand, inside arch/i386/kernel/process.c, i found codes that 
handles CLONE_SETTLS flag (copy_thread() function ):

if (clone_flags & CLONE_SETTLS) {
                struct desc_struct *desc;
                struct user_desc info;
                int idx;

                if (copy_from_user(&info, (void *)childregs->esi, 
sizeof(info)))
                        return -EFAULT;
                if (LDT_empty(&info))
                        return -EINVAL;

                idx = info.entry_number;
                if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
                        return -EINVAL;

                desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
                desc->a = LDT_entry_a(&info);
                desc->b = LDT_entry_b(&info);
        }
My questions is:
1. What is the purpose of allocating new LDT entry? Is it to provide new 
segment for freshly created thread to store its thread-local data?

2. Is the format of LDT entry 100% similar with GDT entry? If yes, what 
is the advantage of using LDT for this threading purpose instead of 
GDT?

3. Observing strace results, it seems that the user space program 
defines certain base address for new allocated segment along with other 
attributes. On the kernel side, seems like these informations are 
retrieved to construct new LDT entry. My early conclusions is: base 
address is needed because thread local data (defined by __thread) only 
contains offset, thus it needs base address to form a complete linear 
address. Is this correct?

4. I read somewhere on the Internet that gs register is used to point on 
the currently used LDT entry related with currently running thread. Is 
this just a convention which is used inside the libpthread? or is there 
other explanation on why using gs register for this purpose?

thank your for your help...again, sorry for this long e-mail.......

regards

Mulyadi


--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux