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

📄 thread.c

📁 多线程库
💻 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 + -