Blame winpr/libwinpr/synch/mutex.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Synchronization Functions
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/debug.h>
Packit 1fb8d4
#include <winpr/wlog.h>
Packit Service 5a9772
#include <winpr/string.h>
Packit 1fb8d4
Packit 1fb8d4
#include "synch.h"
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
Packit 1fb8d4
#include "../handle/handle.h"
Packit 1fb8d4
Packit 1fb8d4
#include "../log.h"
Packit 1fb8d4
#define TAG WINPR_TAG("sync.mutex")
Packit 1fb8d4
Packit 1fb8d4
static BOOL MutexCloseHandle(HANDLE handle);
Packit 1fb8d4
Packit 1fb8d4
static BOOL MutexIsHandled(HANDLE handle)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_TIMER* pMutex = (WINPR_TIMER*)handle;
Packit 1fb8d4
Packit 1fb8d4
	if (!pMutex || (pMutex->Type != HANDLE_TYPE_MUTEX))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int MutexGetFd(HANDLE handle)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_MUTEX* mux = (WINPR_MUTEX*)handle;
Packit 1fb8d4
Packit 1fb8d4
	if (!MutexIsHandled(handle))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: Mutex does not support file handles... */
Packit 1fb8d4
	(void)mux;
Packit 1fb8d4
	return -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL MutexCloseHandle(HANDLE handle)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_MUTEX* mutex = (WINPR_MUTEX*)handle;
Packit 1fb8d4
	int rc;
Packit 1fb8d4
Packit 1fb8d4
	if (!MutexIsHandled(handle))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if ((rc = pthread_mutex_destroy(&mutex->mutex)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "pthread_mutex_destroy failed with %s [%d]", strerror(rc), rc);
Packit 1fb8d4
#if defined(WITH_DEBUG_MUTEX)
Packit 1fb8d4
		{
Packit 1fb8d4
			size_t used = 0, i;
Packit 1fb8d4
			void* stack = winpr_backtrace(20);
Packit 1fb8d4
			char** msg = NULL;
Packit 1fb8d4
Packit 1fb8d4
			if (stack)
Packit 1fb8d4
				msg = winpr_backtrace_symbols(stack, &used);
Packit 1fb8d4
Packit 1fb8d4
			if (msg)
Packit 1fb8d4
			{
Packit 1fb8d4
				for (i = 0; i < used; i++)
Packit Service 5a9772
					WLog_ERR(TAG, "%2" PRIdz ": %s", i, msg[i]);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			free(msg);
Packit 1fb8d4
			winpr_backtrace_free(stack);
Packit 1fb8d4
		}
Packit 1fb8d4
#endif
Packit 1fb8d4
		/**
Packit 1fb8d4
		 * Note: unfortunately we may not return FALSE here since CloseHandle(hmutex) on
Packit 1fb8d4
		 * Windows always seems to succeed independently of the mutex object locking state
Packit 1fb8d4
		 */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	free(mutex->name);
Packit 1fb8d4
	free(handle);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static HANDLE_OPS ops = { MutexIsHandled, MutexCloseHandle,
Packit Service 5a9772
	                      MutexGetFd,     NULL, /* CleanupHandle */
Packit Service 5a9772
	                      NULL,           NULL,
Packit Service 5a9772
	                      NULL,           NULL,
Packit Service 5a9772
	                      NULL,           NULL,
Packit Service 5a9772
	                      NULL,           NULL,
Packit Service 5a9772
	                      NULL,           NULL,
Packit Service 5a9772
	                      NULL,           NULL,
Packit Service 5a9772
	                      NULL,           NULL,
Packit Service 5a9772
	                      NULL,           NULL };
Packit 1fb8d4
Packit 1fb8d4
HANDLE CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName)
Packit 1fb8d4
{
Packit Service 5a9772
	HANDLE handle;
Packit Service 5a9772
	char* name = NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (lpName)
Packit Service 5a9772
	{
Packit Service 5a9772
		int rc = ConvertFromUnicode(CP_UTF8, 0, lpName, -1, &name, 0, NULL, NULL);
Packit Service 5a9772
Packit Service 5a9772
		if (rc < 0)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	handle = CreateMutexA(lpMutexAttributes, bInitialOwner, name);
Packit Service 5a9772
	free(name);
Packit Service 5a9772
	return handle;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
HANDLE CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName)
Packit Service 5a9772
{
Packit 1fb8d4
	HANDLE handle = NULL;
Packit 1fb8d4
	WINPR_MUTEX* mutex;
Packit Service 5a9772
	mutex = (WINPR_MUTEX*)calloc(1, sizeof(WINPR_MUTEX));
Packit Service 5a9772
Packit Service 5a9772
	if (lpMutexAttributes)
Packit Service 5a9772
		WLog_WARN(TAG, "%s [%s] does not support lpMutexAttributes", __FUNCTION__, lpName);
Packit 1fb8d4
Packit 1fb8d4
	if (mutex)
Packit 1fb8d4
	{
Packit 1fb8d4
		pthread_mutexattr_t attr;
Packit 1fb8d4
		pthread_mutexattr_init(&attr);
Packit 1fb8d4
		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
Packit 1fb8d4
		pthread_mutex_init(&mutex->mutex, &attr);
Packit 1fb8d4
		WINPR_HANDLE_SET_TYPE_AND_MODE(mutex, HANDLE_TYPE_MUTEX, WINPR_FD_READ);
Packit 1fb8d4
		mutex->ops = &ops;
Packit Service 5a9772
		handle = (HANDLE)mutex;
Packit 1fb8d4
Packit 1fb8d4
		if (bInitialOwner)
Packit 1fb8d4
			pthread_mutex_lock(&mutex->mutex);
Packit Service 5a9772
Packit Service 5a9772
		if (lpName)
Packit Service 5a9772
			mutex->name = strdup(lpName); /* Non runtime relevant information, skip NULL check */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return handle;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
HANDLE CreateMutexExA(LPSECURITY_ATTRIBUTES lpMutexAttributes, LPCSTR lpName, DWORD dwFlags,
Packit 1fb8d4
                      DWORD dwDesiredAccess)
Packit 1fb8d4
{
Packit Service 5a9772
	BOOL initial = FALSE;
Packit Service 5a9772
	/* TODO: support access modes */
Packit Service 5a9772
Packit Service 5a9772
	if (dwDesiredAccess != 0)
Packit Service 5a9772
		WLog_WARN(TAG, "%s [%s] does not support dwDesiredAccess 0x%08" PRIx32, __FUNCTION__,
Packit Service 5a9772
		          lpName, dwDesiredAccess);
Packit Service 5a9772
Packit Service 5a9772
	if (dwFlags & CREATE_MUTEX_INITIAL_OWNER)
Packit Service 5a9772
		initial = TRUE;
Packit Service 5a9772
Packit Service 5a9772
	return CreateMutexA(lpMutexAttributes, initial, lpName);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HANDLE CreateMutexExW(LPSECURITY_ATTRIBUTES lpMutexAttributes, LPCWSTR lpName, DWORD dwFlags,
Packit 1fb8d4
                      DWORD dwDesiredAccess)
Packit 1fb8d4
{
Packit Service 5a9772
	BOOL initial = FALSE;
Packit Service 5a9772
Packit Service 5a9772
	/* TODO: support access modes */
Packit Service 5a9772
	if (dwDesiredAccess != 0)
Packit Service 5a9772
		WLog_WARN(TAG, "%s [%s] does not support dwDesiredAccess 0x%08" PRIx32, __FUNCTION__,
Packit Service 5a9772
		          lpName, dwDesiredAccess);
Packit Service 5a9772
Packit Service 5a9772
	if (dwFlags & CREATE_MUTEX_INITIAL_OWNER)
Packit Service 5a9772
		initial = TRUE;
Packit Service 5a9772
Packit Service 5a9772
	return CreateMutexW(lpMutexAttributes, initial, lpName);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HANDLE OpenMutexA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
Packit 1fb8d4
{
Packit Service 5a9772
	/* TODO: Implement */
Packit Service 5a9772
	WINPR_UNUSED(dwDesiredAccess);
Packit Service 5a9772
	WINPR_UNUSED(bInheritHandle);
Packit Service 5a9772
	WINPR_UNUSED(lpName);
Packit Service 5a9772
	WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HANDLE OpenMutexW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
Packit 1fb8d4
{
Packit Service 5a9772
	/* TODO: Implement */
Packit Service 5a9772
	WINPR_UNUSED(dwDesiredAccess);
Packit Service 5a9772
	WINPR_UNUSED(bInheritHandle);
Packit Service 5a9772
	WINPR_UNUSED(lpName);
Packit Service 5a9772
	WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL ReleaseMutex(HANDLE hMutex)
Packit 1fb8d4
{
Packit 1fb8d4
	ULONG Type;
Packit 1fb8d4
	WINPR_HANDLE* Object;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Handle_GetInfo(hMutex, &Type, &Object))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (Type == HANDLE_TYPE_MUTEX)
Packit 1fb8d4
	{
Packit Service 5a9772
		WINPR_MUTEX* mutex = (WINPR_MUTEX*)Object;
Packit 1fb8d4
		int rc = pthread_mutex_unlock(&mutex->mutex);
Packit 1fb8d4
Packit 1fb8d4
		if (rc)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "pthread_mutex_unlock failed with %s [%d]", strerror(rc), rc);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#endif