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