/*
 * signal.c
 *
 * Copyright 2004, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 */


#include<types.h>
#include<lib.h>
#include<proc.h>
#include<interrupt.h>
#include<mm.h>
#include<lock.h>
#include<errno.h>
#include<term.h>
#include<signal.h>
#include<test.h>
#include<debug.h>


//#define DEBUG_SIGNAL 1
#ifdef DEBUG_SIGNAL
	#define STATIC
	#define INLINE
#else
	#define STATIC static
	#define INLINE	inline
#endif


/****************************************************************************************
 *
 * < シグナル操作 >
 *
 *****************************************************************************************/


//================================== PRIVATE ============================================


static SIG_ACTION defaultAction[SIG_ACTIONS];


/*
 * Default aactinos.
 */
/* terminate process. */
STATIC void terminate(int signum)
{
	exit(0,signum);
}

/* abnormal terminate process. */
STATIC void abnormalTerminate(int signum)
{
	exit(0,signum);
}

/* stop process. */
STATIC void stopProcess(int signum)
{
	PROC *proc=get_current_task();


	proc->signum = signum;
/**************************************************************/
	/* 親プロセスがwaitしてたら起こす。 */
	if((isForeground(proc))&&(proc->parent->state&TASK_CHILD_WAIT))
			add_to_schedule(proc->parent, TASK_SIGNAL_WAIT, NULL);
/***************************************************************/
	del_from_schedule(TASK_SEND_SIGNAL_WAIT, PROC_SCHEDULE_DEL);
	wait_task();
}


/*
 * シグナルハンドラの実行
 */
STATIC void doSigHandler(SIGNAL *sig,int sigNum)
{
	if (USER_BEG <= (uint)sig->action[sigNum])
	{
		uint beforeMask;

		/* シグナルマスクを入れ換える */
		beforeMask = sig->mask;
		sig->mask |= sig->actMask[sigNum] | (1 << sigNum);

		/* ユーザーハンドラを実行。 */
		doUserHandler(sigNum,sig->action[sigNum]);

		/* シグナルマスクを戻す。 */
		sig->mask = beforeMask;
	}
	else if ((sig->action[sigNum] != SIG_IGN) && (sig->action[sigNum] != SIG_DFL)){
		/* デフォルトハンドラを実行。 */
		sig->action[sigNum](sigNum);
	}
}

/* バイト単位のシグナルごとのシグナル番号 */
static uchar signalNum[] = {
/*	0 1 2 3 4 5 6 7 8 9 a b c d e f */
	0,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 0 */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 1 */
	6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 2 */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 3 */
	7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 4 */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 5 */
	6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 6 */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 7 */
	8,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 8 */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* 9 */
	6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* a */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* b */
	7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* c */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* d */
	6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* e */
	5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,	/* f */
};

/*
 * シグナル番号の取得
 */
STATIC int getSigNum(uint signal)
{
	union{
		uint ui;
		uchar uc[4];
	}sigValue;
	int sigNum;
	
	sigValue.ui = signal;
	if (sigValue.uc[0] != 0)
		sigNum = signalNum[sigValue.uc[0]] - 1;
	else if (sigValue.uc[1] != 0)
		sigNum = signalNum[sigValue.uc[1]] + 7;
	else if (sigValue.uc[2] != 0)
		sigNum = signalNum[sigValue.uc[2]] + 15;
	else
		sigNum = signalNum[sigValue.uc[3]] + 23;
	
	return sigNum;
}


//================================== PROTECTED ==========================================


static void initSigAction()
{
	// デフォルトアクションを設定する。
	defaultAction[0]			= NULL;
	defaultAction[SIGABRT]		= abnormalTerminate;
	defaultAction[SIGALRM]		= terminate;
	defaultAction[SIGBUS]		= abnormalTerminate;
	defaultAction[SIGCHLD]		= SIG_IGN;
	defaultAction[SIGCONT]		= SIG_DFL;
	defaultAction[SIGFPE]		= abnormalTerminate;
	defaultAction[SIGHUP]		= terminate;
	defaultAction[SIGILL]		= abnormalTerminate;
	defaultAction[SIGINT]		= terminate;
	defaultAction[SIGKILL]		= terminate;
	defaultAction[SIGPIPE]		= terminate;
	defaultAction[SIGPOLL]		= terminate;
	defaultAction[SIGPROF]		= terminate;
	defaultAction[SIGQUIT]		= abnormalTerminate;
	defaultAction[SIGSEGV]		= abnormalTerminate;
	defaultAction[SIGSTOP]		= stopProcess;
	defaultAction[SIGSYS]		= abnormalTerminate;
	defaultAction[SIGTERM]		= terminate;
	defaultAction[SIGTRAP]		= abnormalTerminate;
	defaultAction[SIGTSTP]		= stopProcess;
	defaultAction[SIGTTIN]		= stopProcess;
	defaultAction[SIGTTOU]		= stopProcess;
	defaultAction[SIGURG]		= SIG_IGN;
	defaultAction[SIGUSR1]		= terminate;
	defaultAction[SIGUSR2]		= terminate;
	defaultAction[SIGVTALRM]	= terminate;
	defaultAction[SIGXCPU]		= abnormalTerminate;
	defaultAction[SIGXFSZ]		= abnormalTerminate;
	defaultAction[SIGWINCH]		= SIG_IGN;
	defaultAction[SIGINFO]		= SIG_IGN;
	defaultAction[SIGWAKE]		= SIG_IGN;
}


//================================== PUBLIC =============================================


/*
 * シグナル実行
 * parameters : user esp address
 */
void doSignal()
{
	SIGNAL *sig;

	/* カーネル内でネストしているか？ */
	if (isNest() == TRUE)
		return;

	sig = get_current_task()->signal_struct;
	while (sig->signal != 0)
	{
		/* シグナル番号の取得 */
		int sigNum = getSigNum(sig->signal);

		/* シグナルクリアー */
		sig->signal ^= 1 << sigNum;

		/* シグナルハンドラの実行 */
		doSigHandler(sig,sigNum);
	}
}

/*
 * 再スタート開始用シグナル実行
 */
void doSignalRestart()
{
	uint signal;
	uint saveSignal;
	SIGNAL *sig;
	
	/* カーネル内でネスト数は１か？ */
	if (isSingleNest() == FALSE){
		return;
	}

	sig = get_current_task()->signal_struct;
	signal = saveSignal = sig->signal;
	while (signal != 0){
		/* シグナル番号の取得 */
		int sigNum = getSigNum(signal);

		/* シグナルクリアー */
		signal ^= 1 << sigNum;
		if (sig->actFlag[sigNum] & SA_RESTART){
			/* シグナルクリアー */
			saveSignal ^= 1 << sigNum;
			
			/* シグナルハンドラの実行 */
			doSigHandler(sig, sigNum);
		}
	}
	sig->signal = saveSignal;
}

//《割》
// シグナル送信。
// デフォルトアクションの「continue process」は、シグナル送信元で相手先プロセスを起動させる。
// return : 0 or error number
int sendSignal(PROC *proc, int signal)
{
	int sig;
	SIGNAL *sig_st;

	sig_st = proc->signal_struct;

	// シグナルが無効にされていないか
	if (sig_st->action[signal] == SIG_IGN){
		return -EPERM;
	}
	
	// マスクされたシグナルは保留する
	sig_st->reserve |= (1 << signal) & sig_st->mask;

	sig = ((1 << signal) | sig_st->mask) ^ sig_st->mask;
	if (sig != 0){
		sig_st->signal |= sig;
		add_to_schedule(proc, TASK_SIGNAL_WAIT, NULL);
	}

	return 0;
}


//《割》
// 強制シグナル送信。
// return : 0 or error=-1
int forceSendSignal(PROC *proc, const int signal, const int procStat)
{
	SIGNAL *sig = proc->signal_struct;
	int eflag;

	enterCli(&eflag);
	enter_spinlock(&sig->lock);
	{
		sig->signal |= 1 << signal;
		add_to_schedule(proc, procStat, NULL);
	}
	exit_spinlock(&sig->lock);
	exitCli(&eflag);

	return 0;
}


// シグナル待ち。
void sigWait()
{
	SIGNAL *sig = get_current_task()->signal_struct;
	int eflag;

	enterCli(&eflag);
	enter_spinlock(&sig->lock);
	if(sig->signal == 0){
		del_from_schedule(TASK_SIGNAL_WAIT, PROC_SCHEDULE_DEL);
		exit_spinlock(&sig->lock);
		exitCli(&eflag);

		wait_task();
	}
	else{
		exit_spinlock(&sig->lock);
		exitCli(&eflag);
	}

	// SIGWAKEはクリアー。
	sig->signal &= ~(1 << SIGWAKE);
}


/*
 * fork()時のシグナル機構の設定。
 * parameters : 親プロセスのシグナル構造体。
 * return : 0 or error number
 */
SIGNAL *setSignal(SIGNAL *parent_sig)
{
	SIGNAL *sig_st;


	if ((sig_st = kmalloc(sizeof(SIGNAL))) == NULL){
		return NULL;
	}

	memcpy(sig_st,parent_sig,sizeof(SIGNAL));
	sig_st->signal=0;
	sig_st->reserve=0;

	return sig_st;
}


/*
 * exit()時のシグナル機構の開放。
 * parameters : シグナル構造体
 */
void releaseSignal(SIGNAL *sig_st)
{
	kfree(sig_st);
}


/*
 * シグナル機構のリセット。
 * parameters : シグナル構造体
 */
void resetSignal(SIGNAL *sig_st)
{
	memset(sig_st,0,sizeof(SIGNAL));

	/* デフォルトアクションをコピー。 */
	memcpy(sig_st->action, defaultAction, sizeof(defaultAction));
}


/*
 * SIGINTが発生したか。
 * return : FALSE or TRUE
 */
int isSigint()
{
	uint signal = ((SIGNAL*)get_current_task()->signal_struct)->signal;

	// SIGWAKEはシステム用なので省く。
	return ((signal & ~(1 << SIGWAKE)) == 0)? FALSE : TRUE;
}


/*
 * 常駐カーネルスレッド用、終了シグナルをすべてマスクする。
 */
void setSigAllMask()
{
	SIGNAL *sigStruct = get_current_task()->signal_struct;
	
	sigStruct->mask = SIGABRT | SIGBUS | SIGFPE | SIGILL | SIGQUIT | SIGSEGV | SIGSYS | SIGTRAP | SIGXCPU | SIGXFSZ;
}


/*
 * シグナル機構の初期化。
 * return : SIGNAL struct or NULL
 */
SIGNAL *setFirstSignal()
{
	SIGNAL *sig_st;


	if((sig_st=kmalloc(sizeof(SIGNAL)))==NULL)return NULL;

	/* 初期化。 */
	resetSignal(sig_st);	
	sig_st->mask=0;
	sig_st->lock=0;

	return sig_st;
}


/****************************************************************************************
 *
 * < システムコール >
 *
 *****************************************************************************************/


int sys_sigaction(int signum,const struct sigaction *act,struct sigaction *oldact)
{
	SIGNAL *signal = get_current_task()->signal_struct;

	if (signum == 0){
		return 0;
	}
	if ((SIG_ACTIONS <= signum) || (signum < 0)){
		return -EINVAL;
	}

	if (act != NULL){
		if ((signum == SIGKILL) || (signum == SIGSTOP)){
			return -EINVAL;		/* SIGKILLとSIGSTOPは変更不可。 */
		}

		if (act->sa_handler == SIG_DFL){
			signal->action[signum] = defaultAction[signum];
		}
		else if (act->sa_handler == SIG_IGN){
			signal->action[signum] = SIG_IGN;
		}
		else if (USER_BEG <= (uint)act->sa_handler){
			signal->action[signum] = act->sa_handler;
		}
		else{
			return -EINVAL;		/* ハンドラアドレスが不正。 */
		}

		signal->actMask[signum] = act->sa_mask;
		signal->actFlag[signum] = act->sa_flags;
	}
	if (oldact != NULL){
		if (checkMem(oldact,sizeof(*oldact)) == ERR){
			return -EFAULT;
		}

		if (signal->action[signum] == SIG_IGN){
			oldact->sa_handler = SIG_IGN;
		}
		else if (signal->action[signum] == defaultAction[signum]){
			oldact->sa_handler = SIG_DFL;
		}
		else{
			oldact->sa_handler = signal->action[signum];
		}

		oldact->sa_mask = signal->actMask[signum];
	}

	return 0;
}


int sys_sigprocmask(int how,uint *set,uint *oldset)
{
	uint tmp_mask=*set;
	SIGNAL *sig_st;


	sig_st=get_current_task()->signal_struct;

	if (oldset != NULL){
		*oldset = sig_st->mask;
	}

	switch (how){
		case SIG_BLOCK:
			if (tmp_mask & ((1 << SIGKILL) | (1 << SIGSTOP))){
				return -EINVAL;			// SIGKILLとSIGSTOPはブロック不可。
			}
			sig_st->mask |= tmp_mask;
			break;
		case SIG_UNBLOCK:
			sig_st->mask &= ~tmp_mask;
			break;
		case SIG_SETMASK:
			if (tmp_mask & ((1 << SIGKILL) | (1 << SIGSTOP))){
				return -EINVAL;			// SIGKILLとSIGSTOPはブロック不可。
			}
			sig_st->mask = tmp_mask;
			break;
	}

	return 0;
}


int sys_kill(pid_t pid,int sig)
{
	int rest;
	pid_t pgid;
	PROC *proc;


	if ((uint)sig >= SIG_ACTIONS)
		return -EPERM;

	if (pid > 0)
	{
		if ((proc = searchProcList(pid)) == NULL)
			return -ESRCH;
		rest = sendSignal(proc,sig);
	}
	else if (pid == 0)		/* callプロセスと同グループ。 */
	{
		proc = get_current_task();
		pgid = proc->pgid;
		while ((proc = getNextProc(proc,pgid)) != NULL)
			sendSignal(proc,sig);
	}
	else if (pid == -1)	/* 全プロセス。 */
	{
		sendSignalAllProc(sig);
		sendSignal(get_current_task(),sig);
	}
	else				/* pid<-1 -pidのグループ。 */
	{
		pgid = -pid;
		for (proc = NULL; (proc = getNextProc(proc,pgid)) != NULL;)
			sendSignal(proc,sig);
	}

	return 0;
}


int sys_sigpending(sigset_t *set,int flag)
{
	SIGNAL *sig_st;


	/* ポインタの妥当性チェック */
	if (checkMem(set,sizeof(sigset_t)) == -1)
		return -EINVAL;

	sig_st = get_current_task()->signal_struct;

	switch(flag)
	{
		case SIG_PENDING_SOTORE:
			*set = sig_st->reserve;
			break;
		case SIG_PENDING_SET:
			sig_st->reserve = *set;
			break;
	}

	return 0;
}


int sys_sigsuspend(const sigset_t *mask)
{
	uint beforeMask;
	SIGNAL *sig_st;


	/* SIGKILLとSIGSTOPはブロック不可。 */
	if(*mask&((1<<SIGKILL)|(1<<SIGSTOP)))return -EINVAL;

	sig_st=get_current_task()->signal_struct;
	beforeMask=sig_st->mask;
	sig_st->mask=*mask;

	/* suspend. */
	del_from_schedule(TASK_SIGNAL_WAIT, PROC_SCHEDULE_DEL);
	wait_task();

	sig_st->mask=beforeMask;

	return -EINTR;
}


/****************************************************************************************
 *
 * 初期化
 *
 *****************************************************************************************/


void initSignal()
{
	initSigAction();
}

//****************************************************************************************
void testSignal()
{
}
