/************************************************************************
 * AUTHOR: NiuJiuRu
 * FILENAME: swthrd.c
 * DESCRIPTION: 线程操作
 * NOTE:
 * HISTORY:
 * 1, [2010-12-18] created by NiuJiuRu
 * 2, [2014-05-13] 修改"sw_thrd_delay()"函数, 当延时时间为负数时, 线程将
 *                 无限等待; 修改"ThrdProc()"函数,去除不必要的信号检测函
 *                 数, 提高用户回调函数的调用性能.
 ***********************************************************************/
#include "swapi.h"
#include "swstring.h"
#include "swsignal.h"
#include "swmem.h"
#include "swthrd.h"

// 线程的调度策略(1 - "SCHED_FIFO"实时调度策略，先到先服务; 2 - "SCHED_RR"实时调度策略，时间片轮转)
#define MY_SCHEDPOLICY SCHED_RR

typedef struct
{
	// 线程的名称
	char name[32];
	
	// 线程的ID号
	pthread_t nThrdID;
	// 线程的控制事件
	void *hCtlEvent;
	// 线程的退出信号灯
	void *hEndSignal;
	
	// 线程的(用户)回调函数
	PThrdProc proc;
	unsigned long wParam;
	unsigned long lParam;
	
	// 线程是否暂停运行
	volatile bool bPause;
	// 线程是否正在执行(用户)回调函数还没有返回
	volatile bool bBusy;
	// 线程是否已退出
	volatile bool bQuit;
	
} SThrdInfo;

// 匿名线程计数器
static int s_nameless_thrd_counter = 0;

// 线程的执行函数
static void ThrdProc(void *lpParameter);

/* 创建线程, 成功后默认处于暂停状态 */
void *sw_thrd_create(const char *name, int priority, int stack_size, PThrdProc proc,
					 unsigned long wParam, unsigned long lParam)
{
	SThrdInfo *pInfo = NULL;
	pthread_attr_t attr; // 线程的属性对象
	int policy = 0; // 调度策略
	
	pInfo = (SThrdInfo *)sw_heap_malloc(sizeof(SThrdInfo));
	if(!pInfo) goto ErrorP;
	memset(pInfo, 0, sizeof(SThrdInfo));
	
	// 设置线程的名称
	if(name) strncpy(pInfo->name, name, sizeof(pInfo->name)-1);
	else snprintf(pInfo->name, sizeof(pInfo->name)-1, "nameless%d thread", s_nameless_thrd_counter++);
	
	// 产生线程的控制事件
	pInfo->hCtlEvent = sw_signal_create();
	if(!pInfo->hCtlEvent) goto ErrorP;
	
	// 创建线程的退出信号灯
	pInfo->hEndSignal = sw_signal_create();
	if(!pInfo->hEndSignal) goto ErrorP;
	
	// 设置线程的(用户)回调函数
	pInfo->proc = proc;
	pInfo->wParam = wParam;
	pInfo->lParam = lParam;
	
	// 初始化线程属性对象
	pthread_attr_init(&attr);
	
	// 设置线程的调度策略
	if(priority > 0)
	{
		pthread_attr_getschedpolicy(&attr, &policy);
		if(policy != MY_SCHEDPOLICY)
		{
			policy = MY_SCHEDPOLICY;
			if(pthread_attr_setschedpolicy(&attr, policy) != 0) goto ErrorP;
		}
	}
	else pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); // 绑定的, 此线程将与系统中的所有线程进行竞争
	
	// 堆栈大小
	if(pthread_attr_setstacksize(&attr, stack_size) != 0) goto ErrorP;
	
	// 创建线程, 成功后线程默认处于暂停状态
	pInfo->bPause = true; pInfo->bBusy = false; pInfo->bQuit = false;
	if(pthread_create(&pInfo->nThrdID, &attr, (void *)ThrdProc, (void *)pInfo) != 0) goto ErrorP;
	
	// 销毁线程属性对象
	pthread_attr_destroy(&attr);
	
	// 设置线程的优先级
	sw_thrd_setPriority(pInfo, priority);
	
	// 等待线程状态稳定
	sw_thrd_delay(THRDWAIT_DELAY);
	
	return pInfo;
	
ErrorP:
	pthread_attr_destroy(&attr); // 销毁线程属性对象
	sw_thrd_destroy(pInfo, 0);
	
	return NULL;
}

/* 销毁线程, 在"wait time <= timout(ms)"前尝试安全的关闭线程, "wait time > timout"后则强制关闭 */
void sw_thrd_destroy(void *hThrd, int timeout)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return;
	
	if(pInfo->nThrdID != 0)
	{
		pInfo->bQuit = true;
		sw_thrd_resume(pInfo);
		if(sw_signal_wait(pInfo->hEndSignal, timeout) == 0) ; // 尝试安全的关闭线程
		else if(pthread_cancel(pInfo->nThrdID) != 0) // 强制关闭线程
		{ sw_log_error("terminate %s error(errno=%d)!!", pInfo->name, errno); }
		pthread_join(pInfo->nThrdID, NULL);
		pInfo->nThrdID = 0;
	}
	
	if(pInfo->hCtlEvent) { sw_signal_destroy(pInfo->hCtlEvent); pInfo->hCtlEvent = NULL; }
	
	if(pInfo->hEndSignal) { sw_signal_destroy(pInfo->hEndSignal); pInfo->hEndSignal = NULL; }
	
	sw_heap_free(pInfo);
}

/* 暂停运行线程 */
void sw_thrd_pause(void *hThrd)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return;
	
	while(sw_signal_wait(pInfo->hCtlEvent, 0) == 0) sw_thrd_delay(1);
	pInfo->bPause = true;
}

/* 继续运行线程 */
void sw_thrd_resume(void *hThrd)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return;
	
	pInfo->bPause = false;
	sw_signal_give(pInfo->hCtlEvent);
}

/* 延时(毫秒) */
void sw_thrd_delay(int ms)
{
	if(ms < 0) select(0, NULL, NULL, NULL, NULL);
	else
	{
		struct timeval tv = { 0 };
		tv.tv_sec = ms/1000;
		tv.tv_usec = (ms%1000)*1000;
		select(0, NULL, NULL, NULL, &tv);
	}
}

/* 检查线程是否还存在 */
bool sw_thrd_isAlive(void *hThrd)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return false;
	
	return (pInfo->nThrdID != 0 && pInfo->bQuit == false);
}

/* 检查线程是否正在运行: true = 是, false = 否 */
bool sw_thrd_isRunning(void *hThrd)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return false;
	
	return (pInfo->nThrdID != 0 && pInfo->bQuit == false && pInfo->bPause == false);
}

/* 检查线程是否正在执行(用户)回调函数还没有返回: true = 是, false = 否 */
bool sw_thrd_isBusy(void *hThrd)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return false;
	
	return pInfo->bBusy;
}

/* 设置线程名称 */
bool sw_thrd_setName(void *hThrd, const char *name)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo || !name) return false;
	
	memset(pInfo->name, 0, sizeof(pInfo->name));
	strncpy(pInfo->name, name, sizeof(pInfo->name)-1);
	
	return true;
}

/* 取得线程名称 */
char *sw_thrd_getName(void *hThrd, char *name)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo || !name) return NULL;
	
	strcpy(name, pInfo->name);
	
	return name;
}

/* 设置线程优先级 */
bool sw_thrd_setPriority(void *hThrd, int priority)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	struct sched_param sparam = { 0 };
	
	if(!pInfo) return false;
	
	sparam.sched_priority = priority;
	if(pthread_setschedparam(pInfo->nThrdID, MY_SCHEDPOLICY, &sparam) == 0) return true;
	else return false;
}

/* 取得线程优先级 */
int sw_thrd_getPriority(void *hThrd)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	struct sched_param sparam = { 0 };
	int policy;
	
	if(!pInfo) return -1;
	
	if(pthread_getschedparam(pInfo->nThrdID, &policy, &sparam) == 0) return sparam.sched_priority;
	else return -1;
}

/* 设置线程执行的(用户)回调函数 */
bool sw_thrd_setProc(void *hThrd, PThrdProc proc, unsigned long wParam, unsigned long lParam)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return false;
	
	pInfo->proc = proc;
	pInfo->wParam = wParam;
	pInfo->lParam = lParam;
	
	return true;
}

/* 取得线程执行的(用户)回调函数 */
void sw_thrd_getProc(void *hThrd, PThrdProc *proc, unsigned long *wParam, unsigned long *lParam)
{
	SThrdInfo *pInfo = (SThrdInfo *)hThrd;
	
	if(!pInfo) return;
	
	if(proc) *proc = pInfo->proc;
	if(wParam) *wParam = pInfo->wParam;
	if(lParam) *lParam = pInfo->lParam;
}

// 线程的执行函数
static void ThrdProc(void *lpParameter)
{
	SThrdInfo *pInfo = (SThrdInfo *)lpParameter;
	int delay = 0;
	
	while(pInfo->bQuit == false)
	{
		if(pInfo->bPause) sw_signal_wait(pInfo->hCtlEvent, WAIT_FOREVER);
		
		if(pInfo->proc)
		{
			pInfo->bBusy = true;
			delay = pInfo->proc(pInfo->wParam, pInfo->lParam);
			pInfo->bBusy = false;
		}
		else delay = 1;
		
		if(delay < 0) pInfo->bQuit = true;
		else if(delay > 0) sw_signal_wait(pInfo->hCtlEvent, delay);
	}
	
	pInfo->proc = NULL;
	pInfo->wParam = pInfo->lParam = 0;
	sw_signal_give(pInfo->hEndSignal); // 点亮"退出信号灯", 表明线程已正常结束
	
	pthread_exit("thread normal exit.");
}
