1 | /*-␊ |
2 | * Copyright (c) 1990, 1993␊ |
3 | *␉The Regents of the University of California. All rights reserved.␊ |
4 | *␊ |
5 | * This code is derived from software contributed to Berkeley by␊ |
6 | * Chris Torek.␊ |
7 | *␊ |
8 | * Redistribution and use in source and binary forms, with or without␊ |
9 | * modification, are permitted provided that the following conditions␊ |
10 | * are met:␊ |
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.␊ |
19 | *␊ |
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␊ |
30 | * SUCH DAMAGE.␊ |
31 | */␊ |
32 | ␊ |
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 $");␊ |
38 | ␊ |
39 | #include <TargetConditionals.h>␊ |
40 | #include "libsaio.h"␊ |
41 | ␊ |
42 | #include <sys/param.h>␊ |
43 | #include "stdio.h"␊ |
44 | #include "errno.h"␊ |
45 | #include "glue.h"␊ |
46 | ␊ |
47 | ␊ |
48 | #include "local.h"␊ |
49 | ␊ |
50 | int␉__sdidinit;␊ |
51 | void␉(*__cleanup)(void);␊ |
52 | ␊ |
53 | #define _PTHREAD_MUTEX_SIG_init␉␉0x32AAABA7␊ |
54 | #define PTHREAD_MUTEX_INITIALIZER {_PTHREAD_MUTEX_SIG_init, {0}}␊ |
55 | ␊ |
56 | ␊ |
57 | ␊ |
58 | #if !TARGET_OS_EMBEDDED␊ |
59 | #define␉NDYNAMIC 10␉␉/* add ten more whenever necessary */␊ |
60 | #else␊ |
61 | #define␉NDYNAMIC 1␉␉/* add one at a time on embedded */␊ |
62 | #endif␊ |
63 | ␊ |
64 | #define␉std(flags, file) {␉␉\␊ |
65 | ␉._flags = (flags),␉␉\␊ |
66 | ␉._file = (file),␉␉\␊ |
67 | ␉._cookie = __sF + (file),␉\␊ |
68 | ␉._close = __sclose,␉␉\␊ |
69 | ␉._read = __sread,␉␉\␊ |
70 | ␉._seek = __sseek,␉␉\␊ |
71 | ␉._write = __swrite,␉␉\␊ |
72 | ␉._extra = __sFX + file, \␊ |
73 | }␊ |
74 | #define __sFXInit {.fl_mutex = PTHREAD_MUTEX_INITIALIZER}␊ |
75 | /* set counted */␊ |
76 | #define __sFXInit3 {.fl_mutex = PTHREAD_MUTEX_INITIALIZER, .counted = 1}␊ |
77 | ␊ |
78 | //static int __scounted;␉␉/* streams counted against STREAM_MAX */␊ |
79 | //static int __stream_max;␊ |
80 | ␊ |
81 | #if !TARGET_OS_EMBEDDED␊ |
82 | /* usual and usual_extra are data pigs. See 7929728. For embedded we should␊ |
83 | * always allocate dynamically, and probably should for desktop too. */␊ |
84 | ␉␉␉␉/* the usual - (stdin + stdout + stderr) */␊ |
85 | static FILE usual[FOPEN_MAX - 3];␊ |
86 | static struct __sFILEX usual_extra[FOPEN_MAX - 3];␊ |
87 | static struct glue uglue = { NULL, FOPEN_MAX - 3, usual };␊ |
88 | #endif /* !TARGET_OS_EMBEDDED */␊ |
89 | ␊ |
90 | static struct __sFILEX __sFX[3] = {__sFXInit3, __sFXInit3, __sFXInit3};␊ |
91 | ␊ |
92 | /*␊ |
93 | * We can't make this 'static' due to binary compatibility concerns.␊ |
94 | * This also means we cannot change the sizeof(FILE) and must continue to␊ |
95 | * use the __sFILEX stuff to add to FILE.␊ |
96 | */␊ |
97 | FILE __sF[3] = {␊ |
98 | ␉std(__SRD, STDIN_FILENO),␊ |
99 | ␉std(__SWR, STDOUT_FILENO),␊ |
100 | ␉std(__SWR|__SNBF, STDERR_FILENO)␊ |
101 | };␊ |
102 | ␊ |
103 | FILE *__stdinp = &__sF[0];␊ |
104 | FILE *__stdoutp = &__sF[1];␊ |
105 | FILE *__stderrp = &__sF[2];␊ |
106 | ␊ |
107 | #if !TARGET_OS_EMBEDDED␊ |
108 | struct glue __sglue = { &uglue, 3, __sF };␊ |
109 | static struct glue *lastglue = &uglue;␊ |
110 | #else␊ |
111 | struct glue __sglue = { NULL, 3, __sF };␊ |
112 | static struct glue *lastglue = &__sglue;␊ |
113 | #endif␊ |
114 | ␊ |
115 | static struct glue *␉moreglue(int);␊ |
116 | ␊ |
117 | ␊ |
118 | #if NOT_YET␊ |
119 | #define␉SET_GLUE_PTR(ptr, val)␉atomic_set_rel_ptr(&(ptr), (uintptr_t)(val))␊ |
120 | #else␊ |
121 | #define␉SET_GLUE_PTR(ptr, val)␉ptr = val␊ |
122 | #endif␊ |
123 | ␊ |
124 | static struct glue *␊ |
125 | moreglue(n)␊ |
126 | ␉int n;␊ |
127 | {␊ |
128 | ␉struct glue *g;␊ |
129 | ␉static FILE empty;␊ |
130 | ␉FILE *p;␊ |
131 | ␉static struct __sFILEX emptyx = __sFXInit;␊ |
132 | ␉struct __sFILEX *fx;␊ |
133 | ␊ |
134 | ␉g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE) +␊ |
135 | ␉ n * sizeof(struct __sFILEX));␊ |
136 | ␉if (g == NULL)␊ |
137 | ␉␉return (NULL);␊ |
138 | ␉p = (FILE *)ALIGN(g + 1);␊ |
139 | ␉fx = (struct __sFILEX *)&p[n];␊ |
140 | ␉g->next = NULL;␊ |
141 | ␉g->niobs = n;␊ |
142 | ␉g->iobs = p;␊ |
143 | ␊ |
144 | ␉while (--n >= 0) {␊ |
145 | ␉␉*p = empty;␊ |
146 | ␉␉p->_extra = fx;␊ |
147 | ␉␉*p->_extra = emptyx;␊ |
148 | ␉␉p++, fx++;␊ |
149 | ␉}␊ |
150 | ␉return (g);␊ |
151 | }␊ |
152 | ␊ |
153 | /*␊ |
154 | * Find a free FILE for fopen et al.␊ |
155 | */␊ |
156 | FILE *␊ |
157 | __sfp(int count)␊ |
158 | {␊ |
159 | ␉FILE␉*fp;␊ |
160 | ␉int␉n;␊ |
161 | ␉struct glue *g;␊ |
162 | ␊ |
163 | ␉if (!__sdidinit)␊ |
164 | ␉␉__sinit();␊ |
165 | ␊ |
166 | ␉/*if (count) {␊ |
167 | ␉␉if (__scounted >= __stream_max) {␊ |
168 | set_errno(EMFILE);␊ |
169 | ␉␉␉return NULL;␊ |
170 | ␉␉}␊ |
171 | ␉␉//OSAtomicIncrement32(&__scounted);␊ |
172 | __scounted++;␊ |
173 | ␉}*/␊ |
174 | ␉/*␊ |
175 | ␉ * The list must be locked because a FILE may be updated.␊ |
176 | ␉ */␊ |
177 | ␉for (g = &__sglue; g != NULL; g = g->next) {␊ |
178 | ␉␉for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)␊ |
179 | ␉␉␉if (fp->_flags == 0)␊ |
180 | ␉␉␉␉goto found;␊ |
181 | ␉}␊ |
182 | ␉if ((g = moreglue(NDYNAMIC)) == NULL)␊ |
183 | ␉␉return (NULL);␊ |
184 | ␉SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */␊ |
185 | ␉lastglue = g;␉␉/* not atomic; only accessed when locked */␊ |
186 | ␉fp = g->iobs;␊ |
187 | found:␊ |
188 | ␉fp->_flags = 1;␉␉/* reserve this slot; caller sets real flags */␊ |
189 | ␉fp->_p = NULL;␉␉/* no current pointer */␊ |
190 | ␉fp->_w = 0;␉␉/* nothing to read or write */␊ |
191 | ␉fp->_r = 0;␊ |
192 | ␉fp->_bf._base = NULL;␉/* no buffer */␊ |
193 | ␉fp->_bf._size = 0;␊ |
194 | ␉fp->_lbfsize = 0;␉/* not line buffered */␊ |
195 | ␉fp->_file = -1;␉␉/* no file */␊ |
196 | /*␉fp->_cookie = <any>; */␉/* caller sets cookie, _read/_write etc */␊ |
197 | ␉fp->_ub._base = NULL;␉/* no ungetc buffer */␊ |
198 | ␉fp->_ub._size = 0;␊ |
199 | ␉fp->_lb._base = NULL;␉/* no line buffer */␊ |
200 | ␉fp->_lb._size = 0;␊ |
201 | /*␉fp->_lock = NULL; */␉/* once set always set (reused) */␊ |
202 | ␉INITEXTRA(fp);␊ |
203 | ␉fp->_extra->counted = count ? 1 : 0;␊ |
204 | ␉return (fp);␊ |
205 | }␊ |
206 | ␊ |
207 | /*␊ |
208 | * Mark as free and update count as needed␊ |
209 | */␊ |
210 | __private_extern__ void␊ |
211 | __sfprelease(FILE *fp)␊ |
212 | {␊ |
213 | ␉if (fp->_counted) {␊ |
214 | ␉␉//OSAtomicDecrement32(&__scounted);␊ |
215 | //__scounted--;␊ |
216 | ␉␉fp->_counted = 0;␊ |
217 | ␉}␊ |
218 | ␉fp->_flags = 0;␊ |
219 | }␊ |
220 | ␊ |
221 | /*␊ |
222 | * exit() calls _cleanup() through *__cleanup, set whenever we␊ |
223 | * open or buffer a file. This chicanery is done so that programs␊ |
224 | * that do not use stdio need not link it all in.␊ |
225 | *␊ |
226 | * The name `_cleanup' is, alas, fairly well known outside stdio.␊ |
227 | */␊ |
228 | ␊ |
229 | void␊ |
230 | _cleanup()␊ |
231 | {␊ |
232 | ␉/* (void) _fwalk(fclose); */␊ |
233 | ␉ (void) _fwalk(__sflush);␉␉/* `cheating' */␊ |
234 | }␊ |
235 | ␊ |
236 | /*␊ |
237 | * __sinit() is called whenever stdio's internal variables must be set up.␊ |
238 | */␊ |
239 | void␊ |
240 | __sinit()␊ |
241 | {␊ |
242 | ␉if (__sdidinit == 0) {␊ |
243 | #if !TARGET_OS_EMBEDDED␊ |
244 | ␉␉int i;␊ |
245 | #endif␊ |
246 | ␉␉/* Make sure we clean up on exit. */␊ |
247 | ␉␉__cleanup = _cleanup;␉␉/* conservative */␊ |
248 | ␉␉//__stream_max = 9;␊ |
249 | ␉␉//__scounted = 3;␉␉␉/* std{in,out,err} already exists */␊ |
250 | ␊ |
251 | #if !TARGET_OS_EMBEDDED␊ |
252 | ␉␉/* Set _extra for the usual suspects. */␊ |
253 | ␉␉for (i = 0; i < FOPEN_MAX - 3; i++) {␊ |
254 | ␉␉␉usual[i]._extra = &usual_extra[i];␊ |
255 | ␉␉␉INITEXTRA(&usual[i]);␊ |
256 | ␉␉}␊ |
257 | #endif␊ |
258 | ␊ |
259 | ␉␉__sdidinit = 1;␊ |
260 | ␉}␊ |
261 | }␊ |
262 | |