2005/5/9

     
 

core_mutex.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/sys/core_mutex.cpp,v 1.14 2005/03/07 14:02:13 kommer Exp $
#include <acdk.h>
#include "core_mutex.h"
#include "core_fastmutex.h"
#include "core_guard.h"
#include "core_system.h"
#include <errno.h>

#include "../SystemError.h"

#if defined(ACDK_HAS_PTHREAD_MUTEX_SETKIND)
extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *__attr,
                                         int __kind);
#endif //ACDK_HAS_PTHREAD_MUTEX_SETKIND

namespace acdk {
namespace lang {
namespace sys {

#if defined (POSIX_THREADS)
#include "core_ptherror.h"
#endif //defined (POSIX_THREADS)

core_mutex::core_mutex()
#if defined (POSIX_THREADS)
: _lockCount(0)
#if !defined(ACDK_HAS_PTHREAD_RECURSIVE_MUTEX)
,  _threadOwner(0)
#endif //!ACDK_HAS_PTHREAD_RECURSIVE_MUTEX
{
#elif defined (WIN32_THREADS)
{
  _mutex = ::CreateMutex(0, false, 0);
#endif
/FONT>
#if defined (POSIX_THREADS) && (defined(ACDK_HAS_PTHREAD_MUTEX_ATTR_SETTYPE) || defined(ACDK_HAS_PTHREAD_MUTEX_SETKIND))
  pthread_mutexattr_t pattr;
  int erg = pthread_mutexattr_init(&pattr);
  //### error handling
#if defined(ACDK_HAS_PTHREAD_MUTEX_ATTR_SETTYPE)
  //erg = pthread_mutexattr_settype(&pattr, PTHREAD_MUTEX_RECURSIVE);
#if !defined(ACDK_OS_DARWIN)
  erg = pthread_mutexattr_settype(&pattr, PTHREAD_MUTEX_ERRORCHECK);
#endif
/FONT>
#else
/FONT>
  //erg = pthread_mutexattr_setkind_np(&pattr, PTHREAD_MUTEX_ERRORCHECK_NP);
  erg = pthread_mutexattr_settype(&pattr, PTHREAD_MUTEX_RECURSIVE_NP);
  //### error handling
#endif
/FONT>
#if defined(ACDK_HAS_PTHREAD_RECURSIVE_MUTEX)
  erg = pthread_mutex_init(&_mutex, &pattr);
#endif
/FONT>
  //### error handling
#elif defined(ACDK_HAS_PTHREAD_MUTEX_SETKIND)
  pthread_mutexattr_setkind_np

#endif
/FONT>
}

core_mutex::~core_mutex()
{
#if defined (POSIX_THREADS) && defined(ACDK_HAS_PTHREAD_RECURSIVE_MUTEX)
  int erg = pthread_mutex_destroy(&_mutex);
  //### error handling
#elif defined (WIN32_THREADS)
  CloseHandle(_mutex);
#endif
/FONT>
}


void 
core_mutex::_lock(int count)
{
#if defined (POSIX_THREADS)
  if (core_system::inMain() == false)
    return;
#ifdef ACDK_HAS_PTHREAD_RECURSIVE_MUTEX
  while (count--)
  {
    int erg = pthread_mutex_lock(&_mutex);
    //###assert
  }
#else //ACDK_HAS_PTHREAD_RECURSIVE_MUTEX
  pthread_t tid = pthread_self();
  bool obtained = false;
  while (obtained == false) {
    core_lock_guard<core_fastmutex> lock(_internalMutex);
    if (_lockCount == 0) {
      _lockCount += count;
      _threadOwner = tid;
      obtained = true;
      _mutex.lock();
    } else if (_threadOwner == tid) {
      _lockCount += count;
      obtained = true;
    }
    if (obtained == false) {
      core_unlock_guard<core_fastmutex> unlockg(_internalMutex);
      core_lock_guard<core_fastmutex> lockg(_mutex);
    }
  }
#endif //ACDK_HAS_PTHREAD_RECURSIVE_MUTEX
#elif defined (WIN32_THREADS)
  if (WaitForSingleObject(_mutex, INFINITE) == WAIT_FAILED)
    sys::coreout << "WaitForSingleObject, _mutex, INFINITE) == WAIT_FAILED" << sys::eofl;
#endif
/FONT>
}


void 
core_mutex::lock()
{
  _lock(1);
}
 
void 
core_mutex::unlock()
{
#if defined (POSIX_THREADS)
  if (core_system::inMain() == false)
    return;
#ifdef ACDK_HAS_PTHREAD_RECURSIVE_MUTEX
    int erg = pthread_mutex_unlock(&_mutex);
  //### error handling
#else //ACDK_HAS_PTHREAD_RECURSIVE_MUTEX

  core_lock_guard<core_fastmutex> lock(_internalMutex);
  pthread_t tid = pthread_self();
  if (_lockCount <= 0 ) {
    THROW1(SystemError, RString("core_mutex::unlock(): underflow, count: ") + String::valueOf((int)_lockCount));
  }
  if (_threadOwner != tid) {
    THROW1(SystemError, "core_mutex::unlock(), not owner");
  }
  if (--_lockCount == 0) {
    _threadOwner = (pthread_t) 0;
    _mutex.unlock();
  }
#endif
/FONT>
#elif defined (WIN32_THREADS)
  ReleaseMutex(_mutex);
#endif
/FONT>
}
 
bool 
core_mutex::try_lock()
{
#if defined (POSIX_THREADS)
  if (core_system::inMain() == false)
    return true;
#ifdef ACDK_HAS_PTHREAD_RECURSIVE_MUTEX
    int erg = pthread_mutex_trylock(&_mutex);
    if (erg == EBUSY)
      return false;
    //### rorro
    return true;
#else //ACDK_HAS_PTHREAD_RECURSIVE_MUTEX

  bool obtained = false;
  pthread_t tid = pthread_self();
  core_lock_guard<core_fastmutex> lock(_internalMutex);
  if (_lockCount == 0) {
    _lockCount++;
    _threadOwner = tid;
    obtained = true;
    _mutex.lock();
  } else if (_threadOwner == tid) {
      _lockCount++;
      obtained = true;
  }
  return obtained;
#endif // ACDK_HAS_PTHREAD_RECURSIVE_MUTEX

#elif defined (WIN32_THREADS)
  DWORD result = WaitForSingleObject(_mutex, 0);
  if (result == WAIT_FAILED) {
    //THROW1(SystemError, "WaitForSingleObject");
    return false;
  }
  return result != WAIT_TIMEOUT;
#endif
/FONT>
}

static void foo()
{
#if _MSC_VER == 1300

   TLockGuard<core_mutex> tlock;
   core_mutex mutex;
   TLockGuard<core_mutex> tlock2(mutex);
#endif
/FONT>
}


} // namespace sys 
} // namespace lang 
} // namespace acdk