📄 thread.c
字号:
//// Copyright (c) 1999//// A C++ implementation of posix threads, using Linux clone system// calls.//// The implementation is identical to the implementation found in// the linuxthreads package, except that each thread is an object// here.//#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "thread.h"#include "threads/exception.h"#include "threads/signal_num.h"#include "threads/cond.h"#include "threads/stack.h"#include "shared.h"#include "thread_lists.h"#include "sig_handler.h"#include <cstdlib>#include <cerrno>extern "C" {# include <unistd.h># include <sys/ioctl.h># include <sys/types.h># include <sys/wait.h># include "cloning.h"};// We're hard coding this here, to ensure that stack sizes won't be// located with faulty sizes.namespace cpp_threads { template class signalling<Pthread>; struct process_arg { Pthread *s_pthread; void *s_arg; Semaphore *s_sem; }; void __program_on_exit(int, void *); SharedMemory SharedMemory::share; ThreadList ThreadList::__waiting_s; // threads waiting for SIG_RESET ThreadList ThreadList::__threads; // threads active. /** * This class is for the definiton of the main in a program. When * program starts, it has its own pid which is different from all * threads created afterwards. The thread manager, must also know * about this pid in its lists, for the main routine to be able * to perform certain functions, such as join with other threads. * * This class is provided for this purpose, and will only be * implemented in the resulting program, and does not reside in * the library. * * @short The main program thread. * @author Orn Hansen <oe.hansen@gamma.telenordia.se> */ class __program : public Pthread { public: __program() : Pthread(getpid()) { on_exit( program_on_exit,(void *)0 ); } ~__program() { Pthread::debug("main program destroyed"); sys::exit(retcode()); } static void program_on_exit(int, void *); int thread(void *) { return 0; }; }; // // This is a static reference pointer to the main // program. __program __main_program_thread; void __program::program_on_exit(int retcode_p, void *arg_p) { if( getpid() == __main_program_thread.id() ) { Pthread::debug("__program_on_exit(%d,%x)",retcode_p,arg_p); __main_program_thread.cleanup(); } } // // Global signal handler, for those signals that will // terminate the application. void Pthread::sig_terminate(int sig_p) { Pthread *th = ThreadList::__threads.self(); Pthread::debug("terminating signal %d",sig_p); if( th ) th->exit(-1); else sys::exit(-1); } // // Global signal handler, that is used to delete all child // processes from the list. void Pthread::sig_childexit(int sig_p) { Pthread *th; int stat,pid; while( true ) { pid = wait3( &stat,__WCLONE|WNOHANG|WUNTRACED,0 ); Pthread::debug("s_child from %d",pid); if( pid > 0 ) { th = ThreadList::__threads.ptr(pid); if( th ) { if( WIFEXITED(stat) ) th->state( Pthread::p_exited_e ); else if( WIFSIGNALED(stat) ) th->state( Pthread::p_terminated_e ); else if( WIFSTOPPED(stat) ) { th->state( Pthread::p_terminated_e ); Pthread::debug(" - Stopped by signal %d",WSTOPSIG(stat)); } else continue; ThreadList::__threads.remove(pid); } } else break; } } // // Global signal handler, for SIGUSR1 which in our case is // CPPTHREAD_SIG_RESET. The thread, that owns the signal handler // is signalled and removed from the list. void Pthread::sig_handler(int sig_p) { Pthread *th = ThreadList::__threads.self(); if ( th ) { if( th->isSet(Pthread::signal_jmp_e) ) { Pthread::debug("jumping jack flash"); th->jump( Pthread::signal_jmp_e ); } else { Pthread::debug("reset signal"); th->signal(sig_p); ThreadList::__waiting_s.remove(th->id()); } } } // // Global signal handler, for SIGUSR2 which in our case is // CPPTHREAD_SIG_CANCEL. The thread is checked, if cancel is // enabled and active. If so, the thread is stopped on an // asynchronous cancel type, or a jump made to the users // specified jump location. void Pthread::sig_cancel(int sig_p) { Pthread *th = ThreadList::__threads.self(); if ( th ) { Pthread::debug("cancel"); if (th->canceled() && th->cancelstate() == Pthread::cancel_enable_e) { if (th->canceltype() == Pthread::cancel_asynchronous_e) th->exit( CPPTHREAD_CANCELED ); th->jump( Pthread::cancel_jmp_e ); } } else Pthread::debug("No such thread"); } // // Stop or suspend a running process... done from an outside // process. void Pthread::sig_stop(int sig_p) { Pthread *th = ThreadList::__threads.self(); if ( th ) { Pthread::debug("__sig_stop"); th->suspend(); } } // // A function to initialize the signal handlers, for each // thread. void Pthread::signal_init() { sigset_t mask; struct sigaction sa; Pthread::debug("__signal_init()"); sigemptyset(&mask); sigaddset(&mask,s_continue); sigprocmask(SIG_SETMASK,&mask,0); sa.sa_handler = sig_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaddset(&sa.sa_mask,s_child); sys::sigaction(CPPTHREAD_SIG_RESTART, &sa, NULL); sa.sa_handler = sig_cancel; sys::sigaction(s_quit, &sa, NULL); sa.sa_handler = sig_stop; sys::sigaction(s_keyboard, &sa, NULL); sa.sa_handler = sig_terminate; sigemptyset(&sa.sa_mask); if( CPPTHREAD_SIG_CANCEL != s_quit ) sys::sigaction(s_quit, &sa, NULL); sys::sigaction(s_bus_err, &sa, NULL); sys::sigaction(s_fpe, &sa, NULL); sys::sigaction(s_terminate, &sa, NULL); sys::sigaction(s_hangup, &sa, NULL); sys::sigaction(s_abort, &sa, NULL); sys::sigaction(s_interrupt, &sa, NULL); sa.sa_handler = sig_childexit; sys::sigaction(s_child, &sa, NULL); } // // This routine, is called directly from __clone() system // call. It initalizes the thread, and calls the Pthread.thread() // function, with the given argument. int Pthread::__routine(void *arg_p) { process_arg *ap; Pthread *p; Semaphore *sem; int retcode; ap = (process_arg *)arg_p; p = ap->s_pthread; arg_p = ap->s_arg; sem = ap->s_sem; delete ap; while( ThreadList::__threads.self() == 0 ) sched_yield(); if ( sem ) { sem->wait(); // A class may post to the Semaphore, as the last operation // in the constructor. By yeilding twice, perhaps a usleep ? // should provide enough time for the constructor to finish. sched_yield(); sched_yield(); } p->state( Pthread::p_running_e ); p->schedule( p->_attributes ); retcode = p->thread(arg_p); Pthread::debug("return(%d)",retcode); p->exit( retcode ); /* we never get to this point */ return 0; } // // class Pthread // // This class is thought as a superclass to each thread, that is // wanted in a program. // // default constructor. // // create a cloned process, and mark it with 0 as argument. Pthread::Pthread(Semaphore *sem_p,size_t stackPages_p) { invoke((void *)0,sem_p,stackPages_p); } // // constructor - with argument // // create a cloned process, and pass to it the pointer given // as argument. Pthread::Pthread(void *arg_p,Semaphore* sem_p,size_t stackPages_p) { invoke(arg_p,sem_p,stackPages_p); } // // constructor - with a process id. // // create a thread description of the process, given by id, if // it doesn't already exist on the threads list. Pthread::Pthread(int id_p) { if ( ThreadList::__threads.ptr(id_p) ) return; Pthread::debug("envelope %d",id_p); varinit(); _tid = id_p; _ppid = getppid(); _sp = 0; signal_init(); ThreadList::__threads.pushBack(this); } // // varinit - private // // initialize the variables associated with the class with // default values. void Pthread::varinit() { debug("scope %d",_attributes.a_scope); _tid = -1; _errno = 0; _priority = 0; _signal = 0; _joining = 0; _cancel_jmp = 0; _signal_jmp = 0; _retval = (void *)0; _retcode = 0; _cancelstate = cancel_enable_e; _canceltype = cancel_asynchronous_e; _state = p_stopped_e; } // // invoke - private // // create a stack for the thread and call the clone function with // __routine() as the starting point. void Pthread::invoke(void *arg_p,Semaphore *sem_p,size_t stackPages_p) { process_arg *ap = 0; varinit(); if ( stackPages_p < 8 ) stackPages_p = 8; ap = new process_arg; _sp = new ThreadStack(stackPages_p*STACK_PAGE_SIZE); if ( _sp && ap ) { if( sem_p == 0 ) sem_p = new Semaphore; ap->s_pthread = this; ap->s_arg = arg_p; ap->s_sem = _runner = sem_p; _ppid = getpid(); Pthread::debug("cloning"); _tid = beginthread(__routine, _sp->top(), (void *)ap); Pthread::debug("clone is %d",_tid); if ( _tid < 0 ) exception::fatal( EACCES ); else if( _tid > 0 ) ThreadList::__threads.pushBack(this); } else exception::fatal( ENOMEM ); } // // destructor // // if the process is running, terminate it. then free memory and // remove it from the list of threads. Pthread::~Pthread() { Pthread::debug("object %d delete",id()); if( getpid() != id() && !terminated() ) { Pthread::debug("need to terminate state %d",state()); kill(id(),s_quit); usleep(100); } Pthread::debug("remove from lists"); ThreadList::__threads.remove( _tid ); ThreadList::__waiting_s.remove( _tid ); Pthread::debug("destroy stack"); if ( _sp ) delete _sp; Pthread::debug("object deleted"); } void Pthread::cleanup() { int n = 0, status; Pthread *th = ThreadList::__threads.self(); Pthread *child=ThreadList::__threads.child(th->id()); debug("cleanup()"); for( ;child;child=ThreadList::__threads.nextChild(child) ) if ( !child->detached() && !child->canceled() && !child->terminated() ) { debug("cleanup %d in state %d",child->id(),child->state()); child->set(cancel_enable_e); child->set(cancel_asynchronous_e); child->cancel(); waitpid(child->id(),&status,WUNTRACED); } SharedMemory::share.cleanup(); debug("cleanup() %d done.",n); }; void Pthread::exit_child(int retcode_p) { ThreadList::__threads.remove( getpid() ); ThreadList::__waiting_s.remove( getpid() ); kill( getppid(),s_child ); ::_exit( retcode_p ); } // // state // // query the state of the process Pthread::thread_state Pthread::state() { return _state; } // // state // // set the state of the process Pthread::thread_state Pthread::state(thread_state state_p) { thread_state old_state = _state; if( getpid() == id() || getpid() == ppid() ) _state = state_p; return old_state; } // // run // // put the process into running state void Pthread::run() { if( _runner ) _runner->post(); } // // retcode // // returns with the return code, that was set by the system. int Pthread::retcode() { return _retcode; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -