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