xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfrd.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #include	"sfhdr.h"
234887Schin 
244887Schin /*	Internal function to do a hard read.
254887Schin **	This knows about discipline and memory mapping, peek read.
264887Schin **
274887Schin **	Written by Kiem-Phong Vo.
284887Schin */
294887Schin 
304887Schin /* synchronize unseekable write streams */
314887Schin #if __STD_C
_sfwrsync(void)324887Schin static void _sfwrsync(void)
334887Schin #else
344887Schin static void _sfwrsync()
354887Schin #endif
364887Schin {	reg Sfpool_t*	p;
374887Schin 	reg Sfio_t*	f;
384887Schin 	reg int		n;
394887Schin 
404887Schin 	/* sync all pool heads */
414887Schin 	for(p = _Sfpool.next; p; p = p->next)
424887Schin 	{	if(p->n_sf <= 0)
434887Schin 			continue;
444887Schin 		f = p->sf[0];
454887Schin 		if(!SFFROZEN(f) && f->next > f->data &&
464887Schin 		   (f->mode&SF_WRITE) && f->extent < 0 )
474887Schin 			(void)_sfflsbuf(f,-1);
484887Schin 	}
494887Schin 
504887Schin 	/* and all the ones in the discrete pool */
514887Schin 	for(n = 0; n < _Sfpool.n_sf; ++n)
524887Schin 	{	f = _Sfpool.sf[n];
534887Schin 
544887Schin 		if(!SFFROZEN(f) && f->next > f->data &&
554887Schin 		   (f->mode&SF_WRITE) && f->extent < 0 )
564887Schin 			(void)_sfflsbuf(f,-1);
574887Schin 	}
584887Schin }
594887Schin 
604887Schin #if __STD_C
sfrd(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)618462SApril.Chin@Sun.COM ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
624887Schin #else
634887Schin ssize_t sfrd(f,buf,n,disc)
648462SApril.Chin@Sun.COM Sfio_t*		f;
658462SApril.Chin@Sun.COM Void_t*		buf;
668462SApril.Chin@Sun.COM size_t		n;
674887Schin Sfdisc_t*	disc;
684887Schin #endif
694887Schin {
704887Schin 	Sfoff_t		r;
714887Schin 	reg Sfdisc_t*	dc;
724887Schin 	reg int		local, rcrv, dosync, oerrno;
738462SApril.Chin@Sun.COM 	SFMTXDECL(f);
744887Schin 
758462SApril.Chin@Sun.COM 	SFMTXENTER(f,-1);
764887Schin 
774887Schin 	GETLOCAL(f,local);
784887Schin 	if((rcrv = f->mode & (SF_RC|SF_RV)) )
794887Schin 		f->mode &= ~(SF_RC|SF_RV);
804887Schin 	f->bits &= ~SF_JUSTSEEK;
814887Schin 
824887Schin 	if(f->mode&SF_PKRD)
834887Schin 		SFMTXRETURN(f, -1);
844887Schin 
854887Schin 	if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
864887Schin 	{	if(f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
874887Schin 			SFMTXRETURN(f, -1);
884887Schin 		if(f->next < f->endb)
894887Schin 		{	if(SFSYNC(f) < 0)
904887Schin 				SFMTXRETURN(f, -1);
914887Schin 			if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
924887Schin 			{	f->endb = f->next = f->endr = f->data;
934887Schin 				f->mode &= ~SF_SYNCED;
944887Schin 			}
954887Schin #ifdef MAP_TYPE
964887Schin 			if((f->bits&SF_MMAP) && f->data)
974887Schin 			{	SFMUNMAP(f, f->data, f->endb-f->data);
984887Schin 				f->data = NIL(uchar*);
994887Schin 			}
1004887Schin #endif
1014887Schin 			f->next = f->endb = f->endr = f->endw = f->data;
1024887Schin 		}
1034887Schin 	}
1044887Schin 
1054887Schin 	for(dosync = 0;;)
1064887Schin 	{	/* stream locked by sfsetfd() */
1074887Schin 		if(!(f->flags&SF_STRING) && f->file < 0)
1084887Schin 			SFMTXRETURN(f, 0);
1094887Schin 
1104887Schin 		f->flags &= ~(SF_EOF|SF_ERROR);
1114887Schin 
1124887Schin 		dc = disc;
1134887Schin 		if(f->flags&SF_STRING)
1144887Schin 		{	if((r = (f->data+f->extent) - f->next) < 0)
1154887Schin 				r = 0;
1164887Schin 			if(r <= 0)
1174887Schin 				goto do_except;
1184887Schin 			SFMTXRETURN(f, (ssize_t)r);
1194887Schin 		}
1204887Schin 
1214887Schin 		/* warn that a read is about to happen */
1224887Schin 		SFDISC(f,dc,readf);
1234887Schin 		if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
1244887Schin 		{	reg int	rv;
1254887Schin 			if(local)
1264887Schin 				SETLOCAL(f);
1274887Schin 			if((rv = _sfexcept(f,SF_READ,n,dc)) > 0)
1284887Schin 				n = rv;
1294887Schin 			else if(rv < 0)
1304887Schin 			{	f->flags |= SF_ERROR;
1314887Schin 				SFMTXRETURN(f, (ssize_t)rv);
1324887Schin 			}
1334887Schin 		}
1344887Schin 
1354887Schin #ifdef MAP_TYPE
1364887Schin 		if(f->bits&SF_MMAP)
1374887Schin 		{	reg ssize_t	a, round;
1384887Schin 			sfstat_t	st;
1394887Schin 
1404887Schin 			/* determine if we have to copy data to buffer */
1414887Schin 			if((uchar*)buf >= f->data && (uchar*)buf <= f->endb)
1424887Schin 			{	n += f->endb - f->next;
1434887Schin 				buf = NIL(char*);
1444887Schin 			}
1454887Schin 
1464887Schin 			/* actual seek location */
1474887Schin 			if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
1484887Schin 			   (r = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc)) != f->here)
1494887Schin 				f->here = r;
1504887Schin 			else	f->here -= f->endb-f->next;
1514887Schin 
1524887Schin 			/* before mapping, make sure we have data to map */
1534887Schin 			if((f->flags&SF_SHARE) || (size_t)(r = f->extent-f->here) < n)
1544887Schin 			{	if((r = sysfstatf(f->file,&st)) < 0)
1554887Schin 					goto do_except;
1564887Schin 				if((r = (f->extent = st.st_size) - f->here) <= 0 )
1574887Schin 				{	r = 0;	/* eof */
1584887Schin 					goto do_except;
1594887Schin 				}
1604887Schin 			}
1614887Schin 
1624887Schin 			/* make sure current position is page aligned */
1634887Schin 			if((a = (size_t)(f->here%_Sfpage)) != 0)
1644887Schin 			{	f->here -= a;
1654887Schin 				r += a;
1664887Schin 			}
1674887Schin 
1684887Schin 			/* map minimal requirement */
1694887Schin 			if(r > (round = (1 + (n+a)/f->size)*f->size) )
1704887Schin 				r = round;
1714887Schin 
1724887Schin 			if(f->data)
1734887Schin 				SFMUNMAP(f, f->data, f->endb-f->data);
1744887Schin 
1754887Schin 			for(;;)
1764887Schin 			{	f->data = (uchar*) sysmmapf((caddr_t)0, (size_t)r,
1774887Schin 							(PROT_READ|PROT_WRITE),
1784887Schin 							MAP_PRIVATE,
1794887Schin 							f->file, (sfoff_t)f->here);
1804887Schin 				if(f->data && (caddr_t)f->data != (caddr_t)(-1))
1814887Schin 					break;
1824887Schin 				else
1834887Schin 				{	f->data = NIL(uchar*);
1844887Schin 					if((r >>= 1) < (_Sfpage*SF_NMAP) ||
1854887Schin 					   (errno != EAGAIN && errno != ENOMEM) )
1864887Schin 						break;
1874887Schin 				}
1884887Schin 			}
1894887Schin 
1904887Schin 			if(f->data)
1914887Schin 			{	if(f->bits&SF_SEQUENTIAL)
1924887Schin 					SFMMSEQON(f,f->data,r);
1934887Schin 				f->next = f->data+a;
1944887Schin 				f->endr = f->endb = f->data+r;
1954887Schin 				f->endw = f->data;
1964887Schin 				f->here += r;
1974887Schin 
1984887Schin 				/* make known our seek location */
1994887Schin 				(void)SFSK(f,f->here,SEEK_SET,dc);
2004887Schin 
2014887Schin 				if(buf)
2024887Schin 				{	if(n > (size_t)(r-a))
2034887Schin 						n = (ssize_t)(r-a);
2044887Schin 					memcpy(buf,f->next,n);
2054887Schin 					f->next += n;
2064887Schin 				}
2074887Schin 				else	n = f->endb - f->next;
2084887Schin 
2094887Schin 				SFMTXRETURN(f, n);
2104887Schin 			}
2114887Schin 			else
2124887Schin 			{	r = -1;
2134887Schin 				f->here += a;
2144887Schin 
2154887Schin 				/* reset seek pointer to its physical location */
2164887Schin 				(void)SFSK(f,f->here,SEEK_SET,dc);
2174887Schin 
2184887Schin 				/* make a buffer */
2194887Schin 				(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
2204887Schin 
2214887Schin 				if(!buf)
2224887Schin 				{	buf = (Void_t*)f->data;
2234887Schin 					n = f->size;
2244887Schin 				}
2254887Schin 			}
2264887Schin 		}
2274887Schin #endif
2284887Schin 
2294887Schin 		/* sync unseekable write streams to prevent deadlock */
2304887Schin 		if(!dosync && f->extent < 0)
2314887Schin 		{	dosync = 1;
2324887Schin 			_sfwrsync();
2334887Schin 		}
2344887Schin 
2354887Schin 		/* make sure file pointer is right */
2364887Schin 		if(f->extent >= 0 && (f->flags&SF_SHARE) )
2374887Schin 		{	if(!(f->flags&SF_PUBLIC) )
2384887Schin 				f->here = SFSK(f,f->here,SEEK_SET,dc);
2394887Schin 			else	f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
2404887Schin 		}
2414887Schin 
2424887Schin 		oerrno = errno;
2434887Schin 		errno = 0;
2444887Schin 
2454887Schin 		if(dc && dc->readf)
2464887Schin 		{	int	share = f->flags&SF_SHARE;
2474887Schin 
2484887Schin 			if(rcrv) /* pass on rcrv for possible continuations */
2494887Schin 				f->mode |= rcrv;
2504887Schin 				/* tell readf that no peeking necessary */
2514887Schin 			else	f->flags &= ~SF_SHARE;
2524887Schin 
2534887Schin 			SFDCRD(f,buf,n,dc,r);
2544887Schin 
2554887Schin 			/* reset flags */
2564887Schin 			if(rcrv)
2574887Schin 				f->mode &= ~rcrv;
2584887Schin 			else	f->flags |= share;
2594887Schin 		}
2604887Schin 		else if(SFISNULL(f))
2614887Schin 			r = 0;
2624887Schin 		else if(f->extent < 0 && (f->flags&SF_SHARE) && rcrv)
2634887Schin 		{	/* try peek read */
2644887Schin 			r = sfpkrd(f->file, (char*)buf, n,
2654887Schin 				    (rcrv&SF_RC) ? (int)f->getr : -1,
2664887Schin 				    -1L, (rcrv&SF_RV) ? 1 : 0);
2674887Schin 			if(r > 0)
2684887Schin 			{	if(rcrv&SF_RV)
2694887Schin 					f->mode |= SF_PKRD;
2704887Schin 				else	f->mode |= SF_RC;
2714887Schin 			}
2724887Schin 		}
2734887Schin 		else	r = sysreadf(f->file,buf,n);
2744887Schin 
2754887Schin 		if(errno == 0 )
2764887Schin 			errno = oerrno;
2774887Schin 
2784887Schin 		if(r > 0 )
2794887Schin 		{	if(!(f->bits&SF_DCDOWN) )	/* not a continuation call */
2804887Schin 			{	if(!(f->mode&SF_PKRD) )
2814887Schin 				{	f->here += r;
2824887Schin 					if(f->extent >= 0 && f->extent < f->here)
2834887Schin 						f->extent = f->here;
2844887Schin 				}
2854887Schin 				if((uchar*)buf >= f->data &&
2864887Schin 				   (uchar*)buf < f->data+f->size)
2874887Schin 					f->endb = f->endr = ((uchar*)buf) + r;
2884887Schin 			}
2894887Schin 
2904887Schin 			SFMTXRETURN(f, (ssize_t)r);
2914887Schin 		}
2924887Schin 
2934887Schin 	do_except:
2944887Schin 		if(local)
2954887Schin 			SETLOCAL(f);
2964887Schin 		switch(_sfexcept(f,SF_READ,(ssize_t)r,dc))
2974887Schin 		{
2984887Schin 		case SF_ECONT :
2994887Schin 			goto do_continue;
3004887Schin 		case SF_EDONE :
3014887Schin 			n = local ? 0 : (ssize_t)r;
3024887Schin 			SFMTXRETURN(f,n);
3034887Schin 		case SF_EDISC :
3044887Schin 			if(!local && !(f->flags&SF_STRING))
3054887Schin 				goto do_continue;
3064887Schin 			/* else fall thru */
3074887Schin 		case SF_ESTACK :
3084887Schin 			SFMTXRETURN(f, -1);
3094887Schin 		}
3104887Schin 
3114887Schin 	do_continue:
3124887Schin 		for(dc = f->disc; dc; dc = dc->disc)
3134887Schin 			if(dc == disc)
3144887Schin 				break;
3154887Schin 		disc = dc;
3164887Schin 	}
3174887Schin }
318