xref: /titanic_50/usr/src/lib/libast/common/sfio/sfrd.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #include	"sfhdr.h"
23da2e3ebdSchin 
24da2e3ebdSchin /*	Internal function to do a hard read.
25da2e3ebdSchin **	This knows about discipline and memory mapping, peek read.
26da2e3ebdSchin **
27da2e3ebdSchin **	Written by Kiem-Phong Vo.
28da2e3ebdSchin */
29da2e3ebdSchin 
30da2e3ebdSchin /* synchronize unseekable write streams */
31da2e3ebdSchin #if __STD_C
_sfwrsync(void)32da2e3ebdSchin static void _sfwrsync(void)
33da2e3ebdSchin #else
34da2e3ebdSchin static void _sfwrsync()
35da2e3ebdSchin #endif
36da2e3ebdSchin {	reg Sfpool_t*	p;
37da2e3ebdSchin 	reg Sfio_t*	f;
38da2e3ebdSchin 	reg int		n;
39da2e3ebdSchin 
40da2e3ebdSchin 	/* sync all pool heads */
41da2e3ebdSchin 	for(p = _Sfpool.next; p; p = p->next)
42da2e3ebdSchin 	{	if(p->n_sf <= 0)
43da2e3ebdSchin 			continue;
44da2e3ebdSchin 		f = p->sf[0];
45da2e3ebdSchin 		if(!SFFROZEN(f) && f->next > f->data &&
46da2e3ebdSchin 		   (f->mode&SF_WRITE) && f->extent < 0 )
47da2e3ebdSchin 			(void)_sfflsbuf(f,-1);
48da2e3ebdSchin 	}
49da2e3ebdSchin 
50da2e3ebdSchin 	/* and all the ones in the discrete pool */
51da2e3ebdSchin 	for(n = 0; n < _Sfpool.n_sf; ++n)
52da2e3ebdSchin 	{	f = _Sfpool.sf[n];
53da2e3ebdSchin 
54da2e3ebdSchin 		if(!SFFROZEN(f) && f->next > f->data &&
55da2e3ebdSchin 		   (f->mode&SF_WRITE) && f->extent < 0 )
56da2e3ebdSchin 			(void)_sfflsbuf(f,-1);
57da2e3ebdSchin 	}
58da2e3ebdSchin }
59da2e3ebdSchin 
60da2e3ebdSchin #if __STD_C
sfrd(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)617c2fbfb3SApril Chin ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
62da2e3ebdSchin #else
63da2e3ebdSchin ssize_t sfrd(f,buf,n,disc)
647c2fbfb3SApril Chin Sfio_t*		f;
657c2fbfb3SApril Chin Void_t*		buf;
667c2fbfb3SApril Chin size_t		n;
67da2e3ebdSchin Sfdisc_t*	disc;
68da2e3ebdSchin #endif
69da2e3ebdSchin {
70da2e3ebdSchin 	Sfoff_t		r;
71da2e3ebdSchin 	reg Sfdisc_t*	dc;
72da2e3ebdSchin 	reg int		local, rcrv, dosync, oerrno;
737c2fbfb3SApril Chin 	SFMTXDECL(f);
74da2e3ebdSchin 
757c2fbfb3SApril Chin 	SFMTXENTER(f,-1);
76da2e3ebdSchin 
77da2e3ebdSchin 	GETLOCAL(f,local);
78da2e3ebdSchin 	if((rcrv = f->mode & (SF_RC|SF_RV)) )
79da2e3ebdSchin 		f->mode &= ~(SF_RC|SF_RV);
80da2e3ebdSchin 	f->bits &= ~SF_JUSTSEEK;
81da2e3ebdSchin 
82da2e3ebdSchin 	if(f->mode&SF_PKRD)
83da2e3ebdSchin 		SFMTXRETURN(f, -1);
84da2e3ebdSchin 
85da2e3ebdSchin 	if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
86da2e3ebdSchin 	{	if(f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
87da2e3ebdSchin 			SFMTXRETURN(f, -1);
88da2e3ebdSchin 		if(f->next < f->endb)
89da2e3ebdSchin 		{	if(SFSYNC(f) < 0)
90da2e3ebdSchin 				SFMTXRETURN(f, -1);
91da2e3ebdSchin 			if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
92da2e3ebdSchin 			{	f->endb = f->next = f->endr = f->data;
93da2e3ebdSchin 				f->mode &= ~SF_SYNCED;
94da2e3ebdSchin 			}
95da2e3ebdSchin #ifdef MAP_TYPE
96da2e3ebdSchin 			if((f->bits&SF_MMAP) && f->data)
97da2e3ebdSchin 			{	SFMUNMAP(f, f->data, f->endb-f->data);
98da2e3ebdSchin 				f->data = NIL(uchar*);
99da2e3ebdSchin 			}
100da2e3ebdSchin #endif
101da2e3ebdSchin 			f->next = f->endb = f->endr = f->endw = f->data;
102da2e3ebdSchin 		}
103da2e3ebdSchin 	}
104da2e3ebdSchin 
105da2e3ebdSchin 	for(dosync = 0;;)
106da2e3ebdSchin 	{	/* stream locked by sfsetfd() */
107da2e3ebdSchin 		if(!(f->flags&SF_STRING) && f->file < 0)
108da2e3ebdSchin 			SFMTXRETURN(f, 0);
109da2e3ebdSchin 
110da2e3ebdSchin 		f->flags &= ~(SF_EOF|SF_ERROR);
111da2e3ebdSchin 
112da2e3ebdSchin 		dc = disc;
113da2e3ebdSchin 		if(f->flags&SF_STRING)
114da2e3ebdSchin 		{	if((r = (f->data+f->extent) - f->next) < 0)
115da2e3ebdSchin 				r = 0;
116da2e3ebdSchin 			if(r <= 0)
117da2e3ebdSchin 				goto do_except;
118da2e3ebdSchin 			SFMTXRETURN(f, (ssize_t)r);
119da2e3ebdSchin 		}
120da2e3ebdSchin 
121da2e3ebdSchin 		/* warn that a read is about to happen */
122da2e3ebdSchin 		SFDISC(f,dc,readf);
123da2e3ebdSchin 		if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
124da2e3ebdSchin 		{	reg int	rv;
125da2e3ebdSchin 			if(local)
126da2e3ebdSchin 				SETLOCAL(f);
127da2e3ebdSchin 			if((rv = _sfexcept(f,SF_READ,n,dc)) > 0)
128da2e3ebdSchin 				n = rv;
129da2e3ebdSchin 			else if(rv < 0)
130da2e3ebdSchin 			{	f->flags |= SF_ERROR;
131da2e3ebdSchin 				SFMTXRETURN(f, (ssize_t)rv);
132da2e3ebdSchin 			}
133da2e3ebdSchin 		}
134da2e3ebdSchin 
135da2e3ebdSchin #ifdef MAP_TYPE
136da2e3ebdSchin 		if(f->bits&SF_MMAP)
137da2e3ebdSchin 		{	reg ssize_t	a, round;
138da2e3ebdSchin 			sfstat_t	st;
139da2e3ebdSchin 
140da2e3ebdSchin 			/* determine if we have to copy data to buffer */
141da2e3ebdSchin 			if((uchar*)buf >= f->data && (uchar*)buf <= f->endb)
142da2e3ebdSchin 			{	n += f->endb - f->next;
143da2e3ebdSchin 				buf = NIL(char*);
144da2e3ebdSchin 			}
145da2e3ebdSchin 
146da2e3ebdSchin 			/* actual seek location */
147da2e3ebdSchin 			if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
148da2e3ebdSchin 			   (r = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc)) != f->here)
149da2e3ebdSchin 				f->here = r;
150da2e3ebdSchin 			else	f->here -= f->endb-f->next;
151da2e3ebdSchin 
152da2e3ebdSchin 			/* before mapping, make sure we have data to map */
153da2e3ebdSchin 			if((f->flags&SF_SHARE) || (size_t)(r = f->extent-f->here) < n)
154da2e3ebdSchin 			{	if((r = sysfstatf(f->file,&st)) < 0)
155da2e3ebdSchin 					goto do_except;
156da2e3ebdSchin 				if((r = (f->extent = st.st_size) - f->here) <= 0 )
157da2e3ebdSchin 				{	r = 0;	/* eof */
158da2e3ebdSchin 					goto do_except;
159da2e3ebdSchin 				}
160da2e3ebdSchin 			}
161da2e3ebdSchin 
162da2e3ebdSchin 			/* make sure current position is page aligned */
163da2e3ebdSchin 			if((a = (size_t)(f->here%_Sfpage)) != 0)
164da2e3ebdSchin 			{	f->here -= a;
165da2e3ebdSchin 				r += a;
166da2e3ebdSchin 			}
167da2e3ebdSchin 
168da2e3ebdSchin 			/* map minimal requirement */
169da2e3ebdSchin 			if(r > (round = (1 + (n+a)/f->size)*f->size) )
170da2e3ebdSchin 				r = round;
171da2e3ebdSchin 
172da2e3ebdSchin 			if(f->data)
173da2e3ebdSchin 				SFMUNMAP(f, f->data, f->endb-f->data);
174da2e3ebdSchin 
175da2e3ebdSchin 			for(;;)
176da2e3ebdSchin 			{	f->data = (uchar*) sysmmapf((caddr_t)0, (size_t)r,
177da2e3ebdSchin 							(PROT_READ|PROT_WRITE),
178da2e3ebdSchin 							MAP_PRIVATE,
179da2e3ebdSchin 							f->file, (sfoff_t)f->here);
180da2e3ebdSchin 				if(f->data && (caddr_t)f->data != (caddr_t)(-1))
181da2e3ebdSchin 					break;
182da2e3ebdSchin 				else
183da2e3ebdSchin 				{	f->data = NIL(uchar*);
184da2e3ebdSchin 					if((r >>= 1) < (_Sfpage*SF_NMAP) ||
185da2e3ebdSchin 					   (errno != EAGAIN && errno != ENOMEM) )
186da2e3ebdSchin 						break;
187da2e3ebdSchin 				}
188da2e3ebdSchin 			}
189da2e3ebdSchin 
190da2e3ebdSchin 			if(f->data)
191da2e3ebdSchin 			{	if(f->bits&SF_SEQUENTIAL)
192da2e3ebdSchin 					SFMMSEQON(f,f->data,r);
193da2e3ebdSchin 				f->next = f->data+a;
194da2e3ebdSchin 				f->endr = f->endb = f->data+r;
195da2e3ebdSchin 				f->endw = f->data;
196da2e3ebdSchin 				f->here += r;
197da2e3ebdSchin 
198da2e3ebdSchin 				/* make known our seek location */
199da2e3ebdSchin 				(void)SFSK(f,f->here,SEEK_SET,dc);
200da2e3ebdSchin 
201da2e3ebdSchin 				if(buf)
202da2e3ebdSchin 				{	if(n > (size_t)(r-a))
203da2e3ebdSchin 						n = (ssize_t)(r-a);
204da2e3ebdSchin 					memcpy(buf,f->next,n);
205da2e3ebdSchin 					f->next += n;
206da2e3ebdSchin 				}
207da2e3ebdSchin 				else	n = f->endb - f->next;
208da2e3ebdSchin 
209da2e3ebdSchin 				SFMTXRETURN(f, n);
210da2e3ebdSchin 			}
211da2e3ebdSchin 			else
212da2e3ebdSchin 			{	r = -1;
213da2e3ebdSchin 				f->here += a;
214da2e3ebdSchin 
215da2e3ebdSchin 				/* reset seek pointer to its physical location */
216da2e3ebdSchin 				(void)SFSK(f,f->here,SEEK_SET,dc);
217da2e3ebdSchin 
218da2e3ebdSchin 				/* make a buffer */
219da2e3ebdSchin 				(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
220da2e3ebdSchin 
221da2e3ebdSchin 				if(!buf)
222da2e3ebdSchin 				{	buf = (Void_t*)f->data;
223da2e3ebdSchin 					n = f->size;
224da2e3ebdSchin 				}
225da2e3ebdSchin 			}
226da2e3ebdSchin 		}
227da2e3ebdSchin #endif
228da2e3ebdSchin 
229da2e3ebdSchin 		/* sync unseekable write streams to prevent deadlock */
230da2e3ebdSchin 		if(!dosync && f->extent < 0)
231da2e3ebdSchin 		{	dosync = 1;
232da2e3ebdSchin 			_sfwrsync();
233da2e3ebdSchin 		}
234da2e3ebdSchin 
235da2e3ebdSchin 		/* make sure file pointer is right */
236da2e3ebdSchin 		if(f->extent >= 0 && (f->flags&SF_SHARE) )
237da2e3ebdSchin 		{	if(!(f->flags&SF_PUBLIC) )
238da2e3ebdSchin 				f->here = SFSK(f,f->here,SEEK_SET,dc);
239da2e3ebdSchin 			else	f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
240da2e3ebdSchin 		}
241da2e3ebdSchin 
242da2e3ebdSchin 		oerrno = errno;
243da2e3ebdSchin 		errno = 0;
244da2e3ebdSchin 
245da2e3ebdSchin 		if(dc && dc->readf)
246da2e3ebdSchin 		{	int	share = f->flags&SF_SHARE;
247da2e3ebdSchin 
248da2e3ebdSchin 			if(rcrv) /* pass on rcrv for possible continuations */
249da2e3ebdSchin 				f->mode |= rcrv;
250da2e3ebdSchin 				/* tell readf that no peeking necessary */
251da2e3ebdSchin 			else	f->flags &= ~SF_SHARE;
252da2e3ebdSchin 
253da2e3ebdSchin 			SFDCRD(f,buf,n,dc,r);
254da2e3ebdSchin 
255da2e3ebdSchin 			/* reset flags */
256da2e3ebdSchin 			if(rcrv)
257da2e3ebdSchin 				f->mode &= ~rcrv;
258da2e3ebdSchin 			else	f->flags |= share;
259da2e3ebdSchin 		}
260da2e3ebdSchin 		else if(SFISNULL(f))
261da2e3ebdSchin 			r = 0;
262da2e3ebdSchin 		else if(f->extent < 0 && (f->flags&SF_SHARE) && rcrv)
263da2e3ebdSchin 		{	/* try peek read */
264da2e3ebdSchin 			r = sfpkrd(f->file, (char*)buf, n,
265da2e3ebdSchin 				    (rcrv&SF_RC) ? (int)f->getr : -1,
266da2e3ebdSchin 				    -1L, (rcrv&SF_RV) ? 1 : 0);
267da2e3ebdSchin 			if(r > 0)
268da2e3ebdSchin 			{	if(rcrv&SF_RV)
269da2e3ebdSchin 					f->mode |= SF_PKRD;
270da2e3ebdSchin 				else	f->mode |= SF_RC;
271da2e3ebdSchin 			}
272da2e3ebdSchin 		}
273da2e3ebdSchin 		else	r = sysreadf(f->file,buf,n);
274da2e3ebdSchin 
275da2e3ebdSchin 		if(errno == 0 )
276da2e3ebdSchin 			errno = oerrno;
277da2e3ebdSchin 
278da2e3ebdSchin 		if(r > 0 )
279da2e3ebdSchin 		{	if(!(f->bits&SF_DCDOWN) )	/* not a continuation call */
280da2e3ebdSchin 			{	if(!(f->mode&SF_PKRD) )
281da2e3ebdSchin 				{	f->here += r;
282da2e3ebdSchin 					if(f->extent >= 0 && f->extent < f->here)
283da2e3ebdSchin 						f->extent = f->here;
284da2e3ebdSchin 				}
285da2e3ebdSchin 				if((uchar*)buf >= f->data &&
286da2e3ebdSchin 				   (uchar*)buf < f->data+f->size)
287da2e3ebdSchin 					f->endb = f->endr = ((uchar*)buf) + r;
288da2e3ebdSchin 			}
289da2e3ebdSchin 
290da2e3ebdSchin 			SFMTXRETURN(f, (ssize_t)r);
291da2e3ebdSchin 		}
292da2e3ebdSchin 
293da2e3ebdSchin 	do_except:
294da2e3ebdSchin 		if(local)
295da2e3ebdSchin 			SETLOCAL(f);
296da2e3ebdSchin 		switch(_sfexcept(f,SF_READ,(ssize_t)r,dc))
297da2e3ebdSchin 		{
298da2e3ebdSchin 		case SF_ECONT :
299da2e3ebdSchin 			goto do_continue;
300da2e3ebdSchin 		case SF_EDONE :
301da2e3ebdSchin 			n = local ? 0 : (ssize_t)r;
302da2e3ebdSchin 			SFMTXRETURN(f,n);
303da2e3ebdSchin 		case SF_EDISC :
304da2e3ebdSchin 			if(!local && !(f->flags&SF_STRING))
305da2e3ebdSchin 				goto do_continue;
306da2e3ebdSchin 			/* else fall thru */
307da2e3ebdSchin 		case SF_ESTACK :
308da2e3ebdSchin 			SFMTXRETURN(f, -1);
309da2e3ebdSchin 		}
310da2e3ebdSchin 
311da2e3ebdSchin 	do_continue:
312da2e3ebdSchin 		for(dc = f->disc; dc; dc = dc->disc)
313da2e3ebdSchin 			if(dc == disc)
314da2e3ebdSchin 				break;
315da2e3ebdSchin 		disc = dc;
316da2e3ebdSchin 	}
317da2e3ebdSchin }
318