Blame src/lib/libast/sfio/sfrd.c

Packit 992a25
/***********************************************************************
Packit 992a25
*                                                                      *
Packit 992a25
*               This software is part of the ast package               *
Packit 992a25
*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
Packit 992a25
*                      and is licensed under the                       *
Packit 992a25
*                 Eclipse Public License, Version 1.0                  *
Packit 992a25
*                    by AT&T Intellectual Property                     *
Packit 992a25
*                                                                      *
Packit 992a25
*                A copy of the License is available at                 *
Packit 992a25
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit 992a25
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit 992a25
*                                                                      *
Packit 992a25
*              Information and Software Systems Research               *
Packit 992a25
*                            AT&T Research                             *
Packit 992a25
*                           Florham Park NJ                            *
Packit 992a25
*                                                                      *
Packit 992a25
*                 Glenn Fowler <gsf@research.att.com>                  *
Packit 992a25
*                  David Korn <dgk@research.att.com>                   *
Packit 992a25
*                   Phong Vo <kpv@research.att.com>                    *
Packit 992a25
*                                                                      *
Packit 992a25
***********************************************************************/
Packit 992a25
#include	"sfhdr.h"
Packit 992a25
Packit 992a25
/*	Internal function to do a hard read.
Packit 992a25
**	This knows about discipline and memory mapping, peek read.
Packit 992a25
**
Packit 992a25
**	Written by Kiem-Phong Vo.
Packit 992a25
*/
Packit 992a25
Packit 992a25
/* synchronize unseekable write streams */
Packit 992a25
#if __STD_C
Packit 992a25
static void _sfwrsync(void)
Packit 992a25
#else
Packit 992a25
static void _sfwrsync()
Packit 992a25
#endif
Packit 992a25
{	reg Sfpool_t*	p;
Packit 992a25
	reg Sfio_t*	f;
Packit 992a25
	reg int		n;
Packit 992a25
Packit 992a25
	/* sync all pool heads */
Packit 992a25
	for(p = _Sfpool.next; p; p = p->next)
Packit 992a25
	{	if(p->n_sf <= 0)
Packit 992a25
			continue;
Packit 992a25
		f = p->sf[0];
Packit 992a25
		if(!SFFROZEN(f) && f->next > f->data &&
Packit 992a25
		   (f->mode&SF_WRITE) && f->extent < 0 )
Packit 992a25
			(void)_sfflsbuf(f,-1);
Packit 992a25
	}
Packit 992a25
Packit 992a25
	/* and all the ones in the discrete pool */
Packit 992a25
	for(n = 0; n < _Sfpool.n_sf; ++n)
Packit 992a25
	{	f = _Sfpool.sf[n];
Packit 992a25
Packit 992a25
		if(!SFFROZEN(f) && f->next > f->data &&
Packit 992a25
		   (f->mode&SF_WRITE) && f->extent < 0 )
Packit 992a25
			(void)_sfflsbuf(f,-1);
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
#if __STD_C
Packit 992a25
ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
Packit 992a25
#else
Packit 992a25
ssize_t sfrd(f,buf,n,disc)
Packit 992a25
Sfio_t*		f;
Packit 992a25
Void_t*		buf;
Packit 992a25
size_t		n;
Packit 992a25
Sfdisc_t*	disc;
Packit 992a25
#endif
Packit 992a25
{
Packit 992a25
	Sfoff_t		r;
Packit 992a25
	reg Sfdisc_t*	dc;
Packit 992a25
	reg int		local, rcrv, dosync, oerrno;
Packit 992a25
	SFMTXDECL(f);
Packit 992a25
Packit 992a25
	SFMTXENTER(f,-1);
Packit 992a25
Packit 992a25
	GETLOCAL(f,local);
Packit 992a25
	if((rcrv = f->mode & (SF_RC|SF_RV)) )
Packit 992a25
		f->mode &= ~(SF_RC|SF_RV);
Packit 992a25
	f->bits &= ~SF_JUSTSEEK;
Packit 992a25
Packit 992a25
	if(f->mode&SF_PKRD)
Packit 992a25
		SFMTXRETURN(f, -1);
Packit 992a25
Packit 992a25
	if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
Packit 992a25
	{	if(f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
Packit 992a25
			SFMTXRETURN(f, -1);
Packit 992a25
		if(f->next < f->endb)
Packit 992a25
		{	if(SFSYNC(f) < 0)
Packit 992a25
				SFMTXRETURN(f, -1);
Packit 992a25
			if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
Packit 992a25
			{	f->endb = f->next = f->endr = f->data;
Packit 992a25
				f->mode &= ~SF_SYNCED;
Packit 992a25
			}
Packit 992a25
#ifdef MAP_TYPE
Packit 992a25
			if((f->bits&SF_MMAP) && f->data)
Packit 992a25
			{	SFMUNMAP(f, f->data, f->endb-f->data);
Packit 992a25
				f->data = NIL(uchar*);
Packit 992a25
			}
Packit 992a25
#endif
Packit 992a25
			f->next = f->endb = f->endr = f->endw = f->data;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
Packit 992a25
	for(dosync = 0;;)
Packit 992a25
	{	/* stream locked by sfsetfd() */
Packit 992a25
		if(!(f->flags&SF_STRING) && f->file < 0)
Packit 992a25
			SFMTXRETURN(f, 0);
Packit 992a25
Packit 992a25
		f->flags &= ~(SF_EOF|SF_ERROR);
Packit 992a25
Packit 992a25
		dc = disc;
Packit 992a25
		if(f->flags&SF_STRING)
Packit 992a25
		{	if((r = (f->data+f->extent) - f->next) < 0)
Packit 992a25
				r = 0;
Packit 992a25
			if(r <= 0)
Packit 992a25
				goto do_except;
Packit 992a25
			SFMTXRETURN(f, (ssize_t)r);
Packit 992a25
		}
Packit 992a25
Packit 992a25
		/* warn that a read is about to happen */
Packit 992a25
		SFDISC(f,dc,readf);
Packit 992a25
		if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
Packit 992a25
		{	reg int	rv;
Packit 992a25
			if(local)
Packit 992a25
				SETLOCAL(f);
Packit 992a25
			if((rv = _sfexcept(f,SF_READ,n,dc)) > 0)
Packit 992a25
				n = rv;
Packit 992a25
			else if(rv < 0)
Packit 992a25
			{	f->flags |= SF_ERROR;
Packit 992a25
				SFMTXRETURN(f, (ssize_t)rv);
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
Packit 992a25
#ifdef MAP_TYPE
Packit 992a25
		if(f->bits&SF_MMAP)
Packit 992a25
		{	reg ssize_t	a, round;
Packit 992a25
			sfstat_t	st;
Packit 992a25
Packit 992a25
			/* determine if we have to copy data to buffer */
Packit 992a25
			if((uchar*)buf >= f->data && (uchar*)buf <= f->endb)
Packit 992a25
			{	n += f->endb - f->next;
Packit 992a25
				buf = NIL(char*);
Packit 992a25
			}
Packit 992a25
Packit 992a25
			/* actual seek location */
Packit 992a25
			if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
Packit 992a25
			   (r = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc)) != f->here)
Packit 992a25
				f->here = r;
Packit 992a25
			else	f->here -= f->endb-f->next;
Packit 992a25
Packit 992a25
			/* before mapping, make sure we have data to map */
Packit 992a25
			if((f->flags&SF_SHARE) || (size_t)(r = f->extent-f->here) < n)
Packit 992a25
			{	if((r = sysfstatf(f->file,&st)) < 0)
Packit 992a25
					goto do_except;
Packit 992a25
				if((r = (f->extent = st.st_size) - f->here) <= 0 )
Packit 992a25
				{	r = 0;	/* eof */
Packit 992a25
					goto do_except;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
Packit 992a25
			/* make sure current position is page aligned */
Packit 992a25
			if((a = (size_t)(f->here%_Sfpage)) != 0)
Packit 992a25
			{	f->here -= a;
Packit 992a25
				r += a;
Packit 992a25
			}
Packit 992a25
Packit 992a25
			/* map minimal requirement */
Packit 992a25
			if(r > (round = (1 + (n+a)/f->size)*f->size) )
Packit 992a25
				r = round;
Packit 992a25
Packit 992a25
			if(f->data)
Packit 992a25
				SFMUNMAP(f, f->data, f->endb-f->data);
Packit 992a25
Packit 992a25
			for(;;)
Packit 992a25
			{	f->data = (uchar*) sysmmapf((caddr_t)0, (size_t)r,
Packit 992a25
							(PROT_READ|PROT_WRITE),
Packit 992a25
							MAP_PRIVATE,
Packit 992a25
							f->file, (sfoff_t)f->here);
Packit 992a25
				if(f->data && (caddr_t)f->data != (caddr_t)(-1))
Packit 992a25
					break;
Packit 992a25
				else
Packit 992a25
				{	f->data = NIL(uchar*);
Packit 992a25
					if((r >>= 1) < (_Sfpage*SF_NMAP) ||
Packit 992a25
					   (errno != EAGAIN && errno != ENOMEM) )
Packit 992a25
						break;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
Packit 992a25
			if(f->data)
Packit 992a25
			{	if(f->bits&SF_SEQUENTIAL)
Packit 992a25
					SFMMSEQON(f,f->data,r);
Packit 992a25
				f->next = f->data+a;
Packit 992a25
				f->endr = f->endb = f->data+r;
Packit 992a25
				f->endw = f->data;
Packit 992a25
				f->here += r;
Packit 992a25
Packit 992a25
				/* make known our seek location */
Packit 992a25
				(void)SFSK(f,f->here,SEEK_SET,dc);
Packit 992a25
Packit 992a25
				if(buf)
Packit 992a25
				{	if(n > (size_t)(r-a))
Packit 992a25
						n = (ssize_t)(r-a);
Packit 992a25
					memcpy(buf,f->next,n);
Packit 992a25
					f->next += n;
Packit 992a25
				}
Packit 992a25
				else	n = f->endb - f->next;
Packit 992a25
Packit 992a25
				SFMTXRETURN(f, n);
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
			{	r = -1;
Packit 992a25
				f->here += a;
Packit 992a25
Packit 992a25
				/* reset seek pointer to its physical location */
Packit 992a25
				(void)SFSK(f,f->here,SEEK_SET,dc);
Packit 992a25
Packit 992a25
				/* make a buffer */
Packit 992a25
				(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
Packit 992a25
Packit 992a25
				if(!buf)
Packit 992a25
				{	buf = (Void_t*)f->data;
Packit 992a25
					n = f->size;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
#endif
Packit 992a25
Packit 992a25
		/* sync unseekable write streams to prevent deadlock */
Packit 992a25
		if(!dosync && f->extent < 0)
Packit 992a25
		{	dosync = 1;
Packit 992a25
			_sfwrsync();
Packit 992a25
		}
Packit 992a25
Packit 992a25
		/* make sure file pointer is right */
Packit 992a25
		if(f->extent >= 0 && (f->flags&SF_SHARE) )
Packit 992a25
		{	if(!(f->flags&SF_PUBLIC) )
Packit 992a25
				f->here = SFSK(f,f->here,SEEK_SET,dc);
Packit 992a25
			else	f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
Packit 992a25
		}
Packit 992a25
Packit 992a25
		oerrno = errno;
Packit 992a25
		errno = 0;
Packit 992a25
Packit 992a25
		if(dc && dc->readf)
Packit 992a25
		{	int	share = f->flags&SF_SHARE;
Packit 992a25
Packit 992a25
			if(rcrv) /* pass on rcrv for possible continuations */
Packit 992a25
				f->mode |= rcrv;
Packit 992a25
				/* tell readf that no peeking necessary */
Packit 992a25
			else	f->flags &= ~SF_SHARE;
Packit 992a25
Packit 992a25
			SFDCRD(f,buf,n,dc,r);
Packit 992a25
Packit 992a25
			/* reset flags */
Packit 992a25
			if(rcrv)
Packit 992a25
				f->mode &= ~rcrv;
Packit 992a25
			else	f->flags |= share;
Packit 992a25
		}
Packit 992a25
		else if(SFISNULL(f))
Packit 992a25
			r = 0;
Packit 992a25
		else if(f->extent < 0 && (f->flags&SF_SHARE) && rcrv)
Packit 992a25
		{	/* try peek read */
Packit 992a25
			r = sfpkrd(f->file, (char*)buf, n,
Packit 992a25
				    (rcrv&SF_RC) ? (int)f->getr : -1,
Packit 992a25
				    -1L, (rcrv&SF_RV) ? 1 : 0);
Packit 992a25
			if(r > 0)
Packit 992a25
			{	if(rcrv&SF_RV)
Packit 992a25
					f->mode |= SF_PKRD;
Packit 992a25
				else	f->mode |= SF_RC;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else	r = sysreadf(f->file,buf,n);
Packit 992a25
Packit 992a25
		if(errno == 0 )
Packit 992a25
			errno = oerrno;
Packit 992a25
Packit 992a25
		if(r > 0 )
Packit 992a25
		{	if(!(f->bits&SF_DCDOWN) )	/* not a continuation call */
Packit 992a25
			{	if(!(f->mode&SF_PKRD) )
Packit 992a25
				{	f->here += r;
Packit 992a25
					if(f->extent >= 0 && f->extent < f->here)
Packit 992a25
						f->extent = f->here;
Packit 992a25
				}
Packit 992a25
				if((uchar*)buf >= f->data &&
Packit 992a25
				   (uchar*)buf < f->data+f->size)
Packit 992a25
					f->endb = f->endr = ((uchar*)buf) + r;
Packit 992a25
			}
Packit 992a25
Packit 992a25
			SFMTXRETURN(f, (ssize_t)r);
Packit 992a25
		}
Packit 992a25
Packit 992a25
	do_except:
Packit 992a25
		if(local)
Packit 992a25
			SETLOCAL(f);
Packit 992a25
		switch(_sfexcept(f,SF_READ,(ssize_t)r,dc))
Packit 992a25
		{
Packit 992a25
		case SF_ECONT :
Packit 992a25
			goto do_continue;
Packit 992a25
		case SF_EDONE :
Packit 992a25
			n = local ? 0 : (ssize_t)r;
Packit 992a25
			SFMTXRETURN(f,n);
Packit 992a25
		case SF_EDISC :
Packit 992a25
			if(!local && !(f->flags&SF_STRING))
Packit 992a25
				goto do_continue;
Packit 992a25
			/* else fall thru */
Packit 992a25
		case SF_ESTACK :
Packit 992a25
			SFMTXRETURN(f, -1);
Packit 992a25
		}
Packit 992a25
Packit 992a25
	do_continue:
Packit 992a25
		for(dc = f->disc; dc; dc = dc->disc)
Packit 992a25
			if(dc == disc)
Packit 992a25
				break;
Packit 992a25
		disc = dc;
Packit 992a25
	}
Packit 992a25
}