/**********************************************************************
 
	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.

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


#define STREAM_LIB

#include	<stdlib.h>
#include	<fcntl.h>
#include	"memory_debug.h"
#include	"stream.h"
#include	"task.h"

#define ZONBIE_LIFE_TIME	60

extern SEM stream_lock;
/*
int zonbie_ptr;
STREAM * close_zonbie[CLOSE_ZONBIE];
*/
extern STREAM * stream_list;
STREAM * close_zonbie_list;
int zonbie_life_time = ZONBIE_LIFE_TIME;
int zonbie_count;

void
_delete_stream_list(STREAM * s,char * file,int line)
{
STREAM ** sp;

	for ( sp = &stream_list ; *sp ; sp = &(*sp)->h.next ) {
		if ( *sp == s ) {
			*sp = s->h.next;
			return;
		}
	}
	fprintf(stderr,"FILE %s / %i\n",file,line);
	er_panic("_delete_stream_list");
}


void
zonbie_tick()
{
STREAM ** sp, * ss;
unsigned int now;
int life,_life;
	lock_task(stream_lock);
	now = get_xltime();
	life = 0;
	_life = 0;
	for ( sp = &close_zonbie_list ; *sp ; ) {
		ss = *sp;
		life =  ss->h.zonbie_access - ss->h.close_time;
		if ( zonbie_life_time < 2 * life )
			zonbie_life_time = 2 * life;
		if ( _life < life )
			_life = life;
		if ( now - ss->h.close_time < zonbie_life_time ) {
			sp = &ss->h.next;
			continue;
		}
		*sp = ss->h.next;
		d_f_ree(ss);
		zonbie_count --;
	}
	unlock_task(stream_lock,"zonbie_tick");
/*
printf("ZONBIE LIFE TIME c=%i lt=%i(%i)\n",zonbie_count,zonbie_life_time,_life);
*/
}

int
__d_s_close(STREAM * s,char * file,int line)
{
int ret;
char * buf;
int rbyte;
S_TABLE * tbl;
int i;

	ret = -1;
	if ( s == 0 )
		goto end;
	if ( s->h.tbl == 0 ) {
		s->h.zonbie_access = get_xltime();
/*
printf("CLOSE ZOMBIE ACCESS %i %i / %x\n",s->h.close_time,s->h.zonbie_access,s);
*/
		goto end;
	}

	for ( i = 0 ; i < 3 ; i ++ )
		if ( s == (STREAM*)&__s_std[i] )
			goto end;

	tbl = s->h.tbl;
	s->h.tbl = 0;
	if ( s->h.mode == O_WRONLY || s->h.mode == O_RDWR ) {
		buf = d_alloc(s->h.cm->max_ret,105);
		rbyte = (*s->h.cm->close)(buf,s->h.cm_work); 
		(*tbl->write)(s,buf,rbyte);
		d_f_ree(buf);
	}
	else {
		buf = d_alloc(s->h.cm->max_ret,105);
		rbyte = (*s->h.cm->close)(buf,s->h.cm_work); 
		d_f_ree(buf);
	}

	ret = (*tbl->close)(s);

	_delete_stream_list(s,file,line);
/*
	if ( close_zonbie[zonbie_ptr] )
		d_f_ree(close_zonbie[zonbie_ptr]);

	close_zonbie[zonbie_ptr] = s;
	zonbie_ptr ++;
	if ( zonbie_ptr >= CLOSE_ZONBIE )
		zonbie_ptr = 0;
*/

	zonbie_count ++;
	s->h.zonbie_access = s->h.close_time = get_xltime();
	s->h.next = close_zonbie_list;
	close_zonbie_list = s;
/*
printf("CLOSE %i %i - %i / %x\n",zonbie_count,get_tid(),get_xltime(),s);
*/
end:
	return ret;
}


int
_d_s_close(STREAM * s,char * file,int line)
{
int ret;
	lock_task(stream_lock);
	ret = __d_s_close(s,file,line);
	unlock_task(stream_lock,"s_close");
	return ret;
}
