2005/5/9

     
 

core_semaphore.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_semaphore.cpp,v 1.16 2005/03/07 13:47:28 kommer Exp $

#include <acdk.h>
#include "core_semaphore.h"
#include "core_tick.h"
#include "../SystemError.h"
#include "../Thread.h"
#include <errno.h>
#if defined(ACDK_OS_DARWIN)
//# include <mach/shed.h>
# include <mach/mach_init.h>
#endif
/FONT>
namespace acdk {
namespace lang {
namespace sys {


//#define DOUT(msg) sys::coreout << "TID: " << ThreadID::getCurrentThreadID().getId()  << ": " << msg << sys::eofl
#define DOUT(msg)



//  explicit
core_semaphore::core_semaphore(int initcount/* = 0*/, int maxcount/* = -1*/)
{
  DOUT("core_semaphore::core_semaphore(" << (void*)this << ", int initcount = " << initcount << ", int maxcount = " << maxcount << ")");
#if defined(WIN32_THREADS)
  if (maxcount == -1)
    maxcount = 1000000;
  _sema = CreateSemaphore(0, initcount, maxcount, 0);
  if (_sema == NULL)
    THROW1(SystemError, "CreateSemaphore failed");
#endif
/FONT>
#if defined (POSIX_THREADS)
# if defined(ACDK_OS_DARWIN)
  semaphore_create(current_task(), &_sema, SYNC_POLICY_FIFO, initcount);
#else
/FONT>
   ACDK_SYS_CALL3(sem_init, &_sema, 0, initcount, == 0);
#endif
/FONT>
#endif  
}

core_semaphore::~core_semaphore()
{
  DOUT("core_semaphore::~core_semaphore(" << (void*)this << ")");
#if defined(WIN32_THREADS)
  CloseHandle(_sema);
#endif
/FONT>
#if defined (POSIX_THREADS)
# if defined (ACDK_OS_DARWIN)
  semaphore_destroy(current_task(), _sema);
#else
/FONT>
  ACDK_SYS_CALL1(sem_destroy, &_sema, == 0);
#endif
/FONT>
#endif  
}

bool
core_semaphore::up(int count/* = 1*/, int* prevcount/* = 0*/)
{
  DOUT("core_semaphore::up(" << (void*)this << "count=" << count << ")");
#if defined(WIN32_THREADS)
  long p;
  bool ret = ReleaseSemaphore(_sema, count, &p) == TRUE;
  if (ret == false || GetLastError() == ERROR_TOO_MANY_POSTS)
  {
    return false;
  }
  if (prevcount != 0)
    *prevcount = p;
  return ret;
#endif
/FONT>
#if defined (POSIX_THREADS)
#if defined(ACDK_OS_DARWIN)

#else
/FONT>
  int prevval;
  ACDK_SYS_CALL2(sem_getvalue, &_sema, &prevval, == 0);
  for (int i = 0; i < count; ++i)
  {
    ACDK_SYS_CALL1(sem_post, &_sema, == 0);
    //int ret = sem_post(&_sema);
    //if (ret != 0)
    //  sys::coreout << "sem_post() return " << ret << sys::eofl;
  }
  if (prevcount != 0)
    *prevcount = prevval;
  return true;
#endif
/FONT>
#endif  
}


bool 
core_semaphore::down(int millisecs/* = -1*/)
{
  DOUT("core_semaphore::up(" << (void*)this << "ms=" << millisecs << ")");
#if defined(WIN32_THREADS)
  if (millisecs == -1)
    millisecs = INFINITE;
  DWORD res = WaitForSingleObject(_sema, millisecs);
  if (res == WAIT_FAILED) 
  { 
    THROW1(SystemError, "WaitForSingleObject failed");
  }
  return res == WAIT_OBJECT_0;
#endif
/FONT>
#if defined (POSIX_THREADS)
#if defined(ACDK_OS_DARWIN)

#else
/FONT>
#ifndef EAGAIN
# define EAGAIN 11
#endif
/FONT>
  if (millisecs == -1) {
    ACDK_SYS_CALL1(sem_wait, &_sema, == 0);
    return true;
  } else {
    tick_t start = core_tick::now();
    while (true) 
    {
      int ret = sem_trywait(&_sema);
      if (ret == 0)
	      return true;
      if (ret != EAGAIN)
	      THROW1(SystemError, "sem_trywait failed");
      ::acdk::lang::Thread::sleep(millisecs / 10);
      tick_t now = core_tick::now();
      if (core_tick::TicksPerMillisecond == 0) {
	if ((now - start) / core_tick::TicksPerSecond >= millisecs / 1000)
	  return false;
      } else {
	if ((now - start) / core_tick::TicksPerMillisecond >= millisecs)
	  return false;
      }
    }
  }
#endif
/FONT>
#endif  
}

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