findfp.c revision 249808
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: head/lib/libc/stdio/findfp.c 249808 2013-04-23 13:33:13Z emaste $");
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 *
941573Srgrimesmoreglue(n)
9571579Sdeischen	int n;
961573Srgrimes{
9771579Sdeischen	struct glue *g;
98205021Sjhb	static FILE empty = { ._fl_mutex = PTHREAD_MUTEX_INITIALIZER };
9971579Sdeischen	FILE *p;
1001573Srgrimes
101178287Sjhb	g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE));
1021573Srgrimes	if (g == NULL)
1031573Srgrimes		return (NULL);
1041573Srgrimes	p = (FILE *)ALIGN(g + 1);
1051573Srgrimes	g->next = NULL;
1061573Srgrimes	g->niobs = n;
1071573Srgrimes	g->iobs = p;
108178287Sjhb	while (--n >= 0)
109178287Sjhb		*p++ = empty;
1101573Srgrimes	return (g);
1111573Srgrimes}
1121573Srgrimes
1131573Srgrimes/*
1141573Srgrimes * Find a free FILE for fopen et al.
1151573Srgrimes */
1161573SrgrimesFILE *
1171573Srgrimes__sfp()
1181573Srgrimes{
11971579Sdeischen	FILE	*fp;
12071579Sdeischen	int	n;
12171579Sdeischen	struct glue *g;
1221573Srgrimes
1231573Srgrimes	if (!__sdidinit)
1241573Srgrimes		__sinit();
12571579Sdeischen	/*
12671579Sdeischen	 * The list must be locked because a FILE may be updated.
12771579Sdeischen	 */
128234657Skib	STDIO_THREAD_LOCK();
12971579Sdeischen	for (g = &__sglue; g != NULL; g = g->next) {
1301573Srgrimes		for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
1311573Srgrimes			if (fp->_flags == 0)
1321573Srgrimes				goto found;
1331573Srgrimes	}
134234657Skib	STDIO_THREAD_UNLOCK();	/* don't hold lock while malloc()ing. */
13572128Ssobomax	if ((g = moreglue(NDYNAMIC)) == NULL)
13671579Sdeischen		return (NULL);
137234657Skib	STDIO_THREAD_LOCK();	/* reacquire the lock */
13871579Sdeischen	SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */
13971579Sdeischen	lastglue = g;		/* not atomic; only accessed when locked */
14071579Sdeischen	fp = g->iobs;
1411573Srgrimesfound:
1421573Srgrimes	fp->_flags = 1;		/* reserve this slot; caller sets real flags */
143234657Skib	STDIO_THREAD_UNLOCK();
1441573Srgrimes	fp->_p = NULL;		/* no current pointer */
1451573Srgrimes	fp->_w = 0;		/* nothing to read or write */
1461573Srgrimes	fp->_r = 0;
1471573Srgrimes	fp->_bf._base = NULL;	/* no buffer */
1481573Srgrimes	fp->_bf._size = 0;
1491573Srgrimes	fp->_lbfsize = 0;	/* not line buffered */
1501573Srgrimes	fp->_file = -1;		/* no file */
1511573Srgrimes/*	fp->_cookie = <any>; */	/* caller sets cookie, _read/_write etc */
1521573Srgrimes	fp->_ub._base = NULL;	/* no ungetc buffer */
1531573Srgrimes	fp->_ub._size = 0;
1541573Srgrimes	fp->_lb._base = NULL;	/* no line buffer */
1551573Srgrimes	fp->_lb._size = 0;
156205021Sjhb/*	fp->_fl_mutex = NULL; */ /* once set always set (reused) */
157178287Sjhb	fp->_orientation = 0;
158178287Sjhb	memset(&fp->_mbstate, 0, sizeof(mbstate_t));
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.");
16811667Sphk
16911667Sphkvoid
170200150Sedf_prealloc(void)
1711573Srgrimes{
17271579Sdeischen	struct glue *g;
1731573Srgrimes	int n;
1741573Srgrimes
1751573Srgrimes	n = getdtablesize() - FOPEN_MAX + 20;		/* 20 for slop. */
17671579Sdeischen	/*
17771579Sdeischen	 * It should be safe to walk the list without locking it;
17871579Sdeischen	 * new nodes are only added to the end and none are ever
17971579Sdeischen	 * removed.
18071579Sdeischen	 */
1811573Srgrimes	for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
1821573Srgrimes		/* void */;
18371579Sdeischen	if ((n > 0) && ((g = moreglue(n)) != NULL)) {
184234657Skib		STDIO_THREAD_LOCK();
18571579Sdeischen		SET_GLUE_PTR(lastglue->next, g);
18671579Sdeischen		lastglue = g;
187234657Skib		STDIO_THREAD_UNLOCK();
18871579Sdeischen	}
1891573Srgrimes}
1901573Srgrimes
1911573Srgrimes/*
1921573Srgrimes * exit() calls _cleanup() through *__cleanup, set whenever we
1931573Srgrimes * open or buffer a file.  This chicanery is done so that programs
1941573Srgrimes * that do not use stdio need not link it all in.
1951573Srgrimes *
1961573Srgrimes * The name `_cleanup' is, alas, fairly well known outside stdio.
1971573Srgrimes */
1981573Srgrimesvoid
1991573Srgrimes_cleanup()
2001573Srgrimes{
2011573Srgrimes	/* (void) _fwalk(fclose); */
2021573Srgrimes	(void) _fwalk(__sflush);		/* `cheating' */
2031573Srgrimes}
2041573Srgrimes
2051573Srgrimes/*
2061573Srgrimes * __sinit() is called whenever stdio's internal variables must be set up.
2071573Srgrimes */
2081573Srgrimesvoid
2091573Srgrimes__sinit()
2101573Srgrimes{
21172550Simp
212178287Sjhb	/* Make sure we clean up on exit. */
213178287Sjhb	__cleanup = _cleanup;		/* conservative */
214178287Sjhb	__sdidinit = 1;
2151573Srgrimes}
216