- //
- // class mutex
- //
- // Mutes is a semaphore, that can be used by two threads to mutually
- // exclude the other. To ensure uniqe access to memory.
- #include <thread_mutex.h>
- #include <thread_lists.h>
- #include "wait_queue.h"
- #include "shared.h"
- extern "C" {
- # include <errno.h>
- # include <unistd.h>
- };
- char *mutex::m_project = 0;
- mutex::mutex(attributes::scope p_scope)
- {
- init( p_scope );
- }
- mutex::mutex()
- {
- init( attributes::process_private );
- }
- mutex::~mutex()
- {
- if ( _m ) {
- delete m_waiting;
- if ( m_scope == attributes::process_private )
- delete _m;
- else
- shared_mem::share.dealloc( _m );
- _m = 0;
- }
- }
- void mutex::init(attributes::scope p_scope)
- {
- m_id = -1;
- if ( p_scope == attributes::process_private ) {
- _m = new storage;
- _m->m_magic = 0;
- } else {
- m_id = shared_mem::share.create_proj( m_project );
- _m = (storage *)shared_mem::share.alloc( sizeof(storage),m_id );
- assert( _m != (storage *)-1 );
- }
- if ( _m->m_magic != 0x212612 ) {
- _m->m_kind = fast;
- _m->m_count = 0;
- _m->m_owner = -1;
- _m->m_magic = 0x212612;
- }
- m_waiting = new wait_queue( m_id );
- m_scope = p_scope;
- }
- attributes::scope mutex::scope()
- {
- return m_scope;
- }
- void mutex::release()
- {
- _m->m_owner = 0;
- _m->m_count = 0;
- }
- int mutex::acquire()
- {
- _m->m_owner = getpid();
- _m->m_count++;
- return 0;
- }
- //
- // kind
- //
- // set the mutex kind.
- int mutex::kind(mutex_kind _kind)
- {
- if (_kind != mutex::recursive && _kind != mutex::fast)
- return EINVAL;
- _m->m_kind = _kind;
- return 0;
- }
- //
- // kind
- //
- // get the mutex kind.
- int mutex::kind()
- {
- return _m->m_kind;
- }
- //
- // trylock
- //
- // try and lock the mutex.
- //
- // return
- // EBUSY - the mutex is locked by another.
- // EINVAL - the mutex is of an unknown kind.
- // 0 - successful.
- int mutex::trylock()
- {
- int rval = EBUSY;
- _m->m_spinlock.acquire();
- switch(_m->m_kind) {
- case mutex::fast:
- if ( _m->m_count == 0 )
- rval = acquire();
- break;
- case mutex::recursive:
- if (_m->m_count == 0 || _m->m_owner == getpid())
- rval = acquire();
- break;
- case mutex::errorcheck:
- if ( _m->m_count == 0 )
- rval = acquire();
- else
- if ( _m->m_owner == getpid() )
- rval = EDEADLK;
- break;
- default:
- rval = EINVAL;
- break;
- }
- _m->m_spinlock.release();
- return rval;
- }
- //
- // lock
- //
- // Try and lock the mutex. If unsuccessful, suspend the calling
- // process, until the mutex is available.
- int mutex::lock()
- {
- int rval = EBUSY;
- while(rval == EBUSY) {
- if ((rval = trylock()) == EBUSY)
- m_waiting->suspend_me();
- }
- return rval;
- }
- //
- // unlock
- //
- // unlock the mutex, and restart any threads, that are waiting
- // on it.
- int mutex::unlock()
- {
- int rval = 0;
- _m->m_spinlock.acquire();
- switch(_m->m_kind) {
- case mutex::fast:
- if ( _m->m_owner == getpid() )
- release();
- else
- rval = EBUSY;
- break;
- case mutex::recursive:
- if ( _m->m_owner == getpid() ) {
- if (--_m->m_count <= 1)
- release();
- } else
- rval = EBUSY;
- break;
- case mutex::errorcheck:
- if ( _m->m_count == 0 || _m->m_owner != getpid() )
- rval = EPERM;
- else
- release();
- break;
- default:
- rval = EINVAL;
- }
- _m->m_spinlock.release();
- if ( rval == 0 )
- m_waiting->wake_up();
- return rval;
- }
- //
- // project_part
- //
- // change the project part
- void
- mutex::project_part(const char *p_part)
- {
- if ( m_project == 0 )
- m_project = new char[80];
- m_project[0] = 0;
- if ( p_part )
- strcpy( m_project,p_part );
- }