📄 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.//#include "Config.h"#undef __THREADS_MAIN#include "thread.h"#include "thread_lists.h"#include "thread_signal_num.h"#include "thread_cond.h"#include "shared.h"extern "C" {# include <errno.h># include <unistd.h># include <mcheck.h># include "cloning.h"};struct p_arg { pthread *_pthread; void *_arg;};void __program_on_exit(int, void *);static void __sig_terminate(int);/** * 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()) { struct sigaction sa; // The following signals will terminate the program, // we make sure, that they will also remove shared // memory page references, on exit. sa.sa_handler = __sig_terminate; sigemptyset(&sa.sa_mask); sigaction(s_terminate, &sa, NULL); sigaction(s_kill, &sa, NULL); sigaction(s_abort, &sa, NULL); sigaction(s_quit, &sa, NULL); sigaction(s_interrupt, &sa, NULL); sigaction(s_bus_err, &sa, NULL); sigaction(s_fpe, &sa, NULL); on_exit( __program_on_exit,(void *)0 ); }; ~__program() { } void cleanup() { thread_list::iterator i = thread_list::__threads.begin(); for( ;i!=thread_list::__threads.end();i++ ) if ( getpid() != (*i)->id() && !(*i)->detached() && !(*i)->canceled() && !(*i)->terminated() ) { (*i)->set(cancel_enable); (*i)->set(cancel_asynchronous); (*i)->cancel(); } shared_mem::share.cleanup(); }; int thread(void *) { return 0; };};shared_mem shared_mem::share;thread_list thread_list::__waiting_s; // threads waiting for SIG_RESETthread_list thread_list::__threads; // threads active.__program __main_program_thread;void __program_on_exit(int p_retcode, void *p_arg){ __main_program_thread.cleanup();}//// Global signal handler, for those signals that will// terminate the application.static void __sig_terminate(int __sig){#ifdef DEBUG cout << "terminating signal " << __sig << endl;#endif exit(-1);}//// Global signal handler, for SIGUSR1 which in our case is// PTHREAD_SIG_RESET. The thread, that owns the signal handler// is signalled and removed from the list.static void __sig_handler(int _sig){ thread_list::iterator i = thread_list::__waiting_s.locate(getpid()); if (i != thread_list::__waiting_s.end()) { (*i)->signal(_sig); thread_list::__waiting_s.erase(i); }}//// Global signal handler, for SIGUSR2 which in our case is// PTHREAD_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.static void __sig_cancel(int _sig){ pthread *th = thread_list::__threads.self(); if (th != 0) { if (th->canceled() && th->cancelstate() == pthread::cancel_enable) { if (th->canceltype() == pthread::cancel_asynchronous) th->exit(PTHREAD_CANCELED); th->jump(pthread::cancel_jmp); } }}//// A function to initialize th signal handlers, for each// thread.void __signal_init(){ struct sigaction sa; sa.sa_handler = __sig_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(PTHREAD_SIG_RESTART, &sa, NULL); sa.sa_handler = __sig_cancel; sa.sa_flags = 0; sigaction(PTHREAD_SIG_CANCEL, &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.static int __routine(void *_arg){ p_arg *ap; pthread *_p; int retcode; ap = (p_arg *)_arg; _p = ap->_pthread; _arg = ap->_arg; delete ap; __signal_init(); retcode = _p->thread(_arg); _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(){ invoke((void *)0);}//// constructor - with argument//// create a cloned process, and pass to it the pointer given// as argument.pthread::pthread(void *_arg){ invoke(_arg);}//// 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){ if (thread_list::__threads.locate(_id) != thread_list::__threads.end()) return; varinit(); p_id = _id; p_sp = 0; __signal_init(); thread_list::__threads.push_back(this);}//// varinit - private//// initialize the variables associated with the class with// default values.void pthread::varinit(){ p_attributes.a_scope = attributes::process_private; p_attributes.a_state = attributes::attr_joinable; p_id = -1; p_errno = 0; p_priority = 0; p_signal = 0; p_joining = 0; p_retval = (void *)0; p_retcode = 0; p_cancelstate = cancel_enable; p_canceltype = cancel_asynchronous; p_canceled = false; p_terminated = false; p_exited = false;}//// 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_arg *ap; varinit(); ap = new p_arg; p_sp = new char[ 4*PAGE_SIZE ]; if ( p_sp ) { ap->_pthread = this; ap->_arg = _arg; p_id = do_clone(__routine, (void *)ap, (void **)&p_sp); if ( p_id < 0 ) error( EACCES ); } else error( ENOMEM ); thread_list::__threads.push_back(this);}//// destructor//// if the process is running, terminate it. then free memory and// remove it from the list of threads.pthread::~pthread(){ if ( !terminated() ) { cancel(); while( !terminated() ) __sched_yield(); } thread_list::__threads.remove( p_id ); thread_list::__waiting_s.remove( p_id ); if ( p_sp ) delete p_sp;}//// retcode//// returns with the return code, that was set by the system.int pthread::retcode(){ return p_retcode;}//// detached//// return if the thread is detached, or joinable.bool pthread::detached() const{ return p_attributes.a_state == attributes::attr_detached;}//// joinable//// the opposite of detached.bool pthread::joinable() const{ return p_attributes.a_state == attributes::attr_joinable;}//// restart//// send a restart signal to the process associated with this thread.void pthread::restart(){ kill(p_id, PTHREAD_SIG_RESTART);}//// suspend//// suspend the process, until a restart signal is received.//// the thread suspended, is the thread associated with the// calling process.void pthread::suspend(){ pthread *th = thread_list::__threads.self(); sigset_t mask; if (th != NULL) { thread_list::__waiting_s.push_back(th); sigprocmask(SIG_SETMASK, NULL, &mask); sigdelset(&mask, PTHREAD_SIG_RESTART); do { th->signal(0); sigsuspend(&mask); } while(th->signal() != PTHREAD_SIG_RESTART); }}//// suspend_with_cancelation//// suspend the thread, associated with the calling process// until a signal is received or it is canceled.void pthread::suspend_with_cancelation(){ pthread *th = thread_list::__threads.self(); sigset_t mask; sigjmp_buf jmpbuf; if (th != NULL) { thread_list::__waiting_s.push_back(th); sigprocmask(SIG_SETMASK, NULL, &mask); sigdelset(&mask, PTHREAD_SIG_RESTART); if (sigsetjmp(jmpbuf, 0) == 0) { th->set(pthread::cancel_jmp, &jmpbuf); if (!(th->canceled() && th->cancelstate() == pthread::cancel_enable)) { do { th->signal(0); sigsuspend(&mask); } while(th->signal() != PTHREAD_SIG_RESTART); } th->set(pthread::cancel_jmp, 0); } else { sigaddset(&mask, PTHREAD_SIG_RESTART); sigprocmask(SIG_SETMASK, &mask, NULL); } }}//// signal//// set the p_signal variable to the given value. Can only be// done if called from the process that the thread is associated// with. If called from a different process, the given signal// is sent to the process.int pthread::signal(int _sig){ if (getpid() == p_id) p_signal = _sig; else kill(p_id,_sig); return signal();}//// cancel//// send a cancel signal to the process assiated with thread. Setting// the cancelation flag.void pthread::cancel(){ set(pthread::set_canceled, true); kill(p_id, PTHREAD_SIG_CANCEL);}//// running//// return a true value, if the process associated with the thread// can be found on the schedulers list.bool pthread::running(){ return (sched_getscheduler(p_id) != -1);}//// exit//// perform an exit of the process. This means marking it as// terminated and signalling any processes that are joining on// it.void pthread::exit(void *_rval){ int joining = 0; if (getpid() == p_id) { p_canceled = false; p_spinlock.acquire(); p_retval = _rval; p_terminated = true; joining = p_joining; p_spinlock.release(); if (joining) thread_list::__threads.restart(joining); _exit(0); }}//// exit//// perform an exit of the process. This means marking it as// terminated and signalling any processes that are joining on// it.void pthread::exit(int _retcode){ int joining = 0; if (getpid() == p_id) { p_canceled = false; p_spinlock.acquire(); p_retcode = _retcode; p_terminated = true; joining = p_joining; p_spinlock.release(); if (joining) thread_list::__threads.restart(joining); _exit( _retcode ); }}//// set - booleans//// set any of the boolean values, terminated exited canceled or// detached.void pthread::set(booleans _set, bool _val){ switch(_set) { case pthread::set_terminated: p_terminated = _val; break; case pthread::set_detached: if ( _val ) p_attributes.a_state = attributes::attr_detached; else p_attributes.a_state = attributes::attr_joinable; break; case pthread::set_exited: p_exited = _val; break; case pthread::set_canceled: p_canceled = _val; break; case pthread::set_private: break; }}//// set - jumps//// set the signalling jumps, signal or cancel. void pthread::set(jumps _typ, sigjmp_buf *_jbuf){ switch(_typ) { case cancel_jmp: p_cancel_jmp = _jbuf; break; case signal_jmp: p_signal_jmp = _jbuf; break; }}//// join//// suspend the calling process (thread), until the thread// owning the call has terminated.int pthread::join(){ thread_list::iterator i = thread_list::__threads.locate(getpid()); if ( p_id == getpid() ) return EDEADLK; if ( i == thread_list::__threads.end() ) return ESRCH; if ( detached() || joining() != 0 || !joinable() ) return EINVAL; if (!terminated()) { joining(getpid()); (*i)->suspend_with_cancelation(); if (canceled() && cancelstate() == pthread::cancel_enable) { joining(0); exit(PTHREAD_CANCELED); } } return 0;}//// jump//// do a jump, to either signal or cancel locations. If they// are specified.void pthread::jump(jumps _typ){ sigjmp_buf *jmp_buf = 0; switch(_typ) { case cancel_jmp: jmp_buf = p_cancel_jmp; break; case signal_jmp: jmp_buf = p_signal_jmp; break; } if (jmp_buf != 0) siglongjmp(*jmp_buf, 1);}//// set_project//// This is a way for the user to communicate with the// shared memory control.void pthread::set_project(const char *p_name){ shared_mem::share.change_proj( p_name );}//// set_permission//// Set the project permission attributes.void pthread::set_permission(int p_perm){ shared_mem::share.change_perm( p_perm );}//// shalloc//// allocate shared memoryvoid *pthread::shalloc(size_t p_size){ return shared_mem::share.alloc(p_size, 0);}//// shdealloc//// deallocate shared memoryvoid pthread::shdealloc(void *p_ptr){ shared_mem::share.dealloc(p_ptr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -