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