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