/* ************************************************************************** */
/* ********************* thread semaphores functions  *********************** */
/* ************************************************************************** */

#include <malloc.h>
#include "MPSClient_defs.h"
#include "MPSClient_vars.h"

thread_semaphore *create_thread_semaphore()
{
	thread_semaphore *sem;
	pthread_t thread_id;

	thread_id = pthread_self();

	if (thread_semaphores != NULL)
	{
		sem = thread_semaphores;

		do
		{
#if defined(__MINGW32__)
			if ( memcmp(&(sem->thread_id), &thread_id, sizeof(pthread_t)) == 0 )
#else
			if (sem->thread_id == thread_id)
#endif
			{
				return sem;
			}

			sem = sem->next;
		} while (sem != thread_semaphores);
	}

	sem = (thread_semaphore *) malloc(sizeof(thread_semaphore));

	if (sem == NULL) return NULL;

	sem->thread_id = thread_id;
	sem->is_waiting = 0;

	if ( sem_init(&(sem->semaphore), 0, 0) )
	{
		free(sem);

		return NULL;
	}

	if (thread_semaphores == NULL)
	{
		sem->next = sem;
		sem->prev = sem;
		thread_semaphores = sem;
	}
	else
	{
		sem->next = thread_semaphores;
		sem->prev = thread_semaphores->prev;

		thread_semaphores->prev->next = sem;
		thread_semaphores->prev = sem;
	}

	return sem;
}

void delete_thread_semaphores()
{
	thread_semaphore *cur_sem, *del_sem;

	if (thread_semaphores == NULL) return;

	cur_sem = thread_semaphores;

	/* delete thread semaphores */
	do
	{
		del_sem = cur_sem;
		cur_sem = cur_sem->next;

		sem_destroy(&(del_sem->semaphore));

		free(del_sem);
	} while (cur_sem != thread_semaphores);

	thread_semaphores = NULL;
}

thread_semaphore *find_thread_semaphore(sem_t *sem)
{
	thread_semaphore *cur_sem;

	if (thread_semaphores == NULL) return NULL;

	cur_sem = thread_semaphores;

	do
	{
		if (&(cur_sem->semaphore) == sem) return cur_sem;

		cur_sem = cur_sem->next;
	} while (cur_sem != thread_semaphores);

	return NULL;
}

int post_thread_semaphore(sem_t *sem)
{
	thread_semaphore *tsem;
	int ret;

	pthread_mutex_lock(&send_mutex);

	tsem = find_thread_semaphore(sem);

	if (tsem != NULL) tsem->is_waiting = 0;

	ret = sem_post(sem);

	pthread_mutex_unlock(&send_mutex);

	return ret;
}

void post_waiting_thread_semaphores()
{
	thread_semaphore *cur_sem;

	pthread_mutex_lock(&send_mutex);

	if (thread_semaphores == NULL)
	{
		pthread_mutex_unlock(&send_mutex);
		return;
	}

	cur_sem = thread_semaphores;

	do
	{
		if (cur_sem->is_waiting)
		{
			cur_sem->is_waiting = 0;
			sem_post(&(cur_sem->semaphore));
		}

		cur_sem = cur_sem->next;
	} while (cur_sem != thread_semaphores);

	pthread_mutex_unlock(&send_mutex);
}
