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.
16249808Semaste * 3. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
311573Srgrimes */
321573Srgrimes
331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
341573Srgrimesstatic char sccsid[] = "@(#)findfp.c	8.2 (Berkeley) 1/4/94";
351573Srgrimes#endif /* LIBC_SCCS and not lint */
3692986Sobrien#include <sys/cdefs.h>
3792986Sobrien__FBSDID("$FreeBSD$");
381573Srgrimes
391573Srgrimes#include <sys/param.h>
4071579Sdeischen#include <machine/atomic.h>
411573Srgrimes#include <unistd.h>
421573Srgrimes#include <stdio.h>
431573Srgrimes#include <stdlib.h>
441573Srgrimes#include <string.h>
4553459Sdt
4653459Sdt#include <spinlock.h>
4753459Sdt
4871579Sdeischen#include "libc_private.h"
491573Srgrimes#include "local.h"
501573Srgrimes#include "glue.h"
511573Srgrimes
521573Srgrimesint	__sdidinit;
531573Srgrimes
541573Srgrimes#define	NDYNAMIC 10		/* add ten more whenever necessary */
551573Srgrimes
56189249Sdas#define	std(flags, file) {		\
57189249Sdas	._flags = (flags),		\
58189249Sdas	._file = (file),		\
59189249Sdas	._cookie = __sF + (file),	\
60189249Sdas	._close = __sclose,		\
61189249Sdas	._read = __sread,		\
62189249Sdas	._seek = __sseek,		\
63189249Sdas	._write = __swrite,		\
64205021Sjhb	._fl_mutex = PTHREAD_MUTEX_INITIALIZER, \
65189249Sdas}
661573Srgrimes				/* the usual - (stdin + stdout + stderr) */
671573Srgrimesstatic FILE usual[FOPEN_MAX - 3];
6871579Sdeischenstatic struct glue uglue = { NULL, FOPEN_MAX - 3, usual };
691573Srgrimes
70178287Sjhbstatic FILE __sF[3] = {
7172529Simp	std(__SRD, STDIN_FILENO),
7272529Simp	std(__SWR, STDOUT_FILENO),
7372529Simp	std(__SWR|__SNBF, STDERR_FILENO)
7472529Simp};
7572529Simp
7681600SpeterFILE *__stdinp = &__sF[0];
7781600SpeterFILE *__stdoutp = &__sF[1];
7881600SpeterFILE *__stderrp = &__sF[2];
7972732Speter
8072529Simpstruct glue __sglue = { &uglue, 3, __sF };
8171579Sdeischenstatic struct glue *lastglue = &uglue;
821573Srgrimes
8392905Sobrienstatic struct glue *	moreglue(int);
8416586Sjraynard
85234657Skibspinlock_t __stdio_thread_lock = _SPINLOCK_INITIALIZER;
8653459Sdt
8771579Sdeischen#if NOT_YET
8872373Sdeischen#define	SET_GLUE_PTR(ptr, val)	atomic_set_rel_ptr(&(ptr), (uintptr_t)(val))
8971579Sdeischen#else
9071579Sdeischen#define	SET_GLUE_PTR(ptr, val)	ptr = val
9171579Sdeischen#endif
9271579Sdeischen
931573Srgrimesstatic struct glue *
94249810Semastemoreglue(int n)
951573Srgrimes{
9671579Sdeischen	struct glue *g;
97205021Sjhb	static FILE empty = { ._fl_mutex = PTHREAD_MUTEX_INITIALIZER };
9871579Sdeischen	FILE *p;
991573Srgrimes
100178287Sjhb	g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE));
1011573Srgrimes	if (g == NULL)
1021573Srgrimes		return (NULL);
1031573Srgrimes	p = (FILE *)ALIGN(g + 1);
1041573Srgrimes	g->next = NULL;
1051573Srgrimes	g->niobs = n;
1061573Srgrimes	g->iobs = p;
107178287Sjhb	while (--n >= 0)
108178287Sjhb		*p++ = empty;
1091573Srgrimes	return (g);
1101573Srgrimes}
1111573Srgrimes
1121573Srgrimes/*
1131573Srgrimes * Find a free FILE for fopen et al.
1141573Srgrimes */
1151573SrgrimesFILE *
116291336Sngie__sfp(void)
1171573Srgrimes{
11871579Sdeischen	FILE	*fp;
11971579Sdeischen	int	n;
12071579Sdeischen	struct glue *g;
1211573Srgrimes
1221573Srgrimes	if (!__sdidinit)
1231573Srgrimes		__sinit();
12471579Sdeischen	/*
12571579Sdeischen	 * The list must be locked because a FILE may be updated.
12671579Sdeischen	 */
127234657Skib	STDIO_THREAD_LOCK();
12871579Sdeischen	for (g = &__sglue; g != NULL; g = g->next) {
1291573Srgrimes		for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
1301573Srgrimes			if (fp->_flags == 0)
1311573Srgrimes				goto found;
1321573Srgrimes	}
133234657Skib	STDIO_THREAD_UNLOCK();	/* don't hold lock while malloc()ing. */
13472128Ssobomax	if ((g = moreglue(NDYNAMIC)) == NULL)
13571579Sdeischen		return (NULL);
136234657Skib	STDIO_THREAD_LOCK();	/* reacquire the lock */
13771579Sdeischen	SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */
13871579Sdeischen	lastglue = g;		/* not atomic; only accessed when locked */
13971579Sdeischen	fp = g->iobs;
1401573Srgrimesfound:
1411573Srgrimes	fp->_flags = 1;		/* reserve this slot; caller sets real flags */
142234657Skib	STDIO_THREAD_UNLOCK();
1431573Srgrimes	fp->_p = NULL;		/* no current pointer */
1441573Srgrimes	fp->_w = 0;		/* nothing to read or write */
1451573Srgrimes	fp->_r = 0;
1461573Srgrimes	fp->_bf._base = NULL;	/* no buffer */
1471573Srgrimes	fp->_bf._size = 0;
1481573Srgrimes	fp->_lbfsize = 0;	/* not line buffered */
1491573Srgrimes	fp->_file = -1;		/* no file */
1501573Srgrimes/*	fp->_cookie = <any>; */	/* caller sets cookie, _read/_write etc */
1511573Srgrimes	fp->_ub._base = NULL;	/* no ungetc buffer */
1521573Srgrimes	fp->_ub._size = 0;
1531573Srgrimes	fp->_lb._base = NULL;	/* no line buffer */
1541573Srgrimes	fp->_lb._size = 0;
155205021Sjhb/*	fp->_fl_mutex = NULL; */ /* once set always set (reused) */
156178287Sjhb	fp->_orientation = 0;
157178287Sjhb	memset(&fp->_mbstate, 0, sizeof(mbstate_t));
158290544Sache	fp->_flags2 = 0;
1591573Srgrimes	return (fp);
1601573Srgrimes}
1611573Srgrimes
1621573Srgrimes/*
1631573Srgrimes * XXX.  Force immediate allocation of internal memory.  Not used by stdio,
1641573Srgrimes * but documented historically for certain applications.  Bad applications.
1651573Srgrimes */
16611667Sphk__warn_references(f_prealloc,
16780541Ssheldonh	"warning: this program uses f_prealloc(), which is not recommended.");
168291336Sngievoid f_prealloc(void);
16911667Sphk
17011667Sphkvoid
171200150Sedf_prealloc(void)
1721573Srgrimes{
17371579Sdeischen	struct glue *g;
1741573Srgrimes	int n;
1751573Srgrimes
1761573Srgrimes	n = getdtablesize() - FOPEN_MAX + 20;		/* 20 for slop. */
17771579Sdeischen	/*
17871579Sdeischen	 * It should be safe to walk the list without locking it;
17971579Sdeischen	 * new nodes are only added to the end and none are ever
18071579Sdeischen	 * removed.
18171579Sdeischen	 */
1821573Srgrimes	for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
1831573Srgrimes		/* void */;
18471579Sdeischen	if ((n > 0) && ((g = moreglue(n)) != NULL)) {
185234657Skib		STDIO_THREAD_LOCK();
18671579Sdeischen		SET_GLUE_PTR(lastglue->next, g);
18771579Sdeischen		lastglue = g;
188234657Skib		STDIO_THREAD_UNLOCK();
18971579Sdeischen	}
1901573Srgrimes}
1911573Srgrimes
1921573Srgrimes/*
1931573Srgrimes * exit() calls _cleanup() through *__cleanup, set whenever we
1941573Srgrimes * open or buffer a file.  This chicanery is done so that programs
1951573Srgrimes * that do not use stdio need not link it all in.
1961573Srgrimes *
1971573Srgrimes * The name `_cleanup' is, alas, fairly well known outside stdio.
1981573Srgrimes */
1991573Srgrimesvoid
200291336Sngie_cleanup(void)
2011573Srgrimes{
2021573Srgrimes	/* (void) _fwalk(fclose); */
2031573Srgrimes	(void) _fwalk(__sflush);		/* `cheating' */
2041573Srgrimes}
2051573Srgrimes
2061573Srgrimes/*
2071573Srgrimes * __sinit() is called whenever stdio's internal variables must be set up.
2081573Srgrimes */
2091573Srgrimesvoid
210291336Sngie__sinit(void)
2111573Srgrimes{
21272550Simp
213178287Sjhb	/* Make sure we clean up on exit. */
214178287Sjhb	__cleanup = _cleanup;		/* conservative */
215178287Sjhb	__sdidinit = 1;
2161573Srgrimes}
217