/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
**    derived from this software without specific prior written permission. 
**  
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE. */

#include "xmlrpc_config.h"

#undef PACKAGE
#undef VERSION

#include <stddef.h>
#include <string.h>
#include <stdlib.h>

#ifdef WIN32
#ifdef _DEBUG
#	include <crtdbg.h>
#	define new DEBUG_NEW
#	define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__)
#	undef THIS_FILE
	static char THIS_FILE[] = __FILE__;
#endif
#endif /*WIN32*/

#include "pthreadx.h"
#include "xmlrpc.h"
#include "xmlrpc_client.h"

#if defined (WIN32)
#include <process.h>
#endif

/* For debugging the xmlrpc_transport threading. */
/* #define tdbg_printf printf */
#define tdbg_printf (void *)

/* Lacking from the abyss/thread.c implimentaion. */
void wait_for_asynch_thread(pthread_t *thread)
{
#if WIN32
	unsigned long milliseconds = INFINITE;
	switch (WaitForSingleObject (
	*thread /* handle to object to wait for */,
	milliseconds /* time-out interval in milliseconds*/) )
	{
		/* One may want to handle these cases  */
	case WAIT_OBJECT_0:
	case WAIT_TIMEOUT:
		break;
	}
#else
	void * result;
	int success;
	success = pthread_join (*thread, &result);
#endif
}

/* MRB-WARNING: Only call when you have successfully
**     acquired the Lock/Unlock mutex! */
void unregister_asynch_thread (running_thread_list *list, pthread_t *thread)
{
	running_thread_info * pCur = NULL;
	XMLRPC_ASSERT_PTR_OK(thread);
	XMLRPC_ASSERT_PTR_OK(list);

	tdbg_printf("unregister_asynch_thread: &pthread_id = %08X *(%08X)\n", thread, *thread);
	/* Removal */
	/* Lock (); */
	for (pCur = list->AsyncThreadHead; pCur != NULL; pCur = (running_thread_info *)pCur->Next)
	{
		if (pCur->_thread == *thread)
		{
			if (pCur == list->AsyncThreadHead)
				list->AsyncThreadHead = pCur->Next;
			if (pCur == list->AsyncThreadTail)
				list->AsyncThreadTail = pCur->Last;
			if (pCur->Last)
				((running_thread_info *)(pCur->Last))->Next = pCur->Next;
			if (pCur->Next)
				((running_thread_info *)(pCur->Next))->Last = pCur->Last;
			/* Free malloc'd running_thread_info */
			free (pCur);
			return;
		}
	}

	/* This is a serious progmatic error, since the thread
	** should be in that list! */
	XMLRPC_ASSERT_PTR_OK(0x0000);

	/* Unlock (); */
}

/* MRB-WARNING: Only call when you have successfully
**     acquired the Lock/Unlock mutex! */
void register_asynch_thread (running_thread_list *list, pthread_t *thread)
{
	running_thread_info* info = (running_thread_info *) malloc(sizeof(running_thread_info));

	XMLRPC_ASSERT_PTR_OK(thread);
	XMLRPC_ASSERT_PTR_OK(list);
	
	tdbg_printf("register_asynch_thread: &pthread_id = %08X *(%08X)\n", thread, *thread);

	info->_thread = *thread;

	/* Insertion */
	/* Lock (); */
	if (list->AsyncThreadHead == NULL)
	{
		list->AsyncThreadHead = list->AsyncThreadTail = info;
		list->AsyncThreadTail->Next = list->AsyncThreadHead->Next = NULL;
		list->AsyncThreadTail->Last = list->AsyncThreadHead->Last = NULL;
	}
	else
	{
		info->Last = list->AsyncThreadTail;
		list->AsyncThreadTail->Next = info;
		list->AsyncThreadTail = list->AsyncThreadTail->Next;
		list->AsyncThreadTail->Next = NULL;
	}
	/* Unlock (); */
}
