manager.c
来自「Axis 221 camera embedded programing inte」· C语言 代码 · 共 906 行 · 第 1/3 页
C
906 行
SCHED_OTHER, &default_params); } /* Make gdb aware of new thread */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { request.req_thread = self; request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); } /* Run the thread code */ outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, p_start_args.arg)); /* Exit with the given return value */ pthread_exit(outcome);}static int__attribute__ ((noreturn))pthread_start_thread_event(void *arg){ pthread_descr self = (pthread_descr) arg;#ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr);#endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, __getpid()); /* Get the lock the manager will free once all is correctly set up. */ __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); /* Free it immediately. */ __pthread_unlock (THREAD_GETMEM(self, p_lock)); /* Continue with the real function. */ pthread_start_thread (arg);}static int pthread_allocate_stack(const pthread_attr_t *attr, pthread_descr default_new_thread, int pagesize, pthread_descr * out_new_thread, char ** out_new_thread_bottom, char ** out_guardaddr, size_t * out_guardsize){ pthread_descr new_thread; char * new_thread_bottom; char * guardaddr; size_t stacksize, guardsize; if (attr != NULL && attr->__stackaddr_set) { /* The user provided a stack. */ new_thread = (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1; new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize; guardaddr = NULL; guardsize = 0; __pthread_nonstandard_stacks = 1; } else {#ifdef __ARCH_HAS_MMU__ stacksize = STACK_SIZE - pagesize; if (attr != NULL) stacksize = MIN (stacksize, roundup(attr->__stacksize, pagesize)); /* Allocate space for stack and thread descriptor at default address */ new_thread = default_new_thread; new_thread_bottom = (char *) (new_thread + 1) - stacksize; if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE), INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0) == MAP_FAILED) /* Bad luck, this segment is already mapped. */ return -1; /* We manage to get a stack. Now see whether we need a guard and allocate it if necessary. Notice that the default attributes (stack_size = STACK_SIZE - pagesize) do not need a guard page, since the RLIMIT_STACK soft limit prevents stacks from running into one another. */ if (stacksize == STACK_SIZE - pagesize) { /* We don't need a guard page. */ guardaddr = NULL; guardsize = 0; } else { /* Put a bad page at the bottom of the stack */ guardsize = attr->__guardsize; guardaddr = (void *)new_thread_bottom - guardsize; if (mmap ((caddr_t) guardaddr, guardsize, 0, MAP_FIXED, -1, 0) == MAP_FAILED) { /* We don't make this an error. */ guardaddr = NULL; guardsize = 0; } }#else /* We cannot mmap to this huge chunk of stack space when we don't have * an MMU. Pretend we are using a user provided stack even if there was * none provided by the user. Thus, we get around the mmap and reservation * of a huge stack segment. -StS */ stacksize = INITIAL_STACK_SIZE; /* The user may want to use a non-default stacksize */ if (attr != NULL) { stacksize = attr->__stacksize; } /* malloc a stack - memory from the bottom up */ if ((new_thread_bottom = malloc(stacksize)) == NULL) { /* bad luck, we cannot malloc any more */ return -1 ; } PDEBUG("malloced chunk: base=%p, size=0x%04x\n", new_thread_bottom, stacksize); /* Set up the pointers. new_thread marks the TOP of the stack frame and * the address of the pthread_descr struct at the same time. Therefore we * must account for its size and fit it in the malloc()'ed block. The * value of `new_thread' is then passed to clone() as the stack argument. * * ^ +------------------------+ * | | pthread_descr struct | * | +------------------------+ <- new_thread * malloc block | | | * | | thread stack | * | | | * v +------------------------+ <- new_thread_bottom * * Note: The calculated value of new_thread must be word aligned otherwise * the kernel chokes on a non-aligned stack frame. Choose the lower * available word boundary. */ new_thread = ((pthread_descr) ((int)(new_thread_bottom + stacksize) & -sizeof(void*))) - 1; guardaddr = NULL; guardsize = 0; PDEBUG("thread stack: bos=%p, tos=%p\n", new_thread_bottom, new_thread); /* check the initial thread stack boundaries so they don't overlap */ NOMMU_INITIAL_THREAD_BOUNDS((char *) new_thread, (char *) new_thread_bottom); PDEBUG("initial stack: bos=%p, tos=%p\n", __pthread_initial_thread_bos, __pthread_initial_thread_tos); /* on non-MMU systems we always have non-standard stack frames */ __pthread_nonstandard_stacks = 1; #endif /* __ARCH_HAS_MMU__ */ } /* Clear the thread data structure. */ memset (new_thread, '\0', sizeof (*new_thread)); *out_new_thread = new_thread; *out_new_thread_bottom = new_thread_bottom; *out_guardaddr = guardaddr; *out_guardsize = guardsize; return 0;}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(); int saved_errno = 0; /* First check whether we have to change the policy and if yes, whether we can do this. Normally this should be 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 >= PTHREAD_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 be initialized to zero already have this value. */ new_thread->p_tid = new_thread_id; 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;#ifdef __UCLIBC_HAS_XLOCALE__ /* Initialize thread's locale to the global locale. */ new_thread->locale = __global_locale;#endif /* __UCLIBC_HAS_XLOCALE__ */ 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->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 that the thread never can have PID zero. */ /* ******************************************************** */ /* This code was moved from below to cope with running threads * on uClinux systems. See comment below... * Insert new thread in doubly linked list of active threads */ 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; /* ********************************************************* */ if (report_events) { /* See whether the TD_CREATE event bit is set in any of the masks. */ int idx = __td_eventword (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 will use now so that it will stop. */ __pthread_lock(new_thread->p_lock, NULL); /* We have to report this event. */ pid = clone(pthread_start_thread_event, (void **) new_thread, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | __pthread_sig_cancel, new_thread); saved_errno = errno; 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 this since we don't know whether it was 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 will 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. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?