]>
git.saurik.com Git - apple/libc.git/blob - stdio/findfp-fbsd.c
   2  * Copyright (c) 1990, 1993 
   3  *      The Regents of the University of California.  All rights reserved. 
   5  * This code is derived from software contributed to Berkeley by 
   8  * Redistribution and use in source and binary forms, with or without 
   9  * modification, are permitted provided that the following conditions 
  11  * 1. Redistributions of source code must retain the above copyright 
  12  *    notice, this list of conditions and the following disclaimer. 
  13  * 2. Redistributions in binary form must reproduce the above copyright 
  14  *    notice, this list of conditions and the following disclaimer in the 
  15  *    documentation and/or other materials provided with the distribution. 
  16  * 4. Neither the name of the University nor the names of its contributors 
  17  *    may be used to endorse or promote products derived from this software 
  18  *    without specific prior written permission. 
  20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  33 #if defined(LIBC_SCCS) && !defined(lint) 
  34 static char sccsid
[] = "@(#)findfp.c    8.2 (Berkeley) 1/4/94"; 
  35 #endif /* LIBC_SCCS and not lint */ 
  36 #include <sys/cdefs.h> 
  37 __FBSDID("$FreeBSD: src/lib/libc/stdio/findfp.c,v 1.34 2009/12/05 19:31:38 ed Exp $"); 
  39 #include <TargetConditionals.h> 
  41 #include <sys/param.h> 
  42 #include <machine/atomic.h> 
  47 #include <libkern/OSAtomic.h> 
  53 #include "libc_private.h" 
  59 #if !TARGET_OS_EMBEDDED 
  60 #define NDYNAMIC 10             /* add ten more whenever necessary */ 
  62 #define NDYNAMIC 1              /* add one at a time on embedded */ 
  65 #define std(flags, file) {              \ 
  68         ._cookie = __sF + (file),       \ 
  73         ._extra = __sFX + file,         \ 
  75 #define __sFXInit       {.fl_mutex = PTHREAD_MUTEX_INITIALIZER} 
  77 #define __sFXInit3      {.fl_mutex = PTHREAD_MUTEX_INITIALIZER, .counted = 1} 
  79 static int __scounted
;          /* streams counted against STREAM_MAX */ 
  80 static int __stream_max
; 
  82 #if !TARGET_OS_EMBEDDED 
  83 /* usual and usual_extra are data pigs. See 7929728. For embedded we should 
  84  * always allocate dynamically, and probably should for desktop too. */ 
  85                                 /* the usual - (stdin + stdout + stderr) */ 
  86 static FILE usual
[FOPEN_MAX 
- 3]; 
  87 static struct __sFILEX usual_extra
[FOPEN_MAX 
- 3]; 
  88 static struct glue uglue 
= { NULL
, FOPEN_MAX 
- 3, usual 
}; 
  89 #endif /* !TARGET_OS_EMBEDDED */ 
  91 static struct __sFILEX __sFX
[3] = {__sFXInit3
, __sFXInit3
, __sFXInit3
}; 
  94  * We can't make this 'static' due to binary compatibility concerns. 
  95  * This also means we cannot change the sizeof(FILE) and must continue to 
  96  * use the __sFILEX stuff to add to FILE. 
  99         std(__SRD
, STDIN_FILENO
), 
 100         std(__SWR
, STDOUT_FILENO
), 
 101         std(__SWR
|__SNBF
, STDERR_FILENO
) 
 104 FILE *__stdinp 
= &__sF
[0]; 
 105 FILE *__stdoutp 
= &__sF
[1]; 
 106 FILE *__stderrp 
= &__sF
[2]; 
 108 #if !TARGET_OS_EMBEDDED 
 109 struct glue __sglue 
= { &uglue
, 3, __sF 
}; 
 110 static struct glue 
*lastglue 
= &uglue
; 
 112 struct glue __sglue 
= { NULL
, 3, __sF 
}; 
 113 static struct glue 
*lastglue 
= &__sglue
; 
 116 static struct glue 
*    moreglue(int); 
 118 static spinlock_t thread_lock 
= _SPINLOCK_INITIALIZER
; 
 119 #define THREAD_LOCK()   if (__isthreaded) _SPINLOCK(&thread_lock) 
 120 #define THREAD_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock) 
 123 #define SET_GLUE_PTR(ptr, val)  atomic_set_rel_ptr(&(ptr), (uintptr_t)(val)) 
 125 #define SET_GLUE_PTR(ptr, val)  ptr = val 
 135         static struct __sFILEX emptyx 
= __sFXInit
; 
 138         g 
= (struct glue 
*)malloc(sizeof(*g
) + ALIGNBYTES 
+ n 
* sizeof(FILE) + 
 139             n 
* sizeof(struct __sFILEX
)); 
 142         p 
= (FILE *)ALIGN(g 
+ 1); 
 143         fx 
= (struct __sFILEX 
*)&p
[n
]; 
 158  * Find a free FILE for fopen et al. 
 171                 if (__scounted 
>= __stream_max
) { 
 176                 OSAtomicIncrement32(&__scounted
); 
 179          * The list must be locked because a FILE may be updated. 
 182         for (g 
= &__sglue
; g 
!= NULL
; g 
= g
->next
) { 
 183                 for (fp 
= g
->iobs
, n 
= g
->niobs
; --n 
>= 0; fp
++) 
 187         THREAD_UNLOCK();        /* don't hold lock while malloc()ing. */ 
 188         if ((g 
= moreglue(NDYNAMIC
)) == NULL
) 
 190         THREAD_LOCK();          /* reacquire the lock */ 
 191         SET_GLUE_PTR(lastglue
->next
, g
); /* atomically append glue to list */ 
 192         lastglue 
= g
;           /* not atomic; only accessed when locked */ 
 195         fp
->_flags 
= 1;         /* reserve this slot; caller sets real flags */ 
 197         fp
->_p 
= NULL
;          /* no current pointer */ 
 198         fp
->_w 
= 0;             /* nothing to read or write */ 
 200         fp
->_bf
._base 
= NULL
;   /* no buffer */ 
 202         fp
->_lbfsize 
= 0;       /* not line buffered */ 
 203         fp
->_file 
= -1;         /* no file */ 
 204 /*      fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */ 
 205         fp
->_ub
._base 
= NULL
;   /* no ungetc buffer */ 
 207         fp
->_lb
._base 
= NULL
;   /* no line buffer */ 
 209 /*      fp->_lock = NULL; */    /* once set always set (reused) */ 
 211         fp
->_extra
->counted 
= count 
? 1 : 0; 
 216  * Mark as free and update count as needed 
 218 __private_extern__ 
void 
 219 __sfprelease(FILE *fp
) 
 222                 OSAtomicDecrement32(&__scounted
); 
 229  * XXX.  Force immediate allocation of internal memory.  Not used by stdio, 
 230  * but documented historically for certain applications.  Bad applications. 
 232 __warn_references(f_prealloc
,  
 233         "warning: this program uses f_prealloc(), which is not recommended."); 
 241         n 
= getdtablesize() - FOPEN_MAX 
+ 20;           /* 20 for slop. */ 
 243          * It should be safe to walk the list without locking it; 
 244          * new nodes are only added to the end and none are ever 
 247         for (g 
= &__sglue
; (n 
-= g
->niobs
) > 0 && g
->next
; g 
= g
->next
) 
 249         if ((n 
> 0) && ((g 
= moreglue(n
)) != NULL
)) { 
 251                 SET_GLUE_PTR(lastglue
->next
, g
); 
 258  * exit() calls _cleanup() through *__cleanup, set whenever we 
 259  * open or buffer a file.  This chicanery is done so that programs 
 260  * that do not use stdio need not link it all in. 
 262  * The name `_cleanup' is, alas, fairly well known outside stdio. 
 267         /* (void) _fwalk(fclose); */ 
 268         (void) _fwalk(__sflush
);                /* `cheating' */ 
 272  * __sinit() is called whenever stdio's internal variables must be set up. 
 278         if (__sdidinit 
== 0) { 
 279 #if !TARGET_OS_EMBEDDED 
 282                 /* Make sure we clean up on exit. */ 
 283                 __cleanup 
= _cleanup
;           /* conservative */ 
 284                 __stream_max 
= sysconf(_SC_STREAM_MAX
); 
 285                 __scounted 
= 3;                 /* std{in,out,err} already exists */ 
 287 #if !TARGET_OS_EMBEDDED 
 288                 /* Set _extra for the usual suspects. */ 
 289                 for (i 
= 0; i 
< FOPEN_MAX 
- 3; i
++) { 
 290                         usual
[i
]._extra 
= &usual_extra
[i
]; 
 291                         INITEXTRA(&usual
[i
]);