/*-------------------------------------------------------------------------
 * drawElements Thread Library
 * ---------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Unix implementation of semaphore using named semaphores.
 *//*--------------------------------------------------------------------*/

#include "deSemaphore.h"

#if (DE_OS == DE_OS_IOS || DE_OS == DE_OS_OSX)

#include "deMemory.h"
#include "deString.h"

#include <semaphore.h>
#include <unistd.h>

typedef struct NamedSemaphore_s
{
	sem_t*	semaphore;
} NamedSemaphore;

static void NamedSemaphore_getName (const NamedSemaphore* sem, char* buf, int bufSize)
{
	deSprintf(buf, bufSize, "/desem-%d-%p", getpid(), (void*)sem);
}

DE_STATIC_ASSERT(sizeof(deSemaphore) >= sizeof(NamedSemaphore*));

deSemaphore deSemaphore_create (int initialValue, const deSemaphoreAttributes* attributes)
{
	NamedSemaphore*	sem		= (NamedSemaphore*)deCalloc(sizeof(NamedSemaphore));
	char			name[128];
	deUint32		mode	= 0700;

	DE_UNREF(attributes);

	if (!sem)
		return 0;

	NamedSemaphore_getName(sem, name, DE_LENGTH_OF_ARRAY(name));

	sem->semaphore = sem_open(name, O_CREAT|O_EXCL, mode, initialValue);

	if (sem->semaphore == SEM_FAILED)
	{
		deFree(sem);
		return 0;
	}

	return (deSemaphore)sem;
}

void deSemaphore_destroy (deSemaphore semaphore)
{
	NamedSemaphore* sem			= (NamedSemaphore*)semaphore;
	char			name[128];
	int				res;

	NamedSemaphore_getName(sem, name, DE_LENGTH_OF_ARRAY(name));

	res = sem_close(sem->semaphore);
	DE_ASSERT(res == 0);
	res = sem_unlink(name);
	DE_ASSERT(res == 0);
	DE_UNREF(res);
	deFree(sem);
}

void deSemaphore_increment (deSemaphore semaphore)
{
	sem_t*	sem		= ((NamedSemaphore*)semaphore)->semaphore;
	int		res		= sem_post(sem);
	DE_ASSERT(res == 0);
	DE_UNREF(res);
}

void deSemaphore_decrement (deSemaphore semaphore)
{
	sem_t*	sem		= ((NamedSemaphore*)semaphore)->semaphore;
	int		res		= sem_wait(sem);
	DE_ASSERT(res == 0);
	DE_UNREF(res);
}

deBool deSemaphore_tryDecrement (deSemaphore semaphore)
{
	sem_t* sem = ((NamedSemaphore*)semaphore)->semaphore;
	return (sem_trywait(sem) == 0);
}

#endif /* DE_OS */