1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/lib/libast/sfio/sfsetbuf.c
Martijn Dekker 4ca578bde4 libast/sfio: remove unused Vthread API and support code
Sfio may theoretically be compiled with threads support using a
separate AT&T library called Vthread, also by Kiem-Phong Vo. That
library was never shipped in the AST distribution, though. It is
only available with a standalone version of Sfio.

The only standalone Sfio version with Vthread that I've found is
from 2005, mirrored at <https://github.com/lichray/sfio>. More
recent versions never seem to have made it out of the defunct AT&T
software download site.

Even if they weren't, the rest of libast doesn't support threads,
and at this point it never will, so for our purposes the Sfio
threads code is never going to be usable. Meanwhile, macros such as
SFMTXENTER and SFMTXRETURN make the code a lot harder to read. And
not quite all threading code is disabled; some of it is dead code
that is getting compiled in.

Chances are that code now won't work properly in any case as we've
not had any chance to test it as we were making changes. Bit rot
has surely set in by now.

So this commit expands all the sfio/stdio threading-related macros
to their non-threads fallbacks (which is null for most of them, but
not all), deletes dead mutex-related code and struct fields, and
removes the related documentation from the sfio.3 man page. Unless
I did something wrong, there should be no change in behaviour.
2022-02-17 19:38:40 +00:00

419 lines
11 KiB
C

/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2011 AT&T Intellectual Property *
* Copyright (c) 2020-2022 Contributors to ksh 93u+m *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* http://www.eclipse.org/org/documents/epl-v10.html *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* 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> *
* *
***********************************************************************/
#if defined(__STDPP__directive) && defined(__STDPP__hide)
__STDPP__directive pragma pp:hide getpagesize
#else
#define getpagesize ______getpagesize
#endif
#include "sfhdr.h"
#if defined(__STDPP__directive) && defined(__STDPP__hide)
__STDPP__directive pragma pp:nohide getpagesize
#else
#undef getpagesize
#endif
#if _lib_getpagesize
extern int getpagesize(void);
#endif
/* Set a (new) buffer for a stream.
** If size < 0, it is assigned a suitable value depending on the
** kind of stream. The actual buffer size allocated is dependent
** on how much memory is available.
**
** Written by Kiem-Phong Vo.
*/
#if !_sys_stat
struct stat
{ int st_mode;
int st_size;
};
#undef fstat
#define fstat(fd,st) (-1)
#endif /*_sys_stat*/
#if _PACKAGE_ast && !defined(SFSETLINEMODE)
#define SFSETLINEMODE 1
#endif
#if SFSETLINEMODE
static int sfsetlinemode()
{ char* astsfio;
char* endw;
static int modes = -1;
static const char sf_line[] = "SF_LINE";
static const char sf_maxr[] = "SF_MAXR=";
static const char sf_wcwidth[] = "SF_WCWIDTH";
#define ISSEPAR(c) ((c) == ',' || (c) == ' ' || (c) == '\t')
if (modes < 0)
{ modes = 0;
if(astsfio = getenv("SFIO_OPTIONS"))
{ for(; *astsfio != 0; astsfio = endw)
{ while(ISSEPAR(*astsfio) )
++astsfio;
for(endw = astsfio; *endw && !ISSEPAR(*endw); ++endw)
;
if((endw-astsfio) > (sizeof(sf_line)-1) &&
strncmp(astsfio,sf_line,sizeof(sf_line)-1) == 0)
modes |= SF_LINE;
else if((endw-astsfio) > (sizeof(sf_maxr)-1) &&
strncmp(astsfio,sf_maxr,sizeof(sf_maxr)-1) == 0)
#if _PACKAGE_ast
_Sfmaxr = (ssize_t)strtonll(astsfio+sizeof(sf_maxr)-1,NiL,NiL,0);
#else
_Sfmaxr = (ssize_t)strtol(astsfio+sizeof(sf_maxr)-1,NiL,0);
#endif
else if((endw-astsfio) > (sizeof(sf_wcwidth)-1) &&
strncmp(astsfio,sf_wcwidth,sizeof(sf_wcwidth)-1) == 0)
modes |= SF_WCWIDTH;
}
}
}
return modes;
}
#endif
void* sfsetbuf(Sfio_t* f, /* stream to be buffered */
void* buf, /* new buffer */
size_t size) /* buffer size, -1 for default size */
{
int sf_malloc, oflags, init, okmmap, local;
ssize_t bufsize, blksz;
Sfdisc_t* disc;
struct stat st;
uchar* obuf = NIL(uchar*);
ssize_t osize = 0;
if(!f)
return NIL(void*);
GETLOCAL(f,local);
if(size == 0 && buf)
{ /* special case to get buffer info */
_Sfi = f->val = (f->bits&SF_MMAP) ? (f->endb-f->data) : f->size;
return (void*)f->data;
}
/* cleanup actions already done, don't allow write buffering any more */
if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE))
{ buf = NIL(void*);
size = 0;
}
if((init = f->mode&SF_INIT) )
{ if(!f->pool && _sfsetpool(f) < 0)
return NIL(void*);
}
else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0)
return NIL(void*);
if(init)
f->mode = (f->mode&SF_RDWR)|SF_LOCK;
else
{ int rv;
/* make sure there is no hidden read data */
if(f->proc && (f->flags&SF_READ) && (f->mode&SF_WRITE) &&
_sfmode(f,SF_READ,local) < 0)
return NIL(void*);
/* synchronize first */
SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local);
if(rv < 0)
return NIL(void*);
/* turn off the SF_SYNCED bit because buffer is changing */
f->mode &= ~SF_SYNCED;
}
SFLOCK(f,local);
if((Sfio_t*)buf != f)
blksz = -1;
else /* setting alignment size only */
{ blksz = (ssize_t)size;
if(!init) /* stream already initialized */
{ obuf = f->data;
osize = f->size;
goto done;
}
else /* initialize stream as if in the default case */
{ buf = NIL(void*);
size = (size_t)SF_UNBOUND;
}
}
bufsize = 0;
oflags = f->flags;
/* see if memory mapping is possible (see sfwrite for SF_BOTH) */
okmmap = (buf || (f->flags&SF_STRING) || (f->flags&SF_RDWR) == SF_RDWR) ? 0 : 1;
/* save old buffer info */
#ifdef MAP_TYPE
if(f->bits&SF_MMAP)
{ if(f->data)
{ SFMUNMAP(f,f->data,f->endb-f->data);
f->data = NIL(uchar*);
}
} else
#endif
if(f->data == f->tiny)
{ f->data = NIL(uchar*);
f->size = 0;
}
obuf = f->data;
osize = f->size;
f->flags &= ~SF_MALLOC;
f->bits &= ~SF_MMAP;
/* pure read/string streams must have a valid string */
if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR &&
(size == (size_t)SF_UNBOUND || !buf))
size = 0;
/* set disc to the first discipline with a seekf */
for(disc = f->disc; disc; disc = disc->disc)
if(disc->seekf)
break;
if((init || local) && !(f->flags&SF_STRING))
{ /* ASSERT(f->file >= 0) */
st.st_mode = 0;
/* if has discipline, set size by discipline if possible */
if(!_sys_stat || disc)
{ if((f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,disc)) < 0)
goto unseekable;
else
{ Sfoff_t e;
if((e = SFSK(f,(Sfoff_t)0,SEEK_END,disc)) >= 0)
f->extent = e > f->here ? e : f->here;
(void)SFSK(f,f->here,SEEK_SET,disc);
goto setbuf;
}
}
/* get file descriptor status */
if(fstat((int)f->file,&st) < 0)
f->here = -1;
else
{
#if _sys_stat && _stat_blksize /* preferred io block size */
f->blksz = (size_t)st.st_blksize;
#endif
bufsize = 64 * 1024;
if(S_ISDIR(st.st_mode) || (Sfoff_t)st.st_size < (Sfoff_t)SF_GRAIN)
okmmap = 0;
if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc);
else f->here = -1;
#if O_TEXT /* no memory mapping with O_TEXT because read()/write() alter data stream */
if(okmmap && f->here >= 0 &&
(fcntl((int)f->file,F_GETFL,0) & O_TEXT) )
okmmap = 0;
#endif
}
/* set page size, this is also the desired default buffer size */
if(_Sfpage <= 0)
{
#if _lib_getpagesize
if((_Sfpage = (size_t)getpagesize()) <= 0)
#endif
_Sfpage = SF_PAGE;
}
#if SFSETLINEMODE
if(init)
f->flags |= sfsetlinemode();
#endif
if(f->here >= 0)
{ f->extent = (Sfoff_t)st.st_size;
/* seekable std-devices are share-public by default */
if(f == sfstdin || f == sfstdout || f == sfstderr)
f->flags |= SF_SHARE|SF_PUBLIC;
}
else
{
unseekable:
f->extent = -1;
f->here = 0;
if(init)
{ if(S_ISCHR(st.st_mode) )
{ int oerrno = errno;
bufsize = SF_GRAIN;
/* set line mode for terminals */
if(!(f->flags&(SF_LINE|SF_WCWIDTH)) && isatty(f->file))
f->flags |= SF_LINE|SF_WCWIDTH;
#if _sys_stat
else /* special case /dev/null */
{ reg int dev, ino;
static int null_checked, null_dev, null_ino;
dev = (int)st.st_dev;
ino = (int)st.st_ino;
if(!null_checked)
{ if(stat(DEVNULL,&st) < 0)
null_checked = -1;
else
{ null_checked = 1;
null_dev = (int)st.st_dev;
null_ino = (int)st.st_ino;
}
}
if(null_checked >= 0 && dev == null_dev && ino == null_ino)
SFSETNULL(f);
}
#endif
errno = oerrno;
}
/* initialize side buffer for r+w unseekable streams */
if(!f->proc && (f->bits&SF_BOTH) )
(void)_sfpopen(f,-1,-1,1);
}
}
}
#ifdef MAP_TYPE
if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 )
{ /* see if we can try memory mapping */
if(!disc)
for(disc = f->disc; disc; disc = disc->disc)
if(disc->readf)
break;
if(!disc)
{ f->bits |= SF_MMAP;
if(size == (size_t)SF_UNBOUND)
{ if(bufsize > _Sfpage)
size = bufsize * SF_NMAP;
else size = _Sfpage * SF_NMAP;
if(size > 256*1024)
size = 256*1024;
}
}
}
#endif
/* get buffer space */
setbuf:
if(size == (size_t)SF_UNBOUND)
{ /* define a default size suitable for block transfer */
if(init && osize > 0)
size = osize;
else if(f == sfstderr && (f->mode&SF_WRITE))
size = 0;
else if(f->flags&SF_STRING )
size = SF_GRAIN;
else if((f->flags&SF_READ) && !(f->bits&SF_BOTH) &&
f->extent > 0 && f->extent < (Sfoff_t)_Sfpage )
size = (((size_t)f->extent + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
else if((ssize_t)(size = _Sfpage) < bufsize)
size = bufsize;
buf = NIL(void*);
}
sf_malloc = 0;
if(size > 0 && !buf && !(f->bits&SF_MMAP))
{ /* try to allocate a buffer */
if(obuf && size == (size_t)osize && init)
{ buf = (void*)obuf;
obuf = NIL(uchar*);
sf_malloc = (oflags&SF_MALLOC);
}
if(!buf)
{ /* do allocation */
while(!buf && size > 0)
{ if((buf = (void*)malloc(size)) )
break;
else size /= 2;
}
if(size > 0)
sf_malloc = SF_MALLOC;
}
}
if(size == 0 && !(f->flags&SF_STRING) && !(f->bits&SF_MMAP) && (f->mode&SF_READ))
{ /* use the internal buffer */
size = sizeof(f->tiny);
buf = (void*)f->tiny;
}
/* set up new buffer */
f->size = size;
f->next = f->data = f->endr = f->endw = (uchar*)buf;
f->endb = (f->mode&SF_READ) ? f->data : f->data+size;
if(f->flags&SF_STRING)
{ /* these fields are used to test actual size - see sfseek() */
f->extent = (!sf_malloc &&
((f->flags&SF_READ) || (f->bits&SF_BOTH)) ) ? size : 0;
f->here = 0;
/* read+string stream should have all data available */
if((f->mode&SF_READ) && !sf_malloc)
f->endb = f->data+size;
}
f->flags = (f->flags & ~SF_MALLOC)|sf_malloc;
if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC))
{ free((void*)obuf);
obuf = NIL(uchar*);
}
done:
_Sfi = f->val = obuf ? osize : 0;
/* blksz is used for aligning disk block boundary while reading data to
** optimize data transfer from disk (e.g., via direct I/O). blksz can be
** at most f->size/2 so that data movement in buffer can be optimized.
** blksz should also be a power-of-2 for optimal disk seeks.
*/
if(blksz <= 0 || (blksz & (blksz-1)) != 0 )
blksz = SF_GRAIN;
while(blksz > f->size/2)
blksz /= 2;
f->blksz = blksz;
SFOPEN(f,local);
return (void*)obuf;
}