/*
 * proc.c
 *
 * Copyright 2002, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * プロセス関係
 */


#include<config.h>
#include<types.h>
#include<mm.h>
#include<fs.h>
#include<errno.h>
#include<interrupt.h>
#include<lock.h>
#include<segment.h>
#include<time.h>
#include<elf.h>
#include<proc.h>
#include<except_i386.h>
#include<signal.h>
#include<console.h>
#include<share/times.h>
#include<net/net.h>
#include<term.h>
#include<debug.h>
#include<test.h>


#define DEBUG_PROC 1

#ifdef DEBUG_PROC
	#define STATIC
	#define INLINE
#else
	#define STATIC static
	#define INLINE inline
#endif


/* tss格納構造体(104バイト) */
typedef struct{
	uint link,esp0,ss0,esp1,ss1,esp2,ss2,cr3,eip,eflags,eax,ecx,
		edx,ebx,esp,ebp,esi,edi,es,cs,ss,ds,fs,gs,ldts,tflag_iomap;
}TSS;


CPU cputask[MAX_CPU];		/* Task infomations for each cpu */

/* TSS、タスキング時のスタックスイッチに必要 */
static TSS kernel_tss={
	0,
	KERNEL_ESP_BEG - FPU_SAVE_SIZE,		/* esp0 */
	KERNEL_DATA_DES,					/* ss0 */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static PROC *idle_proc[MAX_CPU];	/* Idle process */
static PROC *proc1;					/* pid1プロセス構造体。 */


/******************************************************************************************************
 *
 * タスクスケジュール
 *
 *******************************************************************************************************/


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


//《割》
//《注意》他プロセスから呼ばれる。
// タスクを実行スケジュールに接続する。
// parameters : "TASK_RUNNING"中なら"o_isDel"に"PROC_SCHEDULE_NOT_DEL"を設定
void add_to_schedule(PROC *proc, const int flag, int *o_isDel)
{
	int cpu = proc->cpu;
	int eflags;

	enterCli(&eflags);
	enter_spinlock(&cputask[cpu].gate);
	{
		/* ウエイトフラグの確認。 */
		if(proc->state & flag){
			proc->state = TASK_RUNNING;

			if(cputask[cpu].current_task->next == idle_proc[cpu]){
				proc->next = proc->prev = proc;
				cputask[cpu].current_task->next = proc;
			}
			else{
				PROC *current = cputask[cpu].current_task->next->prev;

				if (current != proc){
					proc->prev = current;
					proc->next = current->next;
					current->next->prev = proc;
					current->next = proc;
				}
			}
		}
		else{
			if (o_isDel != NULL){
				*o_isDel = PROC_SCHEDULE_NOT_DEL;
			}
		}
	}
	exit_spinlock(&cputask[cpu].gate);
	exitCli(&eflags);
}


// 《注意》自プロセスが呼ぶ。
// タスクを実行スケジュールから切り離す。
void del_from_schedule(const int flag, const int isDel)
{
	int cpu = get_current_cpu();
	int eflags;
	PROC *proc = cputask[cpu].current_task;

	enterCli(&eflags);
	enter_spinlock(&cputask[cpu].gate);
	{
		if (isDel == PROC_SCHEDULE_DEL){
			if(proc->next == proc){
				idle_proc[cpu]->next = idle_proc[cpu]->prev = idle_proc[cpu];
				proc->next = idle_proc[cpu];
			}
			else{
				proc->next->prev = proc->prev;
				proc->prev->next = proc->next;
			}
			proc->state = flag;
		}
	}
	exit_spinlock(&cputask[cpu].gate);
	exitCli(&eflags);
}


/*
 * Process switch
 * parameters : 今回の割り込み時のセーブスタックトップesp値,前の割り込み時のesp値を保存するスタック
 * returns : Page directory
 */
uint *switch_task(uint esp, volatile uint beforeEsp)
{
	uint volatile *p_beforeEsp = &beforeEsp;
	uint volatile *p_esp = &esp;
	int cpu;
	PROC *current;


	cpu = get_current_cpu();
	current = cputask[cpu].current_task;
	*p_beforeEsp = current->esp;
	current->esp = esp;

	current = current->next;
	*p_esp = (uint)&current->esp;
	cputask[cpu].current_task = current;

	// TSフラグをセットしてFPU例外が起こるようにする
	setTs();

	return getPageDir();
}


/******************************************************************************************************
 *
 * プロセスリスト
 *
 *******************************************************************************************************/


//=================================== プライベート =======================================


enum{
	PROC_HASH_NUM=29,	/* プロセスハッシュリスト最大数。 */
};


static PROC_LIST procHash[PROC_HASH_NUM];		/* プロセスハッシュリスト。 */


/*
 * プロセスリスト値からプロセスアドレスを得る。
 * parameters : process link address
 * return : process address
 */
STATIC INLINE PROC *procLinkToProc(PROC_LIST *p)
{
	return (PROC*)((uint)p-(uint)&((PROC*)0)->proc_next);
}


/*
 * ハッシュ値を得る。
 * parameters : pid
 * return : hash value
 */
STATIC INLINE int getProcHash(int pid)
{
	return pid%PROC_HASH_NUM;
}


//=================================== パブリック =======================================


/*
 * Add to process list.
 * parameters : process address
 */
STATIC INLINE void addProcList(PROC *proc)
{
	PROC_LIST *hash=&procHash[getProcHash(proc->pid)];
	PROC_LIST *p=(PROC_LIST*)&proc->proc_next;


	enter_spinlock(&hash->lockGate);
	{
		p->prev=hash;
		p->next=hash->next;
		hash->next->prev=p;
		hash->next=p;
	}
	exit_spinlock(&hash->lockGate);
}


/*
 * Delete from process list.
 * parameters : process address
 */
STATIC INLINE void delProcList(PROC *proc)
{
	PROC_LIST *hash=&procHash[getProcHash(proc->pid)];
	PROC_LIST *p=(PROC_LIST*)&proc->proc_next;


	enter_spinlock(&hash->lockGate);
	{
		p->next->prev=p->prev;
		p->prev->next=p->next;
	}
	exit_spinlock(&hash->lockGate);
}


/*
 * Init process list;
 */
STATIC void initProclist()
{
	int i;


	/* プロセスハッシュリスト初期化。 */
	for(i=0;i<PROC_HASH_NUM;++i)
	{
		procHash[i].next=procHash[i].prev=&procHash[i];
		procHash[i].lockGate=0;
	}
}


//=================================== グローバル =======================================


/*
 * Search process from process list.
 * parameters : pid
 * return : process address or failed=NULL
 */
PROC *searchProcList(int pid)
{
	PROC_LIST *hash=&procHash[getProcHash(pid)];
	PROC_LIST *p;


	for(p=hash->next;p!=hash;p=p->next)
		if(procLinkToProc(p)->pid==pid)return procLinkToProc(p);

	return NULL;
}


/******************************************************************************************************
 *
 * プロセスID・グループID
 *
 *******************************************************************************************************/

/*
 * PRIVATE
 * プロセスグループの検索。
 * parameters : search start process,pgid
 * return : process or Failed=NULL
 */
STATIC PROC *searchPg(PROC *proc,pid_t pgid)
{
	PROC *rest;


	do
	{
		if(proc->state!=TASK_EXIT)
		{
			if(proc->pgid==pgid)return proc;
			if(proc->child!=NULL)
				if((rest=searchPg(proc->child,pgid))!=NULL)return rest;
		}
	}while((proc=proc->brother)!=NULL);

	return NULL;
}


/*
 * PUBLIC
 * Get process ID.
 * 注意！
 *  長期間連続稼働させた場合、オーバーフローになる可能性あり。
 * return : process ID.
 */
STATIC INLINE int getPid(PROC *proc)
{
	static int pid=1;

	return pid++;
}


/*
 * GLOBAL
 * 与えられたプロセスグループのプロセスを取得する。
 * parameters : search start process or NULL=proc1,groupe ID
 * return : prosecc or Failed=NULL
 */
PROC *getNextProc(PROC *proc,pid_t pgid)
{
	/* proc1から探す。 */
	if (proc == NULL)
		proc = proc1;

	/* 引数の次の順番のプロセスから探す。 */
	if (proc->child != NULL)
		return searchPg(proc->child,pgid);
	else
		do
		{
			if (proc->brother != NULL)
				return searchPg(proc->brother,pgid);
			if ((proc = proc->parent) == NULL)
				break;
		}while (proc->pgid == pgid);

	return NULL;
}


/*
 * PRIVATE
 * 一番下の子プロセスからシグナルを送る
 * parameters : search start process or NULL=proc1
 * return : prosecc or Failed=NULL
 */
STATIC void sendToProc(PROC *proc,int signal)
{
	/* 引数の次の順番のプロセス。 */
	if (proc->child != NULL)
		sendToProc(proc->child,signal);
	if (proc->brother != NULL)
		sendToProc(proc->brother,signal);

	if (proc != get_current_task())
		sendSignal(proc,signal);
}


/*
 * GLOBAL
 * 自プロセス以外の全プロセスにシグナルを送る
 */
void sendSignalAllProc(int signal)
{
	if (proc1->child != NULL)
		sendToProc(proc1->child,signal);
}


/******************************************************************************************************
 *
 * プロセス操作
 *
 *******************************************************************************************************/


extern int *active_cpu;		/* 稼動 CPU数。 */

/* PUBLIC */
static int procLockGate=0;		/* 他のプロセス構造体参照時のロックゲート。 */


/*
 * PRIVATE
 * 一番タスク数の少ないCPUを得る。
 * retuuns : cpu number
 */
STATIC int GetFewTaskCpu()
{
	int cpu=0;
	uint num;
	int i;


	num=cputask[0].proc_num;
	for(i = 1; i < *active_cpu; ++i)
		if(cputask[i].proc_num<num)
		{
			num=cputask[i].proc_num;
			cpu=i;
		}

	return cpu;
}


/*
 * PRIVATE
 * 該当の子プロセスの状態を報告する。
 * ビットマップ位置の意味は"sys/wait.h"を参照のこと
 * parameters : process,state address
 * return : 0 or not exit or stop=-1
 */
STATIC void setState(PROC *proc,int *stat_loc)
{
	union{
		int i;
		char c[4];
	}stat;
	
	
	if (stat_loc == NULL)
		return;

	stat.i = 0;
	stat.c[0] = proc->signum;
	stat.c[1] = proc->exit_state;
	if (proc->state == TASK_SEND_SIGNAL_WAIT)
	{
		stat.c[0] = 0x7F;
		stat.c[1] = proc->signum;
	}
	*stat_loc = stat.i;
}


/*
 * PRIVATE
 * exitした子プロセス構造体を開放する。
 * parameters : current process
 * return : 兄弟リンクの最後の子プロセスリンク
 */
STATIC PROC *releaseChild(PROC *proc)
{
	PROC **p,*q;


	for (p = &proc->child; *p != NULL;)
	{
		if ((*p)->state == TASK_EXIT)
		{
			q = *p;
			*p = (*p)->brother;
			kfree(q);
		}
		else
			p = &(*p)->brother;
	}

	return *p;
}


/*
 * PUBLIC
 * プロセスを実行可能にする
 * parameters : process
 */
STATIC void addNewProc(PROC *proc)
{
	proc->cpu=GetFewTaskCpu();
	proc->state=TASK_WAIT;
	add_to_schedule(proc, TASK_WAIT, NULL);
	++cputask[proc->cpu].proc_num;
}


/*
 * PUBLIC
 * 親プロセスが実行、
 * 1 exitした子プロセスの開放。
 * 2 残った子プロセスをpid0プロセスに渡す。
 * parameters : current process
 */
STATIC void releaseChildProc(PROC *proc)
{
	PROC *p,**q;


	for (p = proc->child; p != NULL;p = p->brother){
		p->parent = proc1;
	}
	enter_spinlock(&proc->gate);
	{
		p = releaseChild(proc);
	}
	exit_spinlock(&proc->gate);
	enter_spinlock(&proc1->gate);
	{
		for (q = &proc1->child; *q != NULL;q = &(*q)->brother);
		*q = p;
	}
	exit_spinlock(&proc1->gate);
}


/*
 * PUBLIC
 * 1 exitした子プロセスを開放する。
 * 2 該当の子プロセスの状態を報告する。
 * parameters : process structure,search pid,search pgid,task state,state address
 * return : pid or 0 or error number
 */
STATIC int searchExitState(PROC *proc, pid_t pid, pid_t pgid, int state, int *stat_loc)
{
	int rest = -ECHILD;
	PROC *p;


	if (stat_loc != NULL){
		*stat_loc = 0;
	}

	if (pid != 0){
		for (p = proc->child; p != NULL; p = p->brother){
			if (p->pid == pid){
				rest = 0;
				if (p->state & state){
					setState(p,stat_loc);
					rest = pid;
				}
				break;
			}
		}
	}
	else if (pgid != 0){
		for (p = proc->child; p != NULL; p = p->brother){
			if (p->pgid == pgid){
				rest = 0;
				if (p->state & state){
					setState(p,stat_loc);
					rest = p->pid;
					break;
				}
			}
		}
	}
	else if (proc->child != NULL){
		rest = 0;
		for (p = proc->child; p != NULL; p = p->brother){
			if (p->state & state){
				setState(p,stat_loc);
				rest = p->pid;
				break;
			}
		}
	}

	/* exitした子プロセスの開放。 */
	enter_spinlock(&proc->gate);
	{
		releaseChild(proc);
	}
	exit_spinlock(&proc->gate);

	return rest;
}


// parameters : isKernelThreadにはカーネルスレッドを作成するときに"0"以外を設定する
STATIC int fork(int isKernelThread)
{
	void *stack;
	uint esp;
	PROC *parent = get_current_task();
	PROC *child;
	int rest;

	if (parent->count_child >= MAX_CHILD){
		return -EAGAIN;
	}

	/* PROC構造体を割り当てる */
	if ((child = kmalloc(sizeof(PROC))) == NULL){
		return -ENOMEM;
	}

	/* 初期化。 */
	memset(&child->PROC_ZERO_TOP,0,(uint)&child->PROC_ZERO_END - (uint)&child->PROC_ZERO_TOP);
	child->parent = parent;
	enter_spinlock(&parent->gate);
	{
		child->brother = parent->child;
		parent->child = child;
	}
	exit_spinlock(&parent->gate);
	child->nestCount = parent->nestCount;

	/* ID. */
	child->pid = getPid(child);
	child->pgid = parent->pgid;
	child->uid = 0;
	child->gid = parent->gid;
	child->sid = parent->sid;

	/* セッションアドレス(制御端末構造体アドレス)をコピー */
	child->ctlterm = parent->ctlterm;
	
	child->gate = 0;

	/* ファイル関係構造体の割当て。 */
	child->file_struct = copyFileStruct(parent->file_struct);
	if ((child->file_struct) == NULL){
		goto ERR;
	}

	/* Page tableを割り当てる */
	rest = forkPage(parent->mm_struct, isKernelThread, &child->mm_struct, &stack);
	if (rest < 0){
		goto ERR;
	}

	/* シグナルを設定する。 */
	child->signal_struct = setSignal(parent->signal_struct);
	if (child->signal_struct == NULL){
		goto ERR;
	}

	/* タイマーの初期化。 */
	initTimer(child->timer, child->itimer);

	/* 子プロセスのカーネルスタックにコンテキストを設定する */
	esp = setContext((uint)stack);
	if (esp == 0){
		return 0;		// 子プロセス
	}

	child->esp=esp;

	/* プロセスリストに加える。 */
	addProcList(child);

	/* Add child process to schedule queue */
	addNewProc(child);

	++parent->count_child;

	return child->pid;
ERR:
	kfree(child);

	return -ENOMEM;
}


//=================================== グローバル =======================================


/*
 * proc1用wait。
 */
void waitProc1()
{
	for(;;)
	{
		/* 待ち。 */
		del_from_schedule(TASK_SIGNAL_WAIT, PROC_SCHEDULE_DEL);
		wait_task();

		enter_spinlock(&proc1->gate);
		{
			releaseChild(proc1);
		}
		exit_spinlock(&proc1->gate);
	}
	idle();
}


/*
 * カーネル内ネストカウントを増やす
 */
void incrementNest()
{
	get_current_task()->nestCount += 1;
}


/*
 * カーネル内ネストカウントを減らす
 */
void decrementNest()
{
	get_current_task()->nestCount -= 1;

	ASSERT(0 <= get_current_task()->nestCount);
}


/*
 * カーネル内でネストしているか？
 */
int isNest()
{
	return (0 < get_current_task()->nestCount)? TRUE : FALSE;
}


int isSingleNest()
{
	return (get_current_task()->nestCount == 1)? TRUE : FALSE;
}


// カーネルスレッドをforkする
int forkKernelThread()
{
	return fork(1);
}


/***************************************************************************************************
 *
 * System time
 *
 ***************************************************************************************************/


enum{
	CLOCK_TICK=10,		/* クロック単位 ms。 */
	
	CPU_TIME_SYSTEM	= 0,
	CPU_TIME_USER	= 1,
};


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


static uint64 beforeTime[MAX_CPU];	/* 直前のユーザーとシステムが切り替わった時間。 */
static PROC *currentProc[MAX_CPU];	/* 直前のプロセス。 */
static uchar which[MAX_CPU];		/* 現在の実行状態 0:system 1:user. */


// parameters : 1:user 0:system
static void calcCpuTimeOut(int isUser)
{
	int cpu = get_current_cpu();
	uint64 crt_time = rdtsc();

	currentProc[cpu]->cpu_time[which[cpu]] += crt_time - beforeTime[cpu];
	doItimer(currentProc[cpu]->itimer,crt_time - beforeTime[cpu],which[cpu]);
	beforeTime[cpu] = crt_time;
	which[cpu] = isUser;
}


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


/*
 * CPU時間を親プロセスの該当領域に足す。
 */
STATIC void addCpuTimeToParent()
{
	PROC *proc,*parent;

	proc=get_current_task();
	parent=proc->parent;
	parent->ctime[0]+=(uint)proc->cpu_time[0]/clock_1m/CLOCK_TICK;
	parent->ctime[1]+=(uint)proc->cpu_time[1]/clock_1m/CLOCK_TICK;
}


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


// カーネルに入る時
void calcCpuTimeInSys()
{
	int cpu = get_current_cpu();
	uint64 crt_time = rdtsc();
	PROC *proc = cputask[cpu].current_task;

	proc->cpu_time[which[cpu]] += crt_time - beforeTime[cpu];
	doItimer(proc->itimer,crt_time - beforeTime[cpu],which[cpu]);
	beforeTime[cpu] = crt_time;
	which[cpu] = ITIME_SYS;
	currentProc[cpu] = proc;
}

// カーネルから出る時
void calcCpuTimeOutIntr(INTERRUPT_FRAME frame)
{
	calcCpuTimeOut((frame.ds == KERNEL_DATA_DES)? CPU_TIME_SYSTEM : CPU_TIME_USER);
}

void calcCpuTimeOutSyscall()
{
	calcCpuTimeOut(CPU_TIME_USER);
}


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

/*
 * return : 親プロセスなら子プロセスID,子プロセスなら0,error=error number
 * todoリスト
 *  ディレクトリストリームをコピーする。
 */
int sys_fork()
{
	return fork(0);
}


int sys_exec(const char *path, char **argv, char **envp, volatile SYSCALL4_FRAME frame)
{
	enum{
		PARAM = sizeof(frame.para)	/* システムコール時の引数のサイズ */
	};
	uint entry_addr,stack_esp;
	int rest;
	EXEC_FD fd;
	SYS_INFO *sys_info;

	if ((rest = exec_open(path,&fd)) < 0){
		return rest;
	}

	/* 引数と環境変数をユーザースタックにコピーする。 */
	if ((stack_esp = setUserStack(argv,envp)) == 0)
		return -1;

	/* ELFバイナリのロード。 */
	if ((entry_addr = loadElf(&fd)) == 0)
		return -1;

	/* ファイルのクローズ */
	exec_close(&fd);
	
	/* スタックにシステム情報を設定。 */
	sys_info = (SYS_INFO*)(USER_ESP_BEG - sizeof(SYS_INFO));
	sys_info->lastAddr = getLastLinearAddr();

	/* シグナルアクションの初期化。 */
	resetSignal(get_current_task()->signal_struct);

	/* ファイル構造体の初期化。 */
	initExecFs();

	/* システムコールフレームの設定。 */
	frame.es = USER_DATA_DES;
	frame.ds = USER_DATA_DES;
	frame.eip = entry_addr;
	frame.cs = USER_CODE_DES;
	frame.user_esp = stack_esp - PARAM;
	frame.ss = USER_DATA_DES;

	return 0;
}


/*
 * GLOBAL
 * ページディレクトリの開放は別プロセスが行う。
 * parameters : 親プロセスへ渡す戻り値
 */
void exit(int state,int signum)
{
	void *mm_struct;
	PROC *proc=get_current_task();
	PROC *parent;

	/* 端末制御プロセスの開放。 */
	releaseTerm(proc);

	/* プロセスリストから削除する。 */
	delProcList(proc);

	/* 子プロセスの開放。 */
	releaseChildProc(proc);

	parent = proc->parent;

	--parent->count_child;

	/* ファイルディスクリプタの開放。 */
	releaseFileStruct(proc->file_struct);

	/* タイマーの開放。 */
	releaseTimer(proc->timer);

	/* シグナルの開放。 */
	releaseSignal(proc->signal_struct);

	mm_struct = proc->mm_struct;
	proc->exit_state = state & 0xff;
	proc->signum = signum & 0xff;

	// デバイス使用不可例外プロセスのクリアー
	clearFpuBeforeProc();

	/* CPUタイムを親プロセスに足す。 */
	addCpuTimeToParent();

	/* タスクスケジュールから削除してwaitしている親を呼び出す。 */
	cli();
	enter_spinlock(&procLockGate);
	{
		{
//			static PROC tmp_proc[MAX_CPU];
			int cpu=get_current_cpu();

			del_from_schedule(TASK_EXIT, PROC_SCHEDULE_DEL);
//			tmp_proc[cpu].next=proc->next;
//			tmp_proc[cpu].prev=proc->prev;
//			cputask[cpu].current_task=&tmp_proc[cpu];
			--cputask[cpu].proc_num;
		}

		sendSignal(parent,SIGCHLD);
//		if ((isForeground(proc)) && (parent->state & TASK_CHILD_WAIT))
		if (parent->state & TASK_CHILD_WAIT)
			add_to_schedule(parent, TASK_SIGNAL_WAIT | TASK_SEND_SIGNAL_WAIT, NULL);
	}
	exit_spinlock(&procLockGate);

	/* 次のタスクにスイッチして、ページディレクトリを開放する。 */
	returnExit(mm_struct);
}


int sys_exit(int state)
{
	exit(state,0);

	return 0;
}


int sys_wait(int pid,int *stat_loc,int options)
{
	int rest;
	int state;
	PROC *proc = get_current_task();

	/* 調べるプロセス状態の設定。 */
	if (options & WUNTRACED)
		state = TASK_WAIT | TASK_SEND_SIGNAL_WAIT | TASK_EXIT;
	else
		state = TASK_TRACE | TASK_EXIT;

	/* 最初の子プロセス検索。 */
	if (pid > 0){
		rest = searchExitState(proc,pid,0,state,stat_loc);
	}
	else if (pid == 0){
		rest = searchExitState(proc,0,proc->pgid,state,stat_loc);
	}
	else if (pid == -1){
		rest = searchExitState(proc,0,0,state,stat_loc);
	}
	else{
		rest = searchExitState(proc,0,-pid,state,stat_loc);
	}

	if (0 < rest){
		return rest;
	}

	if ((rest < 0) && (options & WNOHANG)){
		return rest;
	}

	/* 待ち。 */
	del_from_schedule(TASK_SIGNAL_WAIT|TASK_CHILD_WAIT, PROC_SCHEDULE_DEL);
	wait_task();

	/* 子プロセス検索。 */
	if (pid > 0)
		rest = searchExitState(proc,pid,0,state,stat_loc);
	else if (pid == 0)
		rest = searchExitState(proc,0,proc->pgid,state,stat_loc);
	else if (pid == -1)
		rest = searchExitState(proc,0,0,state,stat_loc);
	else
		rest = searchExitState(proc,0,-pid,state,stat_loc);

	return rest;
}


int sys_getpid()
{
	return get_current_task()->pid;
}


int sys_getgid()
{
	return get_current_task()->gid;
}


int sys_getpgid(pid_t pid)
{
	if (pid == 0)
		return get_current_task()->pgid;
	else
	{
		PROC *proc = searchProcList(pid);
		
		if (proc == NULL)
			return -ESRCH;
		if (proc->sid != get_current_task()->sid)
			return -EPERM;
		return proc->pgid;
	}
}


int sys_getppid()
{
	return get_current_task()->parent->pid;
}


int sys_getuid()
{
	return get_current_task()->uid;
}


int sys_getsid(pid_t pid)
{
	if (pid == 0)
		return get_current_task()->sid;
	else
	{
		PROC *proc = searchProcList(pid);
		
		if (proc == NULL)
			return -ESRCH;
		if (proc->sid != get_current_task()->sid)
			return -EPERM;
		return proc->sid;
	}
}


int sys_setgid(gid_t gid)
{
	PROC *proc = get_current_task();


	if (proc->uid != 0)
		return -EPERM;
	proc->gid = gid;
	return 0;
}


int sys_setpgid(pid_t pid, pid_t pgid)
{
	PROC *proc,*pgproc;
	
	
	if (pid == 0)
		proc = get_current_task();
	else
	{
		proc = searchProcList(pid);
		if (proc == NULL)
			return -ESRCH;
		if ((proc != get_current_task()) && (proc->parent != get_current_task()))
			return -ESRCH;
	}
	if (pgid < 0)
		return -EINVAL;
	if (pgid == 0)
		pgid = proc->pid;
	
	/* Session leader */
	if (proc->sid == proc->pid)
		return -EPERM;
	if (proc->sid != get_current_task()->sid)
		return -EPERM;
	
	/* プロセスを異なるセッションのプロセスグループに移動させようとした */
	pgproc = searchProcList(pgid);
	if (pgproc == NULL)
		return -EPERM;
	if (pgproc->sid != proc->sid)
		return -EPERM;
	proc->pgid = pgid;

	return 0;
}


int sys_setuid(uid_t uid)
{
	PROC *proc = get_current_task();


	if (proc->uid != 0)
		return -EPERM;
	proc->uid = uid;
	return 0;
}


int sys_setsid()
{
	PROC *proc = get_current_task();
	
	
	if (proc->pgid != proc->pid)
	{
		proc->sid = proc->pid;
		proc->pgid = proc->pid;
		proc->ctlterm = NULL;
		
		return proc->sid;
	}
	else
		return -EPERM;
}


int sys_times(struct tms *tms)
{
	PROC *proc;


	if (checkMem(tms,sizeof(struct tms)) == -1)
		return -EFAULT;

	proc=get_current_task();
	tms->tms_stime=proc->cpu_time[0]/clock_1m/CLOCK_TICK;
	tms->tms_utime=proc->cpu_time[1]/clock_1m/CLOCK_TICK;
	tms->tms_cstime=proc->ctime[0];
	tms->tms_cutime=proc->ctime[1];

	return 0;
}


/******************************************************************************************************
 *
 * < 初期化クラス >
 *
 *******************************************************************************************************/

/*
 * GLOBAL
 * Init taskcpu
 * cpu順にシリアルに設定する必要がある
 * parameters : number of cpu
 * returns : 0
 */
int init_cputask(int cpu)
{
	cputask[cpu].cpu=cpu;
	cputask[cpu].current_task=NULL;
	cputask[cpu].proc_num=0;
	cputask[cpu].gate=0;

	return 0;
}


/*
 * GLOBAL
 * TSSディスクリプタを設定す
 * 引数 : ディスクリプタ値、TSSアドレス
 */
void set_tss(int des)
{
	set_gdt(des,(uint)&kernel_tss,104,TYPE_TSS);

	asm volatile(
		"movl	%0,%%eax\n"
		"ltr	%%ax"
		::"m"(des)
	);
}


/*
 * GLOBAL
 * Set idle process table
 * parameters : Page directory
 * returns : 0 or Error number
 */
int set_idle_proc(int cpu)
{
	/* Set process table */
	idle_proc[cpu] = kmalloc(sizeof(PROC));
	if (idle_proc[cpu] == NULL)
		return -ENOMEM;
	memset(idle_proc[cpu],0,sizeof(PROC));
	idle_proc[cpu]->next=idle_proc[cpu]->prev=idle_proc[cpu];
	idle_proc[cpu]->cpu=cpu;
	idle_proc[cpu]->state=TASK_RUNNING;

	/* init paging */
	if((idle_proc[cpu]->mm_struct=initPaging())==NULL)return -1;

	/* init file descriptor. */
	if(init_file_struct(idle_proc[cpu])==-1)return -ENOMEM;

	/* init signal. */
	if ((idle_proc[cpu]->signal_struct = setFirstSignal()) == NULL){
		return -ENOMEM;
	}

	/* add to schedule queue */
	cputask[cpu].current_task=idle_proc[cpu];

	/* プロセスリストの初期化。 */
	initProclist();

	return 0;
}


/*
 * GLOBAL
 * 最初のプロセスの設定。
 * return : 0 or error number
 */
int initProc1()
{
	proc1 = get_current_task();
	proc1->parent = NULL;

	return initProc1Fs();
}

/*************************************************************************************************/
void test_proc()
{
	PROC *proc;
	PROC *current;
	PROC *before;
	
	for (proc = current= get_current_task(), before = NULL;;){
		printk("0x%x", proc);
		
		before = proc;
		proc = proc->next;
		if ((proc == current) || (proc == before)){
			printk("\n");
			break;
		}
		printk("-");
	}
}
/**************************************************************************************************/
