Blame winpr/libwinpr/synch/mutex.c

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