Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | --- findfp.c.orig 2011-02-15 16:29:38.000000000 -0800 +++ findfp.c 2011-02-16 10:36:00.000000000 -0800 @@ -36,13 +36,18 @@ static char sccsid[] = "@(#)findfp.c 8.2 #include <sys/cdefs.h> __FBSDID("$FreeBSD: src/lib/libc/stdio/findfp.c,v 1.34 2009/12/05 19:31:38 ed Exp $"); +#include <TargetConditionals.h> + #include <sys/param.h> #include <machine/atomic.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <libkern/OSAtomic.h> +#include <errno.h> +#include <pthread.h> #include <spinlock.h> #include "libc_private.h" @@ -51,7 +56,11 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/f int __sdidinit; +#if !TARGET_OS_EMBEDDED #define NDYNAMIC 10 /* add ten more whenever necessary */ +#else +#define NDYNAMIC 1 /* add one at a time on embedded */ +#endif #define std(flags, file) { \ ._flags = (flags), \ @@ -61,12 +70,32 @@ int __sdidinit; ._read = __sread, \ ._seek = __sseek, \ ._write = __swrite, \ + ._extra = __sFX + file, \ } +#define __sFXInit {.fl_mutex = PTHREAD_MUTEX_INITIALIZER} + /* set counted */ +#define __sFXInit3 {.fl_mutex = PTHREAD_MUTEX_INITIALIZER, .counted = 1} + +static int __scounted; /* streams counted against STREAM_MAX */ +static int __stream_max; + +#if !TARGET_OS_EMBEDDED +/* usual and usual_extra are data pigs. See 7929728. For embedded we should + * always allocate dynamically, and probably should for desktop too. */ /* the usual - (stdin + stdout + stderr) */ static FILE usual[FOPEN_MAX - 3]; +static struct __sFILEX usual_extra[FOPEN_MAX - 3]; static struct glue uglue = { NULL, FOPEN_MAX - 3, usual }; +#endif /* !TARGET_OS_EMBEDDED */ -static FILE __sF[3] = { +static struct __sFILEX __sFX[3] = {__sFXInit3, __sFXInit3, __sFXInit3}; + +/* + * We can't make this 'static' due to binary compatibility concerns. + * This also means we cannot change the sizeof(FILE) and must continue to + * use the __sFILEX stuff to add to FILE. + */ +FILE __sF[3] = { std(__SRD, STDIN_FILENO), std(__SWR, STDOUT_FILENO), std(__SWR|__SNBF, STDERR_FILENO) @@ -76,8 +105,13 @@ FILE *__stdinp = &__sF[0]; FILE *__stdoutp = &__sF[1]; FILE *__stderrp = &__sF[2]; +#if !TARGET_OS_EMBEDDED struct glue __sglue = { &uglue, 3, __sF }; static struct glue *lastglue = &uglue; +#else +struct glue __sglue = { NULL, 3, __sF }; +static struct glue *lastglue = &__sglue; +#endif static struct glue * moreglue(int); @@ -98,16 +132,25 @@ moreglue(n) struct glue *g; static FILE empty; FILE *p; + static struct __sFILEX emptyx = __sFXInit; + struct __sFILEX *fx; - g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE)); + g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE) + + n * sizeof(struct __sFILEX)); if (g == NULL) return (NULL); p = (FILE *)ALIGN(g + 1); + fx = (struct __sFILEX *)&p[n]; g->next = NULL; g->niobs = n; g->iobs = p; - while (--n >= 0) - *p++ = empty; + + while (--n >= 0) { + *p = empty; + p->_extra = fx; + *p->_extra = emptyx; + p++, fx++; + } return (g); } @@ -115,7 +158,7 @@ moreglue(n) * Find a free FILE for fopen et al. */ FILE * -__sfp() +__sfp(int count) { FILE *fp; int n; @@ -123,6 +166,15 @@ __sfp() if (!__sdidinit) __sinit(); + + if (count) { + if (__scounted >= __stream_max) { + THREAD_UNLOCK(); + errno = EMFILE; + return NULL; + } + OSAtomicIncrement32(&__scounted); + } /* * The list must be locked because a FILE may be updated. */ @@ -155,12 +207,25 @@ found: fp->_lb._base = NULL; /* no line buffer */ fp->_lb._size = 0; /* fp->_lock = NULL; */ /* once set always set (reused) */ - fp->_orientation = 0; - memset(&fp->_mbstate, 0, sizeof(mbstate_t)); + INITEXTRA(fp); + fp->_extra->counted = count ? 1 : 0; return (fp); } /* + * Mark as free and update count as needed + */ +__private_extern__ void +__sfprelease(FILE *fp) +{ + if (fp->_counted) { + OSAtomicDecrement32(&__scounted); + fp->_counted = 0; + } + fp->_flags = 0; +} + +/* * XXX. Force immediate allocation of internal memory. Not used by stdio, * but documented historically for certain applications. Bad applications. */ @@ -209,8 +274,25 @@ _cleanup() void __sinit() { + THREAD_LOCK(); + if (__sdidinit == 0) { +#if !TARGET_OS_EMBEDDED + int i; +#endif + /* Make sure we clean up on exit. */ + __cleanup = _cleanup; /* conservative */ + __stream_max = sysconf(_SC_STREAM_MAX); + __scounted = 3; /* std{in,out,err} already exists */ + +#if !TARGET_OS_EMBEDDED + /* Set _extra for the usual suspects. */ + for (i = 0; i < FOPEN_MAX - 3; i++) { + usual[i]._extra = &usual_extra[i]; + INITEXTRA(&usual[i]); + } +#endif - /* Make sure we clean up on exit. */ - __cleanup = _cleanup; /* conservative */ - __sdidinit = 1; + __sdidinit = 1; + } + THREAD_UNLOCK(); } |