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: releng/11.0/lib/libc/stdio/findfp.c 292902 2015-12-30 03:36:22Z imp $"); 381573Srgrimes 391573Srgrimes#include <sys/param.h> 4071579Sdeischen#include <machine/atomic.h> 411573Srgrimes#include <unistd.h> 421573Srgrimes#include <stdio.h> 431573Srgrimes#include <stdlib.h> 44292809Simp#include <stdint.h> 451573Srgrimes#include <string.h> 4653459Sdt 4753459Sdt#include <spinlock.h> 4853459Sdt 4971579Sdeischen#include "libc_private.h" 501573Srgrimes#include "local.h" 511573Srgrimes#include "glue.h" 521573Srgrimes 531573Srgrimesint __sdidinit; 541573Srgrimes 551573Srgrimes#define NDYNAMIC 10 /* add ten more whenever necessary */ 561573Srgrimes 57189249Sdas#define std(flags, file) { \ 58189249Sdas ._flags = (flags), \ 59189249Sdas ._file = (file), \ 60189249Sdas ._cookie = __sF + (file), \ 61189249Sdas ._close = __sclose, \ 62189249Sdas ._read = __sread, \ 63189249Sdas ._seek = __sseek, \ 64189249Sdas ._write = __swrite, \ 65205021Sjhb ._fl_mutex = PTHREAD_MUTEX_INITIALIZER, \ 66189249Sdas} 671573Srgrimes /* the usual - (stdin + stdout + stderr) */ 681573Srgrimesstatic FILE usual[FOPEN_MAX - 3]; 6971579Sdeischenstatic struct glue uglue = { NULL, FOPEN_MAX - 3, usual }; 701573Srgrimes 71178287Sjhbstatic FILE __sF[3] = { 7272529Simp std(__SRD, STDIN_FILENO), 7372529Simp std(__SWR, STDOUT_FILENO), 7472529Simp std(__SWR|__SNBF, STDERR_FILENO) 7572529Simp}; 7672529Simp 7781600SpeterFILE *__stdinp = &__sF[0]; 7881600SpeterFILE *__stdoutp = &__sF[1]; 7981600SpeterFILE *__stderrp = &__sF[2]; 8072732Speter 8172529Simpstruct glue __sglue = { &uglue, 3, __sF }; 8271579Sdeischenstatic struct glue *lastglue = &uglue; 831573Srgrimes 8492905Sobrienstatic struct glue * moreglue(int); 8516586Sjraynard 86234657Skibspinlock_t __stdio_thread_lock = _SPINLOCK_INITIALIZER; 8753459Sdt 8871579Sdeischen#if NOT_YET 8972373Sdeischen#define SET_GLUE_PTR(ptr, val) atomic_set_rel_ptr(&(ptr), (uintptr_t)(val)) 9071579Sdeischen#else 9171579Sdeischen#define SET_GLUE_PTR(ptr, val) ptr = val 9271579Sdeischen#endif 9371579Sdeischen 941573Srgrimesstatic struct glue * 95249810Semastemoreglue(int n) 961573Srgrimes{ 9771579Sdeischen struct glue *g; 98205021Sjhb static FILE empty = { ._fl_mutex = PTHREAD_MUTEX_INITIALIZER }; 9971579Sdeischen FILE *p; 100292809Simp size_t align; 1011573Srgrimes 102292902Simp align = __alignof__(FILE); 103292809Simp g = (struct glue *)malloc(sizeof(*g) + align + n * sizeof(FILE)); 1041573Srgrimes if (g == NULL) 1051573Srgrimes return (NULL); 106292809Simp p = (FILE *)roundup((uintptr_t)(g + 1), align); 1071573Srgrimes g->next = NULL; 1081573Srgrimes g->niobs = n; 1091573Srgrimes g->iobs = p; 110178287Sjhb while (--n >= 0) 111178287Sjhb *p++ = empty; 1121573Srgrimes return (g); 1131573Srgrimes} 1141573Srgrimes 1151573Srgrimes/* 1161573Srgrimes * Find a free FILE for fopen et al. 1171573Srgrimes */ 1181573SrgrimesFILE * 119288033Srodrigc__sfp(void) 1201573Srgrimes{ 12171579Sdeischen FILE *fp; 12271579Sdeischen int n; 12371579Sdeischen struct glue *g; 1241573Srgrimes 1251573Srgrimes if (!__sdidinit) 1261573Srgrimes __sinit(); 12771579Sdeischen /* 12871579Sdeischen * The list must be locked because a FILE may be updated. 12971579Sdeischen */ 130234657Skib STDIO_THREAD_LOCK(); 13171579Sdeischen for (g = &__sglue; g != NULL; g = g->next) { 1321573Srgrimes for (fp = g->iobs, n = g->niobs; --n >= 0; fp++) 1331573Srgrimes if (fp->_flags == 0) 1341573Srgrimes goto found; 1351573Srgrimes } 136234657Skib STDIO_THREAD_UNLOCK(); /* don't hold lock while malloc()ing. */ 13772128Ssobomax if ((g = moreglue(NDYNAMIC)) == NULL) 13871579Sdeischen return (NULL); 139234657Skib STDIO_THREAD_LOCK(); /* reacquire the lock */ 14071579Sdeischen SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */ 14171579Sdeischen lastglue = g; /* not atomic; only accessed when locked */ 14271579Sdeischen fp = g->iobs; 1431573Srgrimesfound: 1441573Srgrimes fp->_flags = 1; /* reserve this slot; caller sets real flags */ 145234657Skib STDIO_THREAD_UNLOCK(); 1461573Srgrimes fp->_p = NULL; /* no current pointer */ 1471573Srgrimes fp->_w = 0; /* nothing to read or write */ 1481573Srgrimes fp->_r = 0; 1491573Srgrimes fp->_bf._base = NULL; /* no buffer */ 1501573Srgrimes fp->_bf._size = 0; 1511573Srgrimes fp->_lbfsize = 0; /* not line buffered */ 1521573Srgrimes fp->_file = -1; /* no file */ 1531573Srgrimes/* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */ 1541573Srgrimes fp->_ub._base = NULL; /* no ungetc buffer */ 1551573Srgrimes fp->_ub._size = 0; 1561573Srgrimes fp->_lb._base = NULL; /* no line buffer */ 1571573Srgrimes fp->_lb._size = 0; 158205021Sjhb/* fp->_fl_mutex = NULL; */ /* once set always set (reused) */ 159178287Sjhb fp->_orientation = 0; 160178287Sjhb memset(&fp->_mbstate, 0, sizeof(mbstate_t)); 161290110Sache fp->_flags2 = 0; 1621573Srgrimes return (fp); 1631573Srgrimes} 1641573Srgrimes 1651573Srgrimes/* 1661573Srgrimes * XXX. Force immediate allocation of internal memory. Not used by stdio, 1671573Srgrimes * but documented historically for certain applications. Bad applications. 1681573Srgrimes */ 16911667Sphk__warn_references(f_prealloc, 17080541Ssheldonh "warning: this program uses f_prealloc(), which is not recommended."); 171288033Srodrigcvoid f_prealloc(void); 17211667Sphk 17311667Sphkvoid 174200150Sedf_prealloc(void) 1751573Srgrimes{ 17671579Sdeischen struct glue *g; 1771573Srgrimes int n; 1781573Srgrimes 1791573Srgrimes n = getdtablesize() - FOPEN_MAX + 20; /* 20 for slop. */ 18071579Sdeischen /* 18171579Sdeischen * It should be safe to walk the list without locking it; 18271579Sdeischen * new nodes are only added to the end and none are ever 18371579Sdeischen * removed. 18471579Sdeischen */ 1851573Srgrimes for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next) 1861573Srgrimes /* void */; 18771579Sdeischen if ((n > 0) && ((g = moreglue(n)) != NULL)) { 188234657Skib STDIO_THREAD_LOCK(); 18971579Sdeischen SET_GLUE_PTR(lastglue->next, g); 19071579Sdeischen lastglue = g; 191234657Skib STDIO_THREAD_UNLOCK(); 19271579Sdeischen } 1931573Srgrimes} 1941573Srgrimes 1951573Srgrimes/* 1961573Srgrimes * exit() calls _cleanup() through *__cleanup, set whenever we 1971573Srgrimes * open or buffer a file. This chicanery is done so that programs 1981573Srgrimes * that do not use stdio need not link it all in. 1991573Srgrimes * 2001573Srgrimes * The name `_cleanup' is, alas, fairly well known outside stdio. 2011573Srgrimes */ 2021573Srgrimesvoid 203288033Srodrigc_cleanup(void) 2041573Srgrimes{ 2051573Srgrimes /* (void) _fwalk(fclose); */ 2061573Srgrimes (void) _fwalk(__sflush); /* `cheating' */ 2071573Srgrimes} 2081573Srgrimes 2091573Srgrimes/* 2101573Srgrimes * __sinit() is called whenever stdio's internal variables must be set up. 2111573Srgrimes */ 2121573Srgrimesvoid 213288033Srodrigc__sinit(void) 2141573Srgrimes{ 21572550Simp 216178287Sjhb /* Make sure we clean up on exit. */ 217178287Sjhb __cleanup = _cleanup; /* conservative */ 218178287Sjhb __sdidinit = 1; 2191573Srgrimes} 220