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