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

📄 manager.c

📁 Newlib 嵌入式 C库 标准实现代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Linuxthreads - a simple clone()-based implementation of Posix        *//* threads for Linux.                                                   *//* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              *//*                                                                      *//* This program is free software; you can redistribute it and/or        *//* modify it under the terms of the GNU Library General Public License  *//* as published by the Free Software Foundation; either version 2       *//* of the License, or (at your option) any later version.               *//*                                                                      *//* This program is distributed in the hope that it will be useful,      *//* but WITHOUT ANY WARRANTY; without even the implied warranty of       *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *//* GNU Library General Public License for more details.                 *//* The "thread manager" thread: manages creation and termination of threads */#include <errno.h>#define __USE_MISC#include <sched.h>#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/poll.h>		/* for poll */#include <sys/mman.h>           /* for mmap */#include <sys/param.h>#include <sys/time.h>#include <sys/wait.h>           /* for waitpid macros */#include "pthread.h"#include "internals.h"#include "spinlock.h"#include "restart.h"#include "semaphore.h"/* Array of active threads. Entry 0 is reserved for the initial thread. */struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] ={ { __LOCK_INITIALIZER, &__pthread_initial_thread, 0},  { __LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ };/* For debugging purposes put the maximum number of threads in a variable.  */const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX;#ifndef THREAD_SELF/* Indicate whether at least one thread has a user-defined stack (if 1),   or if all threads have stacks supplied by LinuxThreads (if 0). */int __pthread_nonstandard_stacks;#endif/* Number of active entries in __pthread_handles (used by gdb) */volatile int __pthread_handles_num = 2;/* Whether to use debugger additional actions for thread creation   (set to 1 by gdb) */volatile int __pthread_threads_debug;/* Globally enabled events.  */volatile td_thr_events_t __pthread_threads_events;/* Pointer to thread descriptor with last event.  */volatile pthread_descr __pthread_last_event;/* Mapping from stack segment to thread descriptor. *//* Stack segment numbers are also indices into the __pthread_handles array. *//* Stack segment number 0 is reserved for the initial thread. */#if FLOATING_STACKS# define thread_segment(seq) NULL#elsestatic inline pthread_descr thread_segment(int seg){  return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)         - 1;}#endif/* Flag set in signal handler to record child termination */static volatile int terminated_children;/* Flag set when the initial thread is blocked on pthread_exit waiting   for all other threads to terminate */static int main_thread_exiting;/* Counter used to generate unique thread identifier.   Thread identifier is pthread_threads_counter + segment. */static pthread_t pthread_threads_counter;/* Forward declarations */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);static void pthread_handle_free(pthread_t th_id);static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)     __attribute__ ((noreturn));static void pthread_reap_children(void);static void pthread_kill_all_threads(int sig, int main_thread_also);static void pthread_for_each_thread(void *arg,     void (*fn)(void *, pthread_descr));/* The server thread managing requests for thread creation and termination */int__attribute__ ((noreturn))__pthread_manager(void *arg){  int reqfd = (int) (long int) arg;  struct pollfd ufd;  sigset_t manager_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_reentp = &__pthread_manager_thread.p_reent;  __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;  /* Block all signals except __pthread_sig_cancel and SIGTRAP */  sigfillset(&manager_mask);  sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */  sigdelset(&manager_mask, SIGTRAP);            /* for debugging purposes */  if (__pthread_threads_debug && __pthread_sig_debug > 0)    sigdelset(&manager_mask, __pthread_sig_debug);  sigprocmask(SIG_SETMASK, &manager_mask, NULL);  /* Raise our priority to match that of main thread */  __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);  /* Synchronize debugging of the thread manager */  n = TEMP_FAILURE_RETRY(__libc_read(reqfd, (char *)&request,				     sizeof(request)));  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);    /* Check for termination of the main thread */    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 and execute request */    if (n == 1 && (ufd.revents & POLLIN)) {      n = TEMP_FAILURE_RETRY(__libc_read(reqfd, (char *)&request,					 sizeof(request)));#ifdef DEBUG      if (n < 0) {	char d[64];	write(STDERR_FILENO, d, snprintf(d, sizeof(d), "*** read err %m\n"));      } else if (n != sizeof(request)) {	write(STDERR_FILENO, "*** short read in manager\n", 26);      }#endif      switch(request.req_kind) {      case REQ_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_args.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);	/* NOTREACHED */        break;      case REQ_MAIN_THREAD_EXIT:        main_thread_exiting = 1;	/* Reap children in case all other threads died and the signal handler	   went off before we set main_thread_exiting to 1, and therefore did	   not do REQ_KICK. */	pthread_reap_children();        if (__pthread_main_thread->p_nextlive == __pthread_main_thread) {          restart(__pthread_main_thread);	  /* The main thread will now call exit() which will trigger an	     __on_exit handler, which in turn will send REQ_PROCESS_EXIT	     to the thread manager. In case you are wondering how the	     manager terminates from its loop here. */	}        break;      case REQ_POST:        __new_sem_post(request.req_args.post);        break;      case REQ_DEBUG:	/* Make gdb aware of new thread and gdb will restart the	   new thread when it is ready to handle the new thread. */	if (__pthread_threads_debug && __pthread_sig_debug > 0)	  raise(__pthread_sig_debug);        break;      case REQ_KICK:	/* This is just a prod to get the manager to reap some	   threads right away, avoiding a potential delay at shutdown. */	break;      case REQ_FOR_EACH_THREAD:	pthread_for_each_thread(request.req_args.for_each.arg,	                        request.req_args.for_each.fn);	restart(request.req_thread);	break;      }    }  }}int __pthread_manager_event(void *arg){  /* If we have special thread_self processing, initialize it.  */#ifdef INIT_THREAD_SELF  INIT_THREAD_SELF(&__pthread_manager_thread, 1);#endif  /* Get the lock the manager will free once all is correctly set up.  */  __pthread_lock (THREAD_GETMEM((&__pthread_manager_thread), p_lock), NULL);  /* Free it immediately.  */  __pthread_unlock (THREAD_GETMEM((&__pthread_manager_thread), p_lock));  return __pthread_manager(arg);}/* Process creation */static int__attribute__ ((noreturn))pthread_start_thread(void *arg){  pthread_descr self = (pthread_descr) arg;  struct pthread_request request;  void * outcome;#if HP_TIMING_AVAIL  hp_timing_t tmpclock;#endif  /* Initialize special thread_self processing, if any.  */#ifdef INIT_THREAD_SELF  INIT_THREAD_SELF(self, self->p_nr);#endif#if HP_TIMING_AVAIL  HP_TIMING_NOW (tmpclock);  THREAD_SETMEM (self, p_cpuclock_offset, tmpclock);#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());  /* Initial signal mask is that of the creating thread. (Otherwise,     we'd just inherit the mask of the thread manager.) */  sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL);  /* Set the scheduling policy and priority for the new thread, if needed */  if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0)    /* Explicit scheduling attributes were provided: apply them */    __sched_setscheduler(THREAD_GETMEM(self, p_pid),			 THREAD_GETMEM(self, p_start_args.schedpolicy),                         &self->p_start_args.schedparam);  else if (__pthread_manager_thread.p_priority > 0)    /* Default scheduling required, but thread manager runs in realtime       scheduling: switch new thread to SCHED_OTHER policy */    {      struct sched_param default_params;      default_params.sched_priority = 0;      __sched_setscheduler(THREAD_GETMEM(self, p_pid),                           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_do_exit(outcome, CURRENT_STACK_FRAME);}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;

⌨️ 快捷键说明

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