Linux thread pthread_create Source analysis

Source: Internet
Author: User
int __pthread_create_2_1 (pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine) (void *), void *arg)/  
/thread for pthread_t, actually is pthread pointer. typedef struct PTHREAD *pthread_t; ->unsigned long int//attr additional properties when creating threads//start_routine executing thread function//arg parameter first address pointer {PTHREAD_DESCR self = thread_s  
Elf ();  
Request struct Pthread_request requests to the management thread;  
global int __pthread_manager_request =-1 at initialization time; if (__pthread_manager_request < 0) {//First linuxthreads need to have __pthread_manager_thread, this thread is a very special thread//initialization linuxthreads system  
Thread if (__pthread_initialize_manager () < 0) return eagain;  
} request.req_thread = self;  
Request type CREATE and package the parameters of the new thread (lightweight process) into the request structure.  
Request.req_kind = req_create;  
Request.req_args.create.attr = attr;  
Request.req_args.create.fn = Start_routine;  
Request.req_args.create.arg = arg;  
Sigprocmask is used to change the current blocking signal set of the process Sigprocmask (Sig_setmask, (const sigset_t *) NULL, &request.req_args.create.mask); Write to __pthread_manager_request REquest request.  
Request requests will be read and processed by _pthread_manager_thread.  
__libc_write (__pthread_manager_request, (char *) &request, sizeof (request));  
Hang up suspend (self);  
if (Thread_getmem (self, p_retcode) = = 0) *thread = (pthread_t) thread_getmem (self, p_retval);  
Return Thread_getmem (self, p_retcode); #if defined have_elf && defined PIC && defined do_versioning default_symbol_version (__pthrea  
      
D_create_2_1, Pthread_create, glibc_2.1);  
int __pthread_create_2_0 (pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine) (void *), void *arg) { /* The ATTR attribute is not really of type ' pthread_attr_t * '. 
It has the "old size" and "access to" new members might crash. We convert the struct now.  
      
* * pthread_attr_t new_attr;  
      
if (attr!= NULL) {size_t PS = __getpagesize ();  
memcpy (&new_attr, attr, (size_t) & (((pthread_attr_t*) NULL)->__guardsize));  
New_attr.__guardsize = PS; New_attr.__stAckaddr_set = 0;  
NEW_ATTR.__STACKADDR = NULL;  
New_attr.__stacksize = Stack_size-ps;  
attr = &new_attr;  
return __pthread_create_2_1 (thread, attr, Start_routine, ARG); } symbol_version (__pthread_create_2_0, Pthread_create, glibc_2.0); So the Pthread_create entry function is __pthread_create_2_1 #else strong_alias (__pthread_create_2_1, pthread_create) #endif from the top  
The function of a pthread_create is known to be that the creation of a thread is actually sending a request to pthread_manager_thread. Let's see how the Pthread_manager_thread is initialized: First of all, the initialization of the basic system: that is, filling __pthread_initial_thread, is it a template? Other properties:/* Descriptor of the initial thread * * struct _pthread_descr_struct __pthread_initial_thread = {&__pthread _initial_thread,/* PTHREAD_DESCR p_nextlive///threaded all the user threads in the process &__pthread_initial_thread,/* PTHREAD_DESCR P_pre Vlive */NULL,/* PTHREAD_DESCR p_nextwaiting/NULL,/* PTHREAD_DESCR P_nextlock/Pthread_threads_max,/* pthread_t P_ TID * * 0,/* int p_pid */0,/* int p_priority * * &__pthread_handles[0].h_loCK,/* struct _pthread_fastlock * P_lock/0,/* int p_signal/NULL,/* SIGJMP_BUF * P_SIGNAL_BUF */NULL,/* SIGJMP_BU 
F * P_cancel_buf */0,/* char p_terminated/0,/* char p_detached/0,/* char p_exited/NULL,/* void * P_retval * 0,/* int p_retval */null,/* PTHREAD_DESCR p_joining/null,/* struct _pthread_cleanup_buffer * p_cleanup * * 0,/* CH AR p_cancelstate * * 0,/* char p_canceltype/0,/* char p_canceled/NULL,/* int *P_ERRNOP/0,/* int P_errno/* NUL L,/* int *P_H_ERRNOP */0,/* int P_h_errno/NULL,/* char * p_in_sighandler/0,/* Char p_sigwaiting/Pthread_star T_args_initializer,/* struct Pthread_start_args P_start_args */{NULL},/* void * * * p_specific[pthread_key_1stlevel_size ] */{NULL},/* void * P_libc_specific[_libc_tsd_key_n]/0,/* int p_userstack */null,/* void * p_guardaddr/0,/* s ize_t p_guardsize * * &__pthread_initial_thread,/* PTHREAD_DESCR p_self/0,/* Always index 0/0,/* int P_report_ Events * {{0,}}, 0, NULL},/* td_eventbuf_t p_eventbuf * * atomic_initializer,/* struct pthread_atomic p_resume_count/0, * char P_woken_by_ca  
      
Ncel * * struct pthread_extricate_if *p_extricate * *;  
static void Pthread_initialize (void) {struct sigaction sa;  
sigset_t Mask;  
struct Rlimit limit;  
      
int max_stack; __pthread_initial_thread_bos:limit between the stack of the initial thread (above) and the//stacks of other threads (below).  
Aligned on a stack_size boundary.  
/* If initialization is completed, exit/if (__pthread_initial_thread_bos!= NULL) return; #ifdef TEST_FOR_COMPARE_AND_SWAP/* TEST if COMPARE-AND-SWAP is available * * __pthread_has_cas = Compare_and_swap_is_ava  
Ilable (); #endif/* For the initial stack, reserve at least stack_size bytes of stack below the "current stack", and align That's on a stack_size boundary.  
* * __pthread_initial_thread_bos = (char *) (((Long) current_stack_frame.-2 * stack_size) & ~ (stack_size-1)); /* Assign value to Initial_thread.pid: main process PID */__pthread_initial_thread.p_pid = __getpid (); /* If We have special thread_self processing, initialize "for" the main thread now.  
* * #ifdef init_thread_self init_thread_self (&__pthread_initial_thread, 0);  
#endif/* Shared main process errno/h_errno.*/__pthread_initial_thread.p_errnop = &_errno;  
__pthread_initial_thread.p_h_errnop = &_h_errno; /* Play with the stack size limit to make sure this no stack ever grows beyond stack_size minus two pages (one page for T He thread descriptor immediately beyond, and one page to act as a guard page. * * Getrlimit (Rlimit_stack, &limit);  
Get stack Limit max_stack = stack_size-2 * __getpagesize ();  
if (Limit.rlim_cur > Max_stack) {limit.rlim_cur = Max_stack;  
Setrlimit (Rlimit_stack, &limit); } #ifdef __sigrtmin/* Initialize real-time signals.  
* * Init_rtsigs (); 
#endif/* Setup signal handlers for the initial thread. Since signal handlers are shared between threads, these settings would be inheriteD by all other threads.  
*//Set initial thread signal processing function Other threads will inherit #ifndef __i386__ Sa.sa_handler = Pthread_handle_sigrestart;  
#else Sa.sa_handler = (__sighandler_t) Pthread_handle_sigrestart;  
#endif Sigemptyset (&sa.sa_mask);  
sa.sa_flags = 0;  
__sigaction (__pthread_sig_restart, &sa, NULL);  
#ifndef __i386__ sa.sa_handler = pthread_handle_sigcancel;  
#else Sa.sa_handler = (__sighandler_t) pthread_handle_sigcancel;  
#endif sa.sa_flags = 0;  
__sigaction (__pthread_sig_cancel, &sa, NULL);  
if (__pthread_sig_debug > 0) {sa.sa_handler = Pthread_handle_sigdebug;  
Sigemptyset (&sa.sa_mask);  
sa.sa_flags = 0;  
__sigaction (__pthread_sig_debug, &sa, NULL); }/* Initially, block __pthread_sig_restart. 'll is unblocked on demand.  
* * Sigemptyset (&mask);  
Sigaddset (&mask, __pthread_sig_restart);  
Sigprocmask (Sig_block, &mask, NULL); /* Register an exit function to kill all other threads. */* Do it early so user-registered ateXIT functions are called before pthread_exit_process.  
* * __on_exit (pthread_exit_process, NULL); //Below is __pthread_manager_thread initialization/* Descriptor of the manager thread; The none of this are used but the error variables, the P_pid and P_priority fields, and the address for identification.  
* * struct _pthread_descr_struct __pthread_manager_thread = {NULL,/* PTHREAD_DESCR p_nextlive///These two values are empty! NULL,/* PTHREAD_DESCR p_prevlive */null,/* PTHREAD_DESCR p_nextwaiting/NULL,/* PTHREAD_DESCR p_nextlock/0,/* in T P_tid * * 0,/* int p_pid * * 0,/* int p_priority * * &__pthread_handles[1].h_lock,/* struct _pthread_fastlock * P_lo CK/0,/* int p_signal/NULL,/* SIGJMP_BUF * P_SIGNAL_BUF/NULL,/* SIGJMP_BUF * p_cancel_buf * * 0,/* Char P_termi nated */0,/* char p_detached/0,/* char p_exited/null,/* void * p_retval/0,/* int p_retval/NULL,/* Pthrea D_DESCR p_joining/NULL,/* struct _pthread_cleanup_buffer * p_cleanup * * 0,/* CHar p_cancelstate * * 0,/* char p_canceltype/0,/* char p_canceled/&__pthread_manager_thread.p_errno,/* int *p_  ERRNOP * * 0,/* int p_errno/NULL,/* int *P_H_ERRNOP/0,/* int p_h_errno/NULL,/* char * p_in_sighandler/0,/* Char p_sigwaiting/pthread_start_args_initializer,/* struct Pthread_start_args P_start_args/{NULL},/* void * * * p_sp Ecific[pthread_key_1stlevel_size] */{NULL},/* void * P_libc_specific[_libc_tsd_key_n]/0,/* int p_userstack/NULL, /* void * p_guardaddr/0,/* size_t p_guardsize/&__pthread_manager_thread,/* PTHREAD_DESCR p_self/1,/* Alway  S index 1/0,/* int p_report_events * * {{0,}}, 0, NULL},/* td_eventbuf_t p_eventbuf/atomic_initializer,/* struct  
Pthread_atomic P_resume_count * * 0,/* char p_woken_by_cancel/NULL/struct pthread_extricate_if *p_extricate * *;  
int __pthread_initialize_manager (void) {//manage communication between threads and other threads is done through pipelines. /* Within a process space, the management thread communicates with other threads through a pair of "management piping (manager_pipe[2])", which is created before the administrative thread is created,After the management thread has been successfully started, the read and write ends of the management pipeline are assigned to two global variables __pthread_manager_reader and __pthread_manager_request, after which each user thread passes through the __pthread_ 
Manager_request Cheng the request to the management line, but the management thread itself does not use __pthread_manager_reader directly, and the read end of the pipe (manager_pipe[0) is passed to the management thread as one of the parameters of the __clone (). The main task of managing threads is to listen to the channel and respond to requests taken from it.  
*/int manager_pipe[2];  
int pid;  
      
struct Pthread_request request;  
/* If the basic initialization is not done, then initialize the/if (__pthread_initial_thread_bos = NULL) pthread_initialize ();  
/* Set STACK */__pthread_manager_thread_bos = malloc (thread_manager_stack_size);  
if (__pthread_manager_thread_bos = = NULL) return-1;  
Top value __pthread_manager_thread_tos = __pthread_manager_thread_bos + thread_manager_stack_size;  
/* Set Communication pipe/if (pipe (manager_pipe) = = 1) {free (__pthread_manager_thread_bos);  
return-1;  
/* The PID must not be 0/PID when creating the thread = 0; if (__pthread_initial_thread.p_report_events) {/* It ' s a bit more complicated. We have to the creation of the manager thread.  
* * int idx = __td_eventword (td_create); uint32_t mask = __Td_eventmask (td_create); if (Mask & (__PTHREAD_THREADS_EVENTS.EVENT_BITS[IDX) | __pthread_initial_thread.p_eventbuf.eventmask.event_ BITS[IDX])!= 0 {//sys_fork: Create Pthread_manager Thread: Shared vm FS Files pid = __clone (__pthread_manager_event, (voi d * * * __pthread_manager_thread_tos, CLONE_VM | Clone_fs | Clone_files | Clone_sighand, (void *) (long) manager_pipe[0]); Read pipeline if (PID!=-1) {* Now fill in the information about the new thread in the newly created thread ' s DA TA structure. We cannot let the "new thread do" since we don ' t know whether it is already scheduled when we send the event.  
///Add attribute to new thread __pthread_manager_thread.p_eventbuf.eventdata = &__pthread_manager_thread;  
__pthread_manager_thread.p_eventbuf.eventnum = td_create;  
__pthread_last_event = &__pthread_manager_thread;  
_pthread_manager_thread is the 2*pthread_threads_max+1 __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thrEad.p_pid = pid; The clone process PID/* Now call the function which signals the event.  
      
* * __linuxthreads_create_event (); /* Now restart the thread.  
* * __pthread_unlock (__pthread_manager_thread.p_lock);  }}//If __pthread_initial_thread.p_report_events is marked, nature will no longer create a new thread if (PID = = 0) pid = __clone (__pthread_manager, (void * * *) __pthread_manager_thread_tos, CLONE_VM | Clone_fs | Clone_files |  
Clone_sighand, (void *) (long) manager_pipe[0]);  
if (PID = = 1) {free (__pthread_manager_thread_bos);  
__libc_close (Manager_pipe[0]);  
__libc_close (manager_pipe[1]);  
return-1; }//__pthread_manager_request FD = manager_pipe[1]; Write requests to other threads __pthread_manager_request = manager_pipe[1]; /* global variable writing end */__pthread_manager_reader = manager_pipe[0];  
/* global variable reading end */__pthread_manager_thread.p_tid = 2* Pthread_threads_max + 1;  
__pthread_manager_thread.p_pid = pid; /* Make GDB aware of new thread Manager */if (__pthread_threads_debug && __pthread_Sig_debug > 0) {raise (__pthread_sig_debug); /* We suspend ourself and GDB would wake us up as it is ready to handle us.  
* * __pthread_wait_for_restart_signal (thread_self ());  
}/* Synchronize debugging of the thread Manager */request.req_kind = Req_debug;  
__libc_write (__pthread_manager_request, (char *) &request, sizeof (request));  
return 0;  
At this point, __pthread_manager_thread was created successfully.  Let's see how it's Managed: __pthread_manager function/* The server thread managing requests for thread creation and termination/INT  
__pthread_manager (void *arg) {int REQFD = (int) (long int) arg;//pipe read-port fd struct POLLFD UFD;  
sigset_t Mask;  
int n;  
      
struct Pthread_request request; /* If We have special thread_self processing, initialize it.  
* * #ifdef init_thread_self init_thread_self (&__pthread_manager_thread, 1); #endif/* Set the error variable.  
* * __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; __pthread_manager_thread.p_h_errnOP = &__pthread_manager_thread.p_h_errno;  
/* Block all signals except __pthread_sig_cancel and Sigtrap/Sigfillset (&mask); Sigdelset (&mask, __pthread_sig_cancel); /* for thread termination */Sigdelset (&mask, sigtrap);  
/* For debugging purposes * * Sigprocmask (Sig_setmask, &mask, NULL);  
/* Increase priority equal to the primary thread's priority/__pthread_manager_adjust_prio (__pthread_main_thread->p_priority); /* Synchronize debugging of the Thread Manager//////Read request from Pipeline n = __libc_read (REQFD, (char *) &request, sizeof (reques  
t));  
ASSERT (n = = sizeof (request) && Request.req_kind = = Req_debug);  
UFD.FD = REQFD;  
Ufd.events = Pollin;  /* Enter Server loop */while (1) {n = __poll (&UFD, 1, 2000);//2 SEC Timeout/The termination of main thread will cause all thread terminations */IF (Getppid () = 1)  
{pthread_kill_all_threads (SIGKILL, 0);  
_exit (0);  
}/* Check for dead Children */if (terminated_children) {terminated_children = 0;  
Pthread_reap_children (); /* Read Request/*/if (n = 1 && (Ufd.revents & Pollin))  
{n = __libc_read (REQFD, (char *) &request, sizeof (request));  
ASSERT (n = = sizeof (request));  Switch (request.req_kind) {case req_create://Create Request.req_thread->p_retcode = Pthread_handle_create (pthread_t *) &request.req_thread->p_retval, request.req_args.create.attr, Request.req_args.create.fn, Request.req_arg S.create.arg, &request.req_args.create.mask, Request.req_thread->p_pid, Request.req_thread->p_report_  
events, &request.req_thread->p_eventbuf.eventmask);  
Restart (request.req_thread);  
Break  
Case Req_free:pthread_handle_free (request.req_args.free.thread_id);  
Break  
Case Req_process_exit:pthread_handle_exit (Request.req_thread, Request.req_args.exit.code);  
Break  
Case req_main_thread_exit:main_thread_exiting = 1;  
if (__pthread_main_thread->p_nextlive = = __pthread_main_thread) {restart (__pthread_main_thread);  
return 0;  
} break; Case Req_post: __new_sem_post (Request.req_args.post);  
Break Case REQ_DEBUG:/* Make GDB aware of new thread and GDB would restart the new thread when it's ready to handle the new Thread.  
*/if (__pthread_threads_debug && __pthread_sig_debug > 0) Raise (__pthread_sig_debug);  
Break   
Below we look at how the new thread was created: static int pthread_handle_create (pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine) (void *), void *arg, sigset_t * mask, int father_pid, int report_events, td_thr_events_t *  
EVENT_MASKP) {size_t sseg;  
int pid;  
PTHREAD_DESCR New_thread;  
char * NEW_THREAD_BOTTOM;  
pthread_t new_thread_id;  
char *guardaddr = NULL;  
size_t guardsize = 0;  
      
int pagesize = __getpagesize (); /* Whether we have to change the policy and if yes, whether we can does this. Normally this should is done by examining the return value of the __sched_setscheduler call in Pthread_start_thread but This is hard to implement. FIXME */if (attr!= NULL && attr->__schedpolicy!= sched_other && geteuid ()!= 0) return eperm; /* Find a free segment for the thread, and allocate a stack if needed */for (sseg = 2;; sseg++) {if sseg >= PTH  
Read_threads_max) return eagain;  
if (__PTHREAD_HANDLES[SSEG].H_DESCR!= NULL) continue; if (Pthread_allocate_stack (attr, Thread_segment (sseg), pagesize, &new_thread, &new_thread_bottom, &  
GUARDADDR, &guardsize) = = 0) break;  
} __pthread_handles_num++;  
/* Allocate new Thread identifier/pthread_threads_counter + = Pthread_threads_max;  
new_thread_id = sseg + pthread_threads_counter; /* Initialize the thread descriptor. Elements which have to is initialized to zero already the this value. ///////New_thread->p_tid = new_thread_id for new thread;  
Tid=n*pthread_threads_max+n+1 New_thread->p_lock = & (__pthread_handles[sseg].h_lock);  
New_thread->p_cancelstate = pthread_cancel_enable; New_thread->p_canceltype = Pthread_cancel_deferred;  
New_thread->p_errnop = &new_thread->p_errno;  
New_thread->p_h_errnop = &new_thread->p_h_errno;  
NEW_THREAD->P_GUARDADDR = guardaddr;  
New_thread->p_guardsize = guardsize;  
New_thread->p_self = New_thread;  
NEW_THREAD->P_NR = sseg;  
/* Initialize the thread handle * * __pthread_init_lock (&__pthread_handles[sseg].h_lock);  
__PTHREAD_HANDLES[SSEG].H_DESCR = New_thread;  
__pthread_handles[sseg].h_bottom = New_thread_bottom;  
/* Determine scheduling parameters for the thread * new_thread->p_start_args.schedpolicy =-1;  
if (attr!= NULL) {new_thread->p_detached = attr->__detachstate;  
      
New_thread->p_userstack = attr->__stackaddr_set; Switch (attr->__inheritsched) {Case pthread_explicit_sched:new_thread->p_start_args.schedpolicy = attr->__  
Schedpolicy;  
memcpy (&new_thread->p_start_args.schedparam, &attr->__schedparam, sizeof (struct sched_param));  
Break Case PthrEad_inherit_sched:new_thread->p_start_args.schedpolicy = __sched_getscheduler (father_pid);  
__sched_getparam (Father_pid, &new_thread->p_start_args.schedparam);  
Break  
} new_thread->p_priority = new_thread->p_start_args.schedparam.sched_priority;  }/* Finish setting up arguments to Pthread_start_thread *///new Thread function parameter Assignment New_thread->p_start_args.start_routine =  
Start_routine;  
New_thread->p_start_args.arg = arg;  
New_thread->p_start_args.mask = *mask;  
      
      
      
      
/* Raise Priority of Thread manager if needed/__pthread_manager_adjust_prio (new_thread->p_priority); /* Do the cloning. We have to use two different functions depending on whether we are debugging or not. * * pid = 0; /* Note this thread never can have PID zero. */if (report_events) {/* Whether the Td_create event bit is set in any of the masks. */int idx = __td_eventwor  
D (td_create);  
      
uint32_t mask = __td_eventmask (td_create); if ((Mask & (__pthread_threads_events.event_bits[idx] | event_maskp->event_bits[idx]))!= 0) {/* Lock the Mutex The child would use this it would stop.  
      
* * __pthread_lock (New_thread->p_lock, NULL); /* We have to the this event. * * pid = __clone (Pthread_start_thread_event, (void * *) New_thread, CLONE_VM | Clone_fs | Clone_files |  
Clone_sighand |  
__pthread_sig_cancel, New_thread); if (PID!=-1) {/* Now fill in the information about the new thread in the newly created thread ' s data structure. We cannot let the "new thread do" since we don ' t know whether it is already scheduled when we send the event.  
* * New_thread->p_eventbuf.eventdata = New_thread;  
New_thread->p_eventbuf.eventnum = td_create;  
      
__pthread_last_event = New_thread;  /* We have to set the PID here since the callback function in the debug library would need it and We cannot guarantee the Child got scheduled before the debugger.  
 * * new_thread->p_pid = PID;     
/* Now call the function which signals the event.  
      
* * __linuxthreads_create_event (); /* Now restart the thread.  
* * __pthread_unlock (New_thread->p_lock); }} if (PID = = 0) pid = __clone (Pthread_start_thread, (void * * *) New_thread, CLONE_VM | Clone_fs | Clone_files |  
Clone_sighand |  
__pthread_sig_cancel, New_thread); /* Check If cloning succeeded/if (PID = 1) {/* Free the stack if we allocated it/if (attr = NULL | |!attr-> __stackaddr_set) {if (new_thread->p_guardsize!= 0) munmap (new_thread->p_guardaddr, New_thread->p_guardsiz  
e);  
Munmap ((caddr_t) ((char *) (new_thread+1)-initial_stack_size), initial_stack_size);  
} __PTHREAD_HANDLES[SSEG].H_DESCR = NULL;  
__pthread_handles[sseg].h_bottom = NULL;  
__pthread_handles_num--;  
return errno;  
/* * Add a thread to the __pthread_main_thread two-way list by management thread management/new_thread->p_prevlive = __pthread_main_thread;  
New_thread->p_nextlive = __pthread_main_thread->p_nextlive; __pthrEad_main_thread->p_nextlive->p_prevlive = New_thread;  
__pthread_main_thread->p_nextlive = New_thread; /* Set pid field of the new thread, in case we get there before the starts. * * new_thread->p_pid = PID;  
It records the PID returned by clone/* We ' re all set */*thread = new_thread_id;  
return 0; }

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.