findfp.c revision 81600
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1990, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Chris Torek.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 3. All advertising materials mentioning features or use of this software
171573Srgrimes *    must display the following acknowledgement:
181573Srgrimes *	This product includes software developed by the University of
191573Srgrimes *	California, Berkeley and its contributors.
201573Srgrimes * 4. Neither the name of the University nor the names of its contributors
211573Srgrimes *    may be used to endorse or promote products derived from this software
221573Srgrimes *    without specific prior written permission.
231573Srgrimes *
241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341573Srgrimes * SUCH DAMAGE.
351573Srgrimes */
361573Srgrimes
371573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3816586Sjraynard#if 0
391573Srgrimesstatic char sccsid[] = "@(#)findfp.c	8.2 (Berkeley) 1/4/94";
4016586Sjraynard#endif
4116586Sjraynardstatic const char rcsid[] =
4250476Speter  "$FreeBSD: head/lib/libc/stdio/findfp.c 81600 2001-08-13 21:48:44Z peter $";
431573Srgrimes#endif /* LIBC_SCCS and not lint */
441573Srgrimes
451573Srgrimes#include <sys/param.h>
4671579Sdeischen#include <machine/atomic.h>
471573Srgrimes#include <unistd.h>
481573Srgrimes#include <stdio.h>
491573Srgrimes#include <stdlib.h>
501573Srgrimes#include <string.h>
5153459Sdt
5253459Sdt#include <spinlock.h>
5353459Sdt
5471579Sdeischen#include "libc_private.h"
551573Srgrimes#include "local.h"
561573Srgrimes#include "glue.h"
571573Srgrimes
581573Srgrimesint	__sdidinit;
591573Srgrimes
601573Srgrimes#define	NDYNAMIC 10		/* add ten more whenever necessary */
611573Srgrimes
6272529Simp#define	std(flags, file) \
6372529Simp  	{0,0,0,flags,file,{0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \
6472529Simp	 {0}, __sFX + file}
6572529Simp  /*	 p r w flags file _bf z  cookie      close    read    seek    write */
6672529Simp  /*     _ub _extra */
671573Srgrimes				/* the usual - (stdin + stdout + stderr) */
681573Srgrimesstatic FILE usual[FOPEN_MAX - 3];
6972550Simpstatic struct __sFILEX usual_extra[FOPEN_MAX - 3];
7071579Sdeischenstatic struct glue uglue = { NULL, FOPEN_MAX - 3, usual };
711573Srgrimes
7272529Simpstatic struct __sFILEX __sFX[3];
7372472Speter
7481600Speter#if LIBC_MAJOR >= 6
7581600Speterstatic
7681600Speter#endif
7772529SimpFILE __sF[3] = {
7872529Simp	std(__SRD, STDIN_FILENO),
7972529Simp	std(__SWR, STDOUT_FILENO),
8072529Simp	std(__SWR|__SNBF, STDERR_FILENO)
8172529Simp};
8272529Simp
8372732Speter/*
8472732Speter * The following kludge is done to ensure enough binary compatibility
8572732Speter * with future versions of libc.  Or rather it allows us to work with
8672732Speter * libraries that have been built with a newer libc that defines these
8772732Speter * symbols and expects libc to provide them.  We only have need to support
8872732Speter * i386 and alpha because they are the only "old" systems we have deployed.
8972732Speter */
9081600SpeterFILE *__stdinp = &__sF[0];
9181600SpeterFILE *__stdoutp = &__sF[1];
9281600SpeterFILE *__stderrp = &__sF[2];
9372732Speter
9472529Simpstruct glue __sglue = { &uglue, 3, __sF };
9571579Sdeischenstatic struct glue *lastglue = &uglue;
961573Srgrimes
9716586Sjraynardstatic struct glue *	moreglue __P((int));
9816586Sjraynard
9953459Sdtstatic spinlock_t thread_lock = _SPINLOCK_INITIALIZER;
10053459Sdt#define THREAD_LOCK()	if (__isthreaded) _SPINLOCK(&thread_lock)
10153459Sdt#define THREAD_UNLOCK()	if (__isthreaded) _SPINUNLOCK(&thread_lock)
10253459Sdt
10371579Sdeischen#if NOT_YET
10472373Sdeischen#define	SET_GLUE_PTR(ptr, val)	atomic_set_rel_ptr(&(ptr), (uintptr_t)(val))
10571579Sdeischen#else
10671579Sdeischen#define	SET_GLUE_PTR(ptr, val)	ptr = val
10771579Sdeischen#endif
10871579Sdeischen
1091573Srgrimesstatic struct glue *
1101573Srgrimesmoreglue(n)
11171579Sdeischen	int n;
1121573Srgrimes{
11371579Sdeischen	struct glue *g;
11472529Simp	static FILE empty;
11572529Simp	static struct __sFILEX emptyx;
11671579Sdeischen	FILE *p;
11772529Simp	struct __sFILEX *fx;
1181573Srgrimes
11972529Simp	g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE) +
12072529Simp	    n * sizeof(struct __sFILEX));
1211573Srgrimes	if (g == NULL)
1221573Srgrimes		return (NULL);
1231573Srgrimes	p = (FILE *)ALIGN(g + 1);
12472529Simp	fx = (struct __sFILEX *)&p[n];
1251573Srgrimes	g->next = NULL;
1261573Srgrimes	g->niobs = n;
1271573Srgrimes	g->iobs = p;
12872529Simp	while (--n >= 0) {
12972529Simp		*p = empty;
13072529Simp		p->_extra = fx;
13172529Simp		*p->_extra = emptyx;
13272529Simp		p++, fx++;
13372529Simp	}
1341573Srgrimes	return (g);
1351573Srgrimes}
1361573Srgrimes
1371573Srgrimes/*
1381573Srgrimes * Find a free FILE for fopen et al.
1391573Srgrimes */
1401573SrgrimesFILE *
1411573Srgrimes__sfp()
1421573Srgrimes{
14371579Sdeischen	FILE	*fp;
14471579Sdeischen	int	n;
14571579Sdeischen	struct glue *g;
1461573Srgrimes
1471573Srgrimes	if (!__sdidinit)
1481573Srgrimes		__sinit();
14971579Sdeischen	/*
15071579Sdeischen	 * The list must be locked because a FILE may be updated.
15171579Sdeischen	 */
15253459Sdt	THREAD_LOCK();
15371579Sdeischen	for (g = &__sglue; g != NULL; g = g->next) {
1541573Srgrimes		for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
1551573Srgrimes			if (fp->_flags == 0)
1561573Srgrimes				goto found;
1571573Srgrimes	}
15871579Sdeischen	THREAD_UNLOCK();	/* don't hold lock while malloc()ing. */
15972128Ssobomax	if ((g = moreglue(NDYNAMIC)) == NULL)
16071579Sdeischen		return (NULL);
16171579Sdeischen	THREAD_LOCK();		/* reacquire the lock */
16271579Sdeischen	SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */
16371579Sdeischen	lastglue = g;		/* not atomic; only accessed when locked */
16471579Sdeischen	fp = g->iobs;
1651573Srgrimesfound:
1661573Srgrimes	fp->_flags = 1;		/* reserve this slot; caller sets real flags */
16753459Sdt	THREAD_UNLOCK();
1681573Srgrimes	fp->_p = NULL;		/* no current pointer */
1691573Srgrimes	fp->_w = 0;		/* nothing to read or write */
1701573Srgrimes	fp->_r = 0;
1711573Srgrimes	fp->_bf._base = NULL;	/* no buffer */
1721573Srgrimes	fp->_bf._size = 0;
1731573Srgrimes	fp->_lbfsize = 0;	/* not line buffered */
1741573Srgrimes	fp->_file = -1;		/* no file */
1751573Srgrimes/*	fp->_cookie = <any>; */	/* caller sets cookie, _read/_write etc */
1761573Srgrimes	fp->_ub._base = NULL;	/* no ungetc buffer */
1771573Srgrimes	fp->_ub._size = 0;
1781573Srgrimes	fp->_lb._base = NULL;	/* no line buffer */
1791573Srgrimes	fp->_lb._size = 0;
18072373Sdeischen/*	fp->_lock = NULL; */	/* once set always set (reused) */
1811573Srgrimes	return (fp);
1821573Srgrimes}
1831573Srgrimes
1841573Srgrimes/*
1851573Srgrimes * XXX.  Force immediate allocation of internal memory.  Not used by stdio,
1861573Srgrimes * but documented historically for certain applications.  Bad applications.
1871573Srgrimes */
18811667Sphk__warn_references(f_prealloc,
18980541Ssheldonh	"warning: this program uses f_prealloc(), which is not recommended.");
19011667Sphk
19111667Sphkvoid
1921573Srgrimesf_prealloc()
1931573Srgrimes{
19471579Sdeischen	struct glue *g;
1951573Srgrimes	int n;
1961573Srgrimes
1971573Srgrimes	n = getdtablesize() - FOPEN_MAX + 20;		/* 20 for slop. */
19871579Sdeischen	/*
19971579Sdeischen	 * It should be safe to walk the list without locking it;
20071579Sdeischen	 * new nodes are only added to the end and none are ever
20171579Sdeischen	 * removed.
20271579Sdeischen	 */
2031573Srgrimes	for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
2041573Srgrimes		/* void */;
20571579Sdeischen	if ((n > 0) && ((g = moreglue(n)) != NULL)) {
20671579Sdeischen		THREAD_LOCK();
20771579Sdeischen		SET_GLUE_PTR(lastglue->next, g);
20871579Sdeischen		lastglue = g;
20971579Sdeischen		THREAD_UNLOCK();
21071579Sdeischen	}
2111573Srgrimes}
2121573Srgrimes
2131573Srgrimes/*
2141573Srgrimes * exit() calls _cleanup() through *__cleanup, set whenever we
2151573Srgrimes * open or buffer a file.  This chicanery is done so that programs
2161573Srgrimes * that do not use stdio need not link it all in.
2171573Srgrimes *
2181573Srgrimes * The name `_cleanup' is, alas, fairly well known outside stdio.
2191573Srgrimes */
2201573Srgrimesvoid
2211573Srgrimes_cleanup()
2221573Srgrimes{
2231573Srgrimes	/* (void) _fwalk(fclose); */
2241573Srgrimes	(void) _fwalk(__sflush);		/* `cheating' */
2251573Srgrimes}
2261573Srgrimes
2271573Srgrimes/*
2281573Srgrimes * __sinit() is called whenever stdio's internal variables must be set up.
2291573Srgrimes */
2301573Srgrimesvoid
2311573Srgrimes__sinit()
2321573Srgrimes{
23372550Simp	int	i;
23472550Simp
23572550Simp	THREAD_LOCK();
23672550Simp	if (__sdidinit == 0) {
23772550Simp		/* Set _extra for the usual suspects. */
23872550Simp		for (i = 0; i < FOPEN_MAX - 3; i++)
23972550Simp			usual[i]._extra = &usual_extra[i];
24072550Simp
24172550Simp		/* Make sure we clean up on exit. */
24272550Simp		__cleanup = _cleanup;		/* conservative */
24372550Simp		__sdidinit = 1;
24472550Simp	}
24572550Simp	THREAD_UNLOCK();
2461573Srgrimes}
247