/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/



#include	<sys/wait.h>
#include	<sys/time.h>
#include	<sys/types.h>
#include	<unistd.h>
#include	<stdlib.h>
#include	<stdio.h>
#include	<signal.h>
#include	<errno.h>
#include	"init.h"
#include	"task.h"
#include	"memory_debug.h"

void sigalarm_handler();
void sigpipe_handler();
void sigint_handler();
void siglwp_handler();

extern int task_flags;
int pri_table[PRI_MAX] = {0,10,20,30,40,50};

void
set_ignore_chld()
{
  struct sigaction sa;
  sa.sa_handler = SIG_IGN;
  sa.sa_flags = SA_NOCLDWAIT;
  sigemptyset(&sa.sa_mask);
  sigaction(SIGCHLD, &sa, NULL);
}

void
all_signal_mask_posix()
{
	all_signal_mask(1,45);
}

void
set_alarm_mask(int flags)
{
	all_signal_mask_posix();
	signal(SIGALRM,sigalarm_handler);
	signal(SIGPIPE,sigpipe_handler);
//	signal(SIGLWP,siglwp_handler);
	signal(SIGINT,sigint_handler);
	task_flags = flags;
	if ( (flags&INI_THREAD) == INI_DONTWAITCHI )
		set_ignore_chld();
}

sem_t*
new_semaphore()
{
sem_t * s;
char name[16];
static int sem_num;
extern char * command_arg;
		do {
		sprintf(name, "%d-%04i", getpid(), ++sem_num);
		s = sem_open(name, O_CREAT | O_EXCL, 0600, 0);
	} while ( s == SEM_FAILED );
	sem_trywait(s);
	sem_post(s);
	return s;
}



#ifndef DEADLOCK_CHECK
void
_lock_task(SEM s,char * file,int line)
{
int value;
retry:
	if ( _sem_getvalue(s,&value) < 0 || value > 1 )
		er_panic("lock_task1");
	errno = 0;
	if ( sem_wait(s) ) {
		if ( errno == EINTR )
			goto retry;
	}
	if ( _sem_getvalue(s,&value) < 0 || value >= 1 ) {
		printf("??????\n");
	  	goto retry;
		er_panic("lock_task");
	}
}
#endif

int test;

#ifdef DEADLOCK_CHECK
void
_lock_task(SEM s,char * file,int line)
{
SEM sp;
int tid;
int value;
extern SEM block_lock;


	if ( s == block_lock )
		goto retry;
	tid = _get_tid();
	for ( sp = sem_list ; sp ; sp = sp->next ){
		if ( s == sp ) {
			if ( sp->tid == tid ) {
				fprintf(stderr,"************* DOUBLELOCK\n");
				er_panic("lock_task");
			}
			break;
		}
		if ( sp->tid != tid )
			continue;
		fprintf(stderr,"************* DEADLOCK %i - %i\n",
			sp->level,s->level);
		er_panic("lock_task");
	}
retry:
	if ( _sem_getvalue(s,&value) < 0 || value > 1 )
		er_panic("lock_task1");
	errno = 0;
	if ( sem_wait(&s->s) ) {
		if ( errno == EINTR )
			goto retry;
	}
	if ( _sem_getvalue(s,&value) < 0 || value >= 1 ) {
		printf("??????\n");
		goto retry;
		er_panic("lock_task");
	}
	s->tid = tid;
}
#endif

#ifndef DEADLOCK_CHECK
void
_unlock_task(SEM s,char *str,char * file,int line)
{
int value;
	sem_post(s);
if ( _sem_getvalue(s,&value) < 0 || value >= 2 ) {
fprintf(stderr,"*********** ???? %s %i ************\n",str,_get_tid());
 er_panic("unlock_task");
}
}
#endif

#ifdef DEADLOCK_CHECK
void
_unlock_task(SEM s,char * str,char * file,int line)
{
int value;
	s->tid = 0;
if ( _sem_getvalue(s,&value) < 0 || value  != 0 )
printf("##########################3 %s\n",str);
	sem_post(&s->s);
if ( _sem_getvalue(s,&value) <0  || value >= 2 ) {
fprintf(stderr,"*********** ???? %s %i ************\n",str,_get_tid());
 er_panic("unlock_task");
}
}
#endif

#ifndef DEADLOCK_CHECK
void close_lock(SEM s)
{
	sem_close(s);
}
#endif
#ifdef DEADLOCK_CHECK
void close_lock(SEM s)
{
SEM * sp;
	for ( sp = &sem_list ; *sp ; sp = &(*sp)->next )
		if ( *sp == s ) {
			*sp = s->next;
			break;
		}
	sem_close(s->s);
}
#endif

#ifndef DEADLOCK_CHECK
SEM
new_lock(int level)
{
SEM s;
	s = new_semaphore();
	return s;
}
#endif
#ifdef DEADLOCK_CHECK
SEM
new_lock(int level)
{
SEM s, * sp;
	s = new_block();
	s->level = level;
	s->tid = 0;
	s->s = new_semaphore();
	for ( sp = &sem_list ; *sp ; sp = &(*sp)->next )
		if ( (*sp)->level > level ) {
			s->next = *sp;
			*sp = s;
			goto ok;
		}
	s->next = 0;
	*sp = s;
ok:
	return s;
}
#endif

int
_sem_getvalue(SEM s,int * value)
{
	*value = 0;
	return 0;
}

void
throw_signal(int tid,int sig)
{
	pthread_kill(get_hard_tid(tid),sig);
}



void
ss_do(void (*func)(void*),void * arg)
{
	(*func)(arg);
}
