⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 manager.c

📁 Newlib 嵌入式 C库 标准实现代码
💻 C
📖 第 1 页 / 共 3 页
字号:
  char * guardaddr;  size_t stacksize, guardsize;  if (attr != NULL && attr->__stackaddr_set)    {#ifdef _STACK_GROWS_UP      /* The user provided a stack. */      new_thread = (pthread_descr) attr->__stackaddr;      new_thread_bottom = (char *) (new_thread + 1);      guardaddr = attr->__stackaddr + attr->__stacksize;      guardsize = 0;#else      /* The user provided a stack.  For now we interpret the supplied	 address as 1 + the highest addr. in the stack segment.  If a	 separate register stack is needed, we place it at the low end	 of the segment, relying on the associated stacksize to	 determine the low end of the segment.  This differs from many	 (but not all) other pthreads implementations.  The intent is	 that on machines with a single stack growing toward higher	 addresses, stackaddr would be the lowest address in the stack	 segment, so that it is consistently close to the initial sp	 value. */      new_thread =        (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;      new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;      guardaddr = new_thread_bottom;      guardsize = 0;#endif#ifndef THREAD_SELF      __pthread_nonstandard_stacks = 1;#endif      /* Clear the thread data structure.  */      memset (new_thread, '\0', sizeof (*new_thread));    }  else    {#ifdef NEED_SEPARATE_REGISTER_STACK      size_t granularity = 2 * pagesize;      /* Try to make stacksize/2 a multiple of pagesize */#else      size_t granularity = pagesize;#endif      void *map_addr;      /* Allocate space for stack and thread descriptor at default address */#if FLOATING_STACKS      if (attr != NULL)	{	  guardsize = page_roundup (attr->__guardsize, granularity);	  stacksize = __pthread_max_stacksize - guardsize;	  stacksize = MIN (stacksize,			   page_roundup (attr->__stacksize, granularity));	}      else	{	  guardsize = granularity;	  stacksize = __pthread_max_stacksize - guardsize;	}      map_addr = mmap(NULL, stacksize + guardsize,		      PROT_READ | PROT_WRITE | PROT_EXEC,		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);      if (map_addr == MAP_FAILED)        /* No more memory available.  */        return -1;# ifdef NEED_SEPARATE_REGISTER_STACK      guardaddr = map_addr + stacksize / 2;      if (guardsize > 0)	mprotect (guardaddr, guardsize, PROT_NONE);      new_thread_bottom = (char *) map_addr;      new_thread = ((pthread_descr) (new_thread_bottom + stacksize				     + guardsize)) - 1;# elif _STACK_GROWS_DOWN      guardaddr = map_addr;      if (guardsize > 0)	mprotect (guardaddr, guardsize, PROT_NONE);      new_thread_bottom = (char *) map_addr + guardsize;      new_thread = ((pthread_descr) (new_thread_bottom + stacksize)) - 1;# elif _STACK_GROWS_UP      guardaddr = map_addr + stacksize;      if (guardsize > 0)	mprotect (guardaddr, guardsize, PROT_NONE);      new_thread = (pthread_descr) map_addr;      new_thread_bottom = (char *) (new_thread + 1);# else#  error You must define a stack direction# endif /* Stack direction */#else /* !FLOATING_STACKS */      void *res_addr;      if (attr != NULL)	{	  guardsize = page_roundup (attr->__guardsize, granularity);	  stacksize = STACK_SIZE - guardsize;	  stacksize = MIN (stacksize,			   page_roundup (attr->__stacksize, granularity));	}      else	{	  guardsize = granularity;	  stacksize = STACK_SIZE - granularity;	}# ifdef NEED_SEPARATE_REGISTER_STACK      new_thread = default_new_thread;      new_thread_bottom = (char *) (new_thread + 1) - stacksize - guardsize;      /* Includes guard area, unlike the normal case.  Use the bottom       end of the segment as backing store for the register stack.       Needed on IA64.  In this case, we also map the entire stack at       once.  According to David Mosberger, that's cheaper.  It also       avoids the risk of intermittent failures due to other mappings       in the same region.  The cost is that we might be able to map       slightly fewer stacks.  */      /* First the main stack: */      map_addr = (caddr_t)((char *)(new_thread + 1) - stacksize / 2);      res_addr = mmap(map_addr, stacksize / 2,		      PROT_READ | PROT_WRITE | PROT_EXEC,		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);      if (res_addr != map_addr)	{	  /* Bad luck, this segment is already mapped. */	  if (res_addr != MAP_FAILED)	    munmap(res_addr, stacksize / 2);	  return -1;	}      /* Then the register stack:	*/      map_addr = (caddr_t)new_thread_bottom;      res_addr = mmap(map_addr, stacksize/2,		      PROT_READ | PROT_WRITE | PROT_EXEC,		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);      if (res_addr != map_addr)	{	  if (res_addr != MAP_FAILED)	    munmap(res_addr, stacksize / 2);	  munmap((caddr_t)((char *)(new_thread + 1) - stacksize/2),		 stacksize/2);	  return -1;	}      guardaddr = new_thread_bottom + stacksize/2;      /* We leave the guard area in the middle unmapped.	*/# else  /* !NEED_SEPARATE_REGISTER_STACK */#  ifdef _STACK_GROWS_DOWN      new_thread = default_new_thread;      new_thread_bottom = (char *) (new_thread + 1) - stacksize;      map_addr = new_thread_bottom - guardsize;      res_addr = mmap(map_addr, stacksize + guardsize,		      PROT_READ | PROT_WRITE | PROT_EXEC,		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);      if (res_addr != map_addr)	{	  /* Bad luck, this segment is already mapped. */	  if (res_addr != MAP_FAILED)	    munmap (res_addr, stacksize + guardsize);	  return -1;	}      /* We manage to get a stack.  Protect the guard area pages if	 necessary.  */      guardaddr = map_addr;      if (guardsize > 0)	mprotect (guardaddr, guardsize, PROT_NONE);#  else      /* The thread description goes at the bottom of this area, and       * the stack starts directly above it.       */      new_thread = (pthread_descr)((unsigned long)default_new_thread &~ (STACK_SIZE - 1));      map_addr = mmap(new_thread, stacksize + guardsize,		      PROT_READ | PROT_WRITE | PROT_EXEC,		      MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);      if (map_addr == MAP_FAILED)	  return -1;      new_thread_bottom = map_addr + sizeof(*new_thread);      guardaddr = map_addr + stacksize;      if (guardsize > 0)	  mprotect (guardaddr, guardsize, PROT_NONE);#  endif /* stack direction */# endif  /* !NEED_SEPARATE_REGISTER_STACK */#endif   /* !FLOATING_STACKS */    }  *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();  /* 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_reentp = &new_thread->p_reent;  _REENT_INIT_PTR(new_thread->p_reentp);  new_thread->p_h_errnop = &new_thread->p_h_errno;  new_thread->p_resp = &new_thread->p_res;  new_thread->p_guardaddr = guardaddr;  new_thread->p_guardsize = guardsize;  new_thread->p_header.data.self = new_thread;  new_thread->p_nr = sseg;  new_thread->p_inheritsched = attr ? attr->__inheritsched : 0;  /* 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;  /* Make the new thread ID available already now.  If any of the later     functions fail we return an error value and the caller must not use     the stored thread ID.  */  *thread = new_thread_id;  /* 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.  */  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.  */#ifdef NEED_SEPARATE_REGISTER_STACK	  /* Perhaps this version should be used on all platforms. But	   this requires that __clone2 be uniformly supported	   everywhere.	   And there is some argument for changing the __clone2	   interface to pass sp and bsp instead, making it more IA64	   specific, but allowing stacks to grow outward from each	   other, to get less paging and fewer mmaps.  */	  pid = __clone2(pthread_start_thread_event,  		 (void **)new_thread_bottom,			 (char *)new_thread - new_thread_bottom,			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |			 __pthread_sig_cancel, new_thread);#elif _STACK_GROWS_UP	  pid = __clone(pthread_start_thread_event, (void **) new_thread_bottom,			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |			__pthread_sig_cancel, new_thread);#else	  pid = __clone(pthread_start_thread_event, (void **) new_thread,			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |			__pthread_sig_cancel, new_thread);#endif	  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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -