thread.C
上传用户:shtangtang
上传日期:2007-01-04
资源大小:167k
文件大小:13k
- //
- // 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_RESET
- thread_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 memory
- void *pthread::shalloc(size_t p_size)
- {
- return shared_mem::share.alloc(p_size, 0);
- }
- //
- // shdealloc
- //
- // deallocate shared memory
- void pthread::shdealloc(void *p_ptr)
- {
- shared_mem::share.dealloc(p_ptr);
- }