manager.c
来自「Axis 221 camera embedded programing inte」· C语言 代码 · 共 906 行 · 第 1/3 页
C
906 行
/* 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 *//* mods for uClibc: getpwd and getpagesize are the syscalls */#define __getpid getpid#define __getpagesize getpagesize#include <features.h>#define __USE_GNU#include <errno.h>#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"#include "debug.h" /* PDEBUG, added by StS *//* poll() is not supported in kernel <= 2.0, therefore is __NR_poll is * not available, we assume an old Linux kernel is in use and we will * use select() instead. */#include <sys/syscall.h>#ifndef __NR_poll# define USE_SELECT#endif/* 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;/* 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;/* 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. */static inline pthread_descr thread_segment(int seg){ return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE) - 1;}/* Flag set in signal handler to record child termination */static volatile int terminated_children = 0;/* Flag set when the initial thread is blocked on pthread_exit waiting for all other threads to terminate */static int main_thread_exiting = 0;/* Counter used to generate unique thread identifier. Thread identifier is pthread_threads_counter + segment. */static pthread_t pthread_threads_counter = 0;/* 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);static void pthread_reap_children(void);static void pthread_kill_all_threads(int sig, int main_thread_also);/* The server thread managing requests for thread creation and termination */int __pthread_manager(void *arg){ int reqfd = (int) (long int) arg;#ifdef USE_SELECT struct timeval tv; fd_set fd;#else struct pollfd ufd;#endif 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_errnop = &__pthread_manager_thread.p_errno; __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;#ifdef __UCLIBC_HAS_XLOCALE__ /* Initialize thread's locale to the global locale. */ __pthread_manager_thread.locale = __global_locale;#endif /* __UCLIBC_HAS_XLOCALE__ */ /* 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);#ifndef USE_SELECT ufd.fd = reqfd; ufd.events = POLLIN;#endif /* Enter server loop */ while(1) {#ifdef USE_SELECT tv.tv_sec = 2; tv.tv_usec = 0; FD_ZERO (&fd); FD_SET (reqfd, &fd); n = select (reqfd + 1, &fd, NULL, NULL, &tv);#elsePDEBUG("before poll\n"); n = poll(&ufd, 1, 2000);PDEBUG("after poll\n");#endif /* 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 */#ifdef USE_SELECT if (n == 1)#else if (n == 1 && (ufd.revents & POLLIN))#endif {PDEBUG("before __libc_read\n"); n = __libc_read(reqfd, (char *)&request, sizeof(request));PDEBUG("after __libc_read, n=%d\n", n); ASSERT(n == sizeof(request)); switch(request.req_kind) { case REQ_CREATE:PDEBUG("got REQ_CREATE\n"); 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);PDEBUG("restarting %d\n", request.req_thread); restart(request.req_thread); break; case REQ_FREE:PDEBUG("got REQ_FREE\n"); pthread_handle_free(request.req_args.free.thread_id); break; case REQ_PROCESS_EXIT:PDEBUG("got REQ_PROCESS_EXIT from %d, exit code = %d\n", request.req_thread, request.req_args.exit.code); pthread_handle_exit(request.req_thread, request.req_args.exit.code); break; case REQ_MAIN_THREAD_EXIT:PDEBUG("got REQ_MAIN_THREAD_EXIT\n"); 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:PDEBUG("got REQ_POST\n"); __new_sem_post(request.req_args.post); break; case REQ_DEBUG:PDEBUG("got REQ_DEBUG\n"); /* 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) {PDEBUG("about to call raise(__pthread_sig_debug)\n"); raise(__pthread_sig_debug); } 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; } } }}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; /* Initialize special thread_self processing, if any. */#ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr);#endifPDEBUG("\n"); /* 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),
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?