/**********************************************************************
 * Copyright (c) 2005, 2006 Scapa Technologies Limited and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: mutex.c,v 1.2 2006/10/26 22:40:21 kcallaghan Exp $
 * 
 * Contributors: 
 * Scapa Technologies Limited - Initial API and implementation
 **********************************************************************/

/***********************************************************************
 *
 * File: Mutex.c
 * Overview: The following code provides a wrapper to the Win32 
 *                                API routines for mutex operations. Implicit in the 
 *                               routines is that the Mutex struct has been allocated.
 *                               This is to ensure data is thread specific, and not
 *                               simply local to functions.
 ***********************************************************************/

#include "system.h"

/***********************************************************************
 * Function: XMutexCreate
 * Purpose: Creates a mutex variable. The user sees the mutex
 *                               as a pointer to a Mutex structure. The function calls 
 *                               the O/S and initialises the Mutex structure.
 * Parameters: Mutex *, a pointer to Mutex struct. Defined in 
 *                                        Mutex.h.
 * Returns: int, MUTEX_SUCCESS on successful creation, 
 *                              MUTEX_FAILURE otherwise.
 ***********************************************************************/
int XMutexCreate(XMutex *mutex)
{
#ifdef WIN32
#ifdef MUTEX_HANDLE
    mutex->handle = CreateMutex(NULL, FALSE, NULL); /* default security, not claimed, no name */

    if (! mutex->handle) 
    {
      return XMUTEX_ERROR_CREATE;
    }
#else
	InitializeCriticalSection(&mutex->cs);
#endif
#endif
#if defined(LINUX) || defined(SOLARIS) || defined(AIX) || defined(USS) || defined(HPUX) || defined(LINUX_S390) || defined(SOLARIS_I386)
  if (pthread_mutex_init(&mutex->mutex, NULL) != 0)
  {
    return FAILURE;
  }
#endif

    return SUCCESS;
}
                

/***********************************************************************
 * Function: XMutexClaim
 * Purpose: This function attempts to exclusively claim the mutex
 *                               if it is not sucessful it will block the calling thread. Once
 *                               the mutex is available again this thread may be scheduled
 *                               and hence allowed to claim it.
 * Parameters: Mutex *, a pointer to a Mutex struct.
 * Returns: int, MUTEX_SUCCESS on successful claim,
 *                              MUTEX_FAILURE on otherwise.
 ***********************************************************************/
int XMutexClaim(XMutex *mutex)
{
#ifdef WIN32
#ifdef MUTEX_HANDLE
    DWORD result;

    result = WaitForSingleObject(mutex->handle, INFINITE); /* no timed wait */

    if (result != WAIT_OBJECT_0) 
    {
      return XMUTEX_ERROR_CLAIM;
    }
#else
	EnterCriticalSection(&mutex->cs);
#endif
#endif
#if defined(LINUX) || defined(SOLARIS) || defined(AIX) || defined(USS) || defined(HPUX) || defined(LINUX_S390) || defined(SOLARIS_I386)
  if (pthread_mutex_lock(&mutex->mutex) != 0)
  {
    return FAILURE;
  }
#endif

    return SUCCESS;
}

/***********************************************************************
 * Function: XMutexRelease
 * Purpose: Allows the thread that has claimed a mutex to release
 *                               it. The thread must have successfully called MutexClaim
 *                              before calling this function.
 * Parameters: Mutex *, pointer to a Mutex struct.
 * Returns: int, MUTEX_SUCCESS is successful release,
 *                              MUTEX_FAILURE otherwise.
 ***********************************************************************/
int XMutexRelease(XMutex *mutex)
{
#ifdef WIN32
#ifdef MUTEX_HANDLE
  BOOL released;
    
  released = ReleaseMutex(mutex->handle);  /* release the mutex */

  if (released != TRUE) 
  {
    return XMUTEX_ERROR_RELEASE;
  }
#else
  LeaveCriticalSection(&mutex->cs);
#endif
#endif
#if defined(LINUX) || defined(SOLARIS) || defined(AIX) || defined(USS) || defined(HPUX) || defined(LINUX_S390) || defined(SOLARIS_I386)
  if (pthread_mutex_unlock(&mutex->mutex) != 0)
  {
    return FAILURE;
  }
#endif
  return SUCCESS;
}

/***********************************************************************
 * Function: XMutexDelete
 * Purpose: Notifies the O/S that the thread is no longer using 
 *                               the mutex. Note that all threads using this mutex 
 *                               must call this routine before the O/S deallocates
 *                               the associated resources. Once called this routine
 *                               will set event.deleted to TRUE.
 * Parameters: Mutex *, pointer to a Mutex struct.
 * Returns: int, MUTEX_SUCCESS if successful deletion,
 *                              MUTEX_FAILURE otherwise.
 ***********************************************************************/
int XMutexDelete(XMutex *mutex)
{
#ifdef WIN32
#ifdef MUTEX_HANDLE
    BOOL closed;
   
    /* decrement the number of references to kernel object, 
    *  and free mutex struct, setting mutex to NULL */
    
    closed = CloseHandle(mutex->handle); 

    if (! closed)
    {
      return XMUTEX_ERROR_DELETE;
    } 
#else
	DeleteCriticalSection(&mutex->cs);
#endif
#endif
#if defined(LINUX) || defined(SOLARIS) || defined(AIX) || defined(USS) || defined(HPUX) || defined(LINUX_S390) || defined(SOLARIS_I386)
  if (pthread_mutex_destroy(&mutex->mutex) != 0)
  {
    return FAILURE;
  }
#endif

    return SUCCESS;
}

/***********************************************************************
 * EOF
 ***********************************************************************/
